1. 程式人生 > >python影象處理之scikit-image基本用法

python影象處理之scikit-image基本用法

本文介紹Python語言用於數字影象處理,那麼要使用python進行各種開發和科學計算,需要對應相對的python包,

python有很多的數字影象處理相關的包,像

  • PIL
  • Pillow
  • OpenCV
  • scikit-image
  • 等等

其中PIL和Pillow只提供最基礎的數字影象處理,功能有限;

opencv實際上是一個c++庫,只是提供了python介面,

scikit-image是基於scipy的一款影象處理包,它將圖片作為numpy陣列進行處理,正好與matlab一樣,因此,我們最終選擇scikit-image進行數字影象處理。

python庫安裝

可以通過pip進行安裝

sudo pip install xxxx

scikit-image是基於numpy,因此需要安裝numpy和scipy,同時需要安裝matplotlib進行圖片的實現等。

因此,需要安裝如下的包:

numpy (1.13.3)
matplotlib (2.1.0)
scikit-image (0.13.1)
scipy (1.0.0)

也可以直接下載整合開發環境Anaconda,該環境已經集成了數字影象處理相關的包,因此安裝起來比較方便。

可以通過如下程式簡單測試下相關庫是否安裝成功

import numpy as np
import scipy as sp
import
matplotlib.pyplot as plt from skimage import io img = io.imread("./cat.png") print(img.shape) plt.imshow(img) plt.show()

若顯示正常,則可以認為相關的庫安裝成功

skimage庫子模組介紹

skimage庫的全稱scikit-image Scikit, 是對scipy.ndimage進行了擴充套件,提供了更多的圖片處理功能。skimage包含很多的子模組,各個子模組具有不同的功能,如下

子模組名稱 實現功能
io 讀取,儲存和顯示圖片和視訊
color 顏色空間變換
data 提供一些測試圖片和樣本資料
filters 影象增強,邊緣檢測,排序濾波器,自動閾值等
draw 操作於numpy陣列上的基本圖形繪製,包括線條,矩陣,圓和文字等
transform 幾何變換和其他變換,如旋轉,拉伸和Radon(拉東)變換等
exposure 影象強度調整,例如,直方圖均衡化等
feature 特徵檢測和提取, 例如,紋理分析等
graph 圖論操作,例如,最短路徑
measure 影象屬性測量,例如,相似度和輪廓
morphology 形態學操作,如開閉運算,骨架提取等
novice 簡化的用於教學目的的介面
restoration 修復演算法,例如去卷積演算法,去噪等
segmentation 影象分割為多個區域
util 通用工具
viewer 簡單圖形使用者介面用於視覺化結果和探索引數

當要使用對應的模組中功能函式時,需要通過import匯入對應的子模組即可, 若要匯入多個子模組時,子模組之間用逗號隔開,如下:

from skimage import io, data, feature

skimage操作

影象讀取, 儲存與顯示

skimage中io子模組提供了相關的功能,同時也提供了一些data模組,其中包含一些示例圖片用於練習

匯入io子模組的python語句如下:

from skimage import io

從外部讀取圖片並顯示

使用 skimage.io.imread(fname) 讀取fname指定的圖片,

skimage.io.imshow(arr), 表示顯示arr陣列表示的圖片

from skimage import io
img = io.imread('./cat.png')
io.imshow(img)
io.show()

cat.png

讀取單張灰度圖片時,使用 skimage.io.imread(fname, as_grey=True) 函式,第一個引數fname表示要顯示的圖片路徑,第二個引數as_grey,是bool型別,預設值False。

from skimage import io
img = io.imread('./cat.png', as_grey=True)
io.imshow(img)
io.show()

grey_cat.png

skimage自帶圖片

圖片名稱 說明
astronaut 宇航員
binary_blobs 二元斑點
camera 相機
checkerboard 棋盤
chelsea
clock 時鐘
coffee 一杯咖啡
coins 硬幣
horse
hubble_deep_field 星空
immunohistochemistry 結腸圖片
logo 商標
moon 月球表面
page 書頁內容
rocket 火箭
text 文字圖片

例如

from skimage import io, data
img = data.hubble_deep_field()
io.imshow(img)
io.show()

moon.png

圖片名就是對應的函式名,如camera圖片對應的函式名為 data.camera()

注:這些圖片儲存在skimage的安裝目錄下,可以通過data_dir把路徑打印出來。

from skimage import data_dir
print (data_dir)

輸出為:

/usr/local/lib/python3.6/dist-packages/skimage/data

儲存圖片

使用 io.imsave(fname, arr) 函式進行儲存,

  • 引數fname: 表示儲存的路徑和名稱
  • 引數arr:表示需要儲存的陣列變數
from skimage import io, data

img = data.checkerboard()
io.imshow(img)
io.imsave('checkerboard_copy.jpg', img)

這樣,在當前的工作目錄下就增加了一個checkerboard_copy.jpg檔案。

注:儲存圖片同時也起到了轉換格式的作用,若讀取的是png格式圖片,當儲存為jpg時,則圖片從png格式轉換為jpg格式圖片。

獲取圖片資訊

from skimage import io, data

img = data.chelsea()
io.imshow(img)
io.show()

print(type(img))    # 型別
print(img.shape)    # 形狀
print(img.shape[0]) # 圖片寬度
print(img.shape[1]) # 圖片高度
print(img.shape[2]) # 圖片通道數
print(img.size)     # 顯示總畫素個數
print(img.max())    # 最大畫素值
print(img.min())    # 最小畫素值
print(img.mean())   # 畫素平均值

輸出如下

get_cat_information.png

影象畫素訪問與裁剪

圖片讀入程式後,以numpy陣列方式儲存,因此對numpy陣列的操作,都可以用於圖片陣列,對陣列元素的訪問,實際上就是對圖片畫素點的訪問。

畫素讀取

彩色圖片 的畫素點訪問方式如下

img[i, j, c]

其中:

  • i 表示圖片的行數
  • j 表示圖片的列數
  • c 表示圖片的通道數(RGB三通道分別對應0, 1, 2)。

座標從左上角開始

灰度圖片 的畫素點訪問方式如下

gray[i, j]

例如, 對data中宇航員圖片的B通道中的第20行10列的畫素值

from skimage import io, data

img = data.astronaut()
pixel = img[20, 10, 2]
print(pixel)

輸出

69

例如,顯示紅色單通道圖片的程式如下

from skimage import io, data

img = data.astronaut()
R = img[:, :, 0]
io.imshow(R)
io.show()

輸出為:

astronaut_red_channel.png

畫素修改

例如,對宇航員圖片隨機新增椒鹽噪聲

from skimage import io, data
import numpy as np

img = data.astronaut()

# 隨機生成5000個椒鹽點
rows, cols, dims = img.shape

for i in range(5000):
    x = np.random.randint(0, rows)
    y = np.random.randint(0, cols)
    img[x, y, :] = 255

io.imshow(img)
io.show()

輸出如下:

astronaut_added_noise.png

此處,使用numpy中的random來產生隨機數, randint(0, cols)表示隨機生成一個整數, 範圍在0到cols之間。

圖片裁剪

由於圖片是以numpy陣列進行儲存,因此對於陣列的裁剪,就是對圖片的裁剪

例如,對宇航員圖片進行裁剪

from skimage import io, data

img = data.astronaut()
partial_img = img[50:150, 170:270, :]
io.imshow(partial_img)
io.show()

輸出結果為:

astronaut_partial_img.png

對多個畫素點進行操作時, 使用陣列切片方式進行訪問, 切片方式訪問的是指定間隔內下標對應的畫素點。以下是一些例子

img[i,:] = im[j,:]      # 將第 j 行的數值賦值給第 i 行

img[:,i] = 100          # 將第 i 列的所有數值設為 100

img[:100,:50].sum()     # 計算前 100 行、前 50 列所有數值的和

img[50:100,50:100]      # 50~100 行,50~100 列(不包括第 100 行和第 100 列)

img[i].mean()           # 第 i 行所有數值的平均值

img[:,-1]               # 最後一列

img[-2,:] (or im[-2])   # 倒數第二行

以下是兩個對圖片的畫素值進行訪問和修改的例子

例1: 將宇航員圖片進行二值化,畫素值大於128的變為1, 否在變為0

from skimage import io, data, color

img = data.astronaut()

img_gray = color.rgb2gray(img)
rows, cols = img_gray.shape

for i in range(rows):
    for j in range(cols):
        if (img_gray[i, j] <= 0.5):
            img_gray[i, j] = 0
        else:
            img_gray[i, j] = 1
io.imshow(img_gray)
io.show()

astronaut_binary_gray.png

例2: 使用color模組的rgb2gray()函式,將彩色三通道圖片轉換為灰度圖片,轉換結果為float64型別的陣列,範圍在[0,1]之間

from skimage import io, data

img = data.astronaut()

img_idx_modified = img[:, :, 0] > 170
print(img_idx_modified)
img[img_idx_modified] = [0, 255, 0]

io.imshow(img)
io.show()

輸出為

astronaut_green.png

這個例子先對R通道的所有畫素值進行判斷,如果大於170,則將這個地方的畫素值變為[0,255,0], 即G通道值為255,R和B通道值為0。

影象資料型別以及顏色空間轉換

影象資料型別

在skimage中,一張圖片以numpy陣列形式儲存,陣列的資料型別有很多中,相互之間可以轉換,資料型別以及取值範圍如下表所示

資料型別 數值範圍
uint8 0 to 255
uint16 0 to 65535
uint32 0 to 232−1232−1
float16 半精度浮點數:16位,正負號1位,指數5位,精度10位
float32 單精度浮點數:32位,正負號1位,指數8位,精度23位
float64 雙精度浮點數:64位,正負號1位,指數11位,精度52位
float -1 to 1 or 0 to 1
int8 -128 to 127
int16 -32768 to 32767
int32 −231−231 to 232−1232−1

一張圖片的畫素值範圍是[0,255], 因此預設型別是unit8, 可用如下程式碼檢視資料型別:

from skimage import io, data

img = data.astronaut()

print(img.dtype.name)

輸出

uint8

在上面的表中,特別注意的是float型別,它的範圍是[-1,1]或[0,1]之間。一張彩色圖片轉換為灰度圖後,它的型別就由unit8變成了float

uint8轉為float

from skimage import data, img_as_float

img = data.astronaut()
print(img.dtype.name)

dst = img_as_float(img)
print(dst.dtype.name)
dst

輸出為

uint8
float64

float轉為uint8

from skimage import img_as_ubyte
import numpy as np

img = np.array([0, 0.5, 1], dtype=float)
print(img.dtype.name)

dst = img_as_ubyte(img)
print(dst.dtype.name)

輸出為:

float64
uint8

float轉為uint8,可能會造成資料損失,因此會有警告

除了如上兩種轉換以外,還有其他的一些型別轉換,如下表:

函式名 描述
img_as_float Convert to 64-bit floating point
img_as_ubyte Convert to 8-bit uint
img_as_uint Convert to 16-bit uint
img_as_int Convert to 16-bit int

顏色空間及轉換

除了直接轉換可以改變資料型別外,還可以通過影象的顏色空間轉換來改變資料型別。

常用的顏色空間有灰度空間、rgb空間、hsv空間和cmyk空間。顏色空間轉換以後,圖片型別都變成了float型。

所有的顏色空間轉換函式,都放在skimage的color模組內

例1: RGB轉為灰度圖

from skimage import io,data,color
img=data.camera()
gray=color.rgb2gray(img)
io.imshow(gray)
io.show()

camera-gray.png

其它的轉換,用法都是一樣的,列舉常用的如下:

skimage.color.rgb2grey(rgb)

skimage.color.rgb2hsv(rgb)

skimage.color.rgb2lab(rgb)

skimage.color.gray2rgb(image)

skimage.color.hsv2rgb(hsv)

skimage.color.lab2rgb(lab)

實際上,上面的所有轉換函式,都可以用一個函式來代替

skimage.color.convert_colorspace(arr, fromspace, tospace)

表示將arr從fromspace顏色空間轉換到tospace顏色空間。

例1: RGB轉為HSV

from skimage import io, data, color

img = data.coffee()
hsv = color.convert_colorspace(img, 'RGB', 'HSV')
io.imshow(hsv)
io.show()

輸出為

coffee-HSV.png

在color模組的顏色空間轉換函式中,還有一個比較有用的函式是

skimage.color.label2rgb(arr), 可以根據標籤值對圖片進行著色。以後的圖片分類後著色就可以用這個函式。

例:將coffee圖片分成三類,然後用預設顏色對三類進行著色

from skimage import io,data,color
import numpy as np

img=data.coffee()
gray=color.rgb2gray(img)
rows,cols=gray.shape

labels=np.zeros([rows,cols])
for i in range(rows):
    for j in range(cols):
        if(gray[i,j]<0.4):
            labels[i,j]=0
        elif(gray[i,j]<0.75):
            labels[i,j]=1
        else:
            labels[i,j]=2
dst=color.label2rgb(labels)

io.imshow(dst)
io.show()

coffee-label2grb-demo.png

參考