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()
讀取單張灰度圖片時,使用 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()
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()
圖片名就是對應的函式名,如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()) # 畫素平均值
輸出如下
影象畫素訪問與裁剪
圖片讀入程式後,以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()
輸出為:
畫素修改
例如,對宇航員圖片隨機新增椒鹽噪聲
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()
輸出如下:
此處,使用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()
輸出結果為:
對多個畫素點進行操作時, 使用陣列切片方式進行訪問, 切片方式訪問的是指定間隔內下標對應的畫素點。以下是一些例子
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()
例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()
輸出為
這個例子先對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()
其它的轉換,用法都是一樣的,列舉常用的如下:
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()
輸出為
在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()