1. 程式人生 > >python skimage影象處理(一)

python skimage影象處理(一)

本文轉自 python數字影象處理

基於python指令碼語言開發的數字圖片處理包,比如PIL,Pillow, opencv, scikit-image等。
PIL和Pillow只提供最基礎的數字影象處理,功能有限;opencv實際上是一個c++庫,只是提供了python介面,更新速度非常慢。scikit-image是基於scipy的一款影象處理包,它將圖片作為numpy陣列進行處理,正好與matlab一樣,因此,我們最終選擇scikit-image進行數字影象處理。


Image讀出來的是PIL的型別,而skimage.io讀出來的資料是numpy格式的


   
  1. import
    Image as img
  2. import os
  3. from matplotlib import pyplot as plot
  4. from skimage import io,transform
  5. #Image和skimage讀圖片
  6. img_file1 = img.open('./CXR_png/MCUCXR_0042_0.png')
  7. img_file2 = io.imread('./CXR_png/MCUCXR_0042_0.png')

輸出可以看出Img讀圖片的大小是圖片的(width, height);而skimage的是(height,width, channel)

, [這也是為什麼caffe在單獨測試時要要在程式碼中設定:transformer.set_transpose('data',(2,0,1)),因為caffe可以處理的圖片的資料格式是(channel,height,width),所以要轉換資料]


   
  1. #讀圖片後資料的大小:
  2. print "the picture's size: ", img_file1.size
  3. print "the picture's shape: ", img_file2.shape

   
  1. the picture 's size: (4892, 4020)
  2. the picture's shape: (4020, 4892)

   
  1. #得到畫素:
  2. print(img_file1.getpixel((500,1000)), img_file2[500][1000])
  3. print(img_file1.getpixel((500,1000)), img_file2[1000][500])
  4. print(img_file1.getpixel((1000,500)), img_file2[500][1000])

   
  1. (0, 139)
  2. (0, 0)
  3. (139, 139)

Img讀出來的圖片獲得某點畫素用getpixel((w,h))可以直接返回這個點三個通道的畫素值
skimage讀出來的圖片可以直接img_file2[0][0]獲得,但是一定記住它的格式,並不是你想的(channel,height,width)

圖片資訊

如果我們想知道一些skimage圖片資訊


   
  1. from skimage import io, data
  2. img = data.chelsea()
  3. io.imshow(img)
  4. print(type(img)) #顯示型別
  5. print(img.shape) #顯示尺寸
  6. print(img.shape[0]) #圖片高度
  7. print(img.shape[1]) #圖片寬度
  8. print(img.shape[2]) #圖片通道數
  9. print(img.size) #顯示總畫素個數
  10. print(img.max()) #最大畫素值
  11. print(img.min()) #最小畫素值
  12. print(img.mean()) #畫素平均值
  13. print(img[0][0])#影象的畫素值

PIL image 檢視圖片資訊,可用如下的方法


   
  1. print type(img)
  2. print img.size #圖片的尺寸
  3. print img.mode #圖片的模式
  4. print img.format #圖片的格式
  5. print(img.getpixel((0,0))) #得到畫素:
  6. #img讀出來的圖片獲得某點畫素用getpixel((w,h))可以直接返回這個點三個通道的畫素值

   
  1. # 獲取影象的灰度值範圍
  2. width = img.size[0]
  3. height = img.size[1]
  4. # 輸出圖片的畫素值
  5. count = 0
  6. for i in range(0, width):
  7. for j in range(0, height):
  8. if img.getpixel((i, j))>=0 and img.getpixel((i, j))<=255:
  9. count +=1
  10. print count
  11. print(height*width)

skimage提供了io模組,顧名思義,這個模組是用來圖片輸入輸出操作的。為了方便練習,也提供一個data模組,裡面嵌套了一些示例圖片,我們可以直接使用。

skimage包的子模組

skimage包的全稱是scikit-image SciKit (toolkit for SciPy) ,它對scipy.ndimage進行了擴充套件,提供了更多的圖片處理功能。它是由python語言編寫的,由scipy 社群開發和維護。skimage包由許多的子模組組成,各個子模組提供不同的功能。主要子模組列表如下:


   
  1. 子模組名稱  主要實現功能
  2. io 讀取、儲存和顯示圖片或視訊
  3. data 提供一些測試圖片和樣本資料
  4. color 顏色空間變換
  5. filters 影象增強、邊緣檢測、排序濾波器、自動閾值等
  6. draw 操作於numpy陣列上的基本圖形繪製,包括線條、矩形、圓和文字等
  7. transform 幾何變換或其它變換,如旋轉、拉伸和拉東變換等
  8. morphology 形態學操作,如開閉運算、骨架提取等
  9. exposure 圖片強度調整,如亮度調整、直方圖均衡等
  10. feature 特徵檢測與提取等
  11. measure 影象屬性的測量,如相似性或等高線等
  12. segmentation 影象分割
  13. restoration 影象恢復
  14. util 通用函式

從外部讀取圖片並顯示

讀取單張彩色rgb圖片,使用skimage.io.imread(fname)函式,帶一個引數,表示需要讀取的檔案路徑。顯示圖片使用skimage.io.imshow(arr)函式,帶一個引數,表示需要顯示的arr陣列(讀取的圖片以numpy陣列形式計算)。


   
  1. from skimage import io
  2. img=io.imread('d:/dog.jpg')
  3. io.imshow(img)

讀取單張灰度圖片,使用skimage.io.imread(fname,as_grey=True)函式,第一個引數為圖片路徑,第二個引數為as_grey, bool型值,預設為False


   
  1. from skimage import io
  2. img=io.imread('d:/dog.jpg',as_grey=True)
  3. io.imshow(img)

程式自帶圖片
skimage程式自帶了一些示例圖片,如果我們不想從外部讀取圖片,就可以直接使用這些示例圖片:


   
  1. astronaut 航員圖片 coffee 一杯咖啡圖片
  2. lena lena美女圖片 camera 拿相機的人圖片
  3. coins 硬幣圖片 moon 月亮圖片
  4. checkerboard 棋盤圖片 horse 馬圖片
  5. page 書頁圖片 chelsea 小貓圖片
  6. hubble_deep_field 星空圖片 text 文字圖片
  7. clock 時鐘圖片 immunohistochemistry 結腸圖片

顯示這些圖片可用如下程式碼,不帶任何引數


   
  1. from skimage import io, data
  2. img=data.lena()
  3. io.imshow(img)

圖片名對應的就是函式名,如camera圖片對應的函式名為camera(). 這些示例圖片存放在skimage的安裝目錄下面,路徑名稱為data_dir,我們可以將這個路徑打印出來看看


   
  1. from skimage import data_dir
  2. print(data_dir)

儲存圖片
使用io模組的imsave(fname,arr)函式來實現。第一個引數表示儲存的路徑和名稱,第二個引數表示需要儲存的陣列變數。


   
  1. from skimage import io,data
  2. img=data.chelsea()
  3. io.imshow(img)
  4. io.imsave('d:/cat.jpg',img)

儲存圖片的同時也起到了轉換格式的作用。如果讀取時圖片格式為jpg圖片,儲存為png格式,則將圖片從jpg圖片轉換為png圖片並儲存。

圖片資訊

如果我們想知道一些圖片資訊


   
  1. from skimage import io, data
  2. img = data.chelsea()
  3. io.imshow(img)
  4. print(type(img)) #顯示型別
  5. print(img.shape) #顯示尺寸
  6. print(img.shape[0]) #圖片高度
  7. print(img.shape[1]) #圖片寬度
  8. print(img.shape[2]) #圖片通道數
  9. print(img.size) #顯示總畫素個數
  10. print(img.max()) #最大畫素值
  11. print(img.min()) #最小畫素值
  12. print(img.mean()) #畫素平均值
  13. print(img[0][0])#影象的畫素值

影象畫素的訪問與裁剪

圖片讀入程式中後,是以numpy陣列存在的。因此對numpy陣列的一切功能,對圖片也適用。對陣列元素的訪問,實際上就是對圖片畫素點的訪問。

彩色圖片訪問方式為:img[i,j,c]
i表示圖片的行數,j表示圖片的列數,c表示圖片的通道數(RGB三通道分別對應0,1,2)。座標是從左上角開始。

灰度圖片訪問方式為:gray[i,j]

例1:輸出小貓圖片的G通道中的第20行30列的畫素值


   
  1. from skimage import io,data
  2. img=data.chelsea()
  3. pixel=img[20,30,1]
  4. print(pixel)

例2:顯示紅色單通道圖片


   
  1. from skimage import io,data
  2. img=data.chelsea()
  3. R=img[:,:,0]
  4. io.imshow(R)

除了對畫素進行讀取,也可以修改畫素值。

例3:對小貓圖片隨機新增椒鹽噪聲


   
  1. from skimage import io,data
  2. import numpy as np
  3. img=data.chelsea()
  4. #隨機生成5000個椒鹽
  5. rows,cols,dims=img.shape
  6. for i in range(5000):
  7. x=np.random.randint(0,rows)
  8. y=np.random.randint(0,cols)
  9. img[x,y,:]=255
  10. io.imshow(img)

這裡用到了numpy包裡的random來生成隨機數,randint(0,cols)表示隨機生成一個整數,範圍在0到cols之間。
用img[x,y,:]=255這句來對畫素值進行修改,將原來的三通道畫素值,變為255

通過對陣列的裁剪,就可以實現對圖片的裁剪。
例4:對小貓圖片進行裁剪


   
  1. from skimage import io,data
  2. img=data.chelsea()
  3. roi=img[80:180,100:200,:]
  4. io.imshow(roi)

對多個畫素點進行操作,使用陣列切片方式訪問。切片方式返回的是以指定間隔下標訪問 該陣列的畫素值。下面是有關灰度影象的一些例子:


   
  1. img[i,:] = im[j,:] # 將第 j 行的數值賦值給第 i 行
  2. img[:,i] = 100 # 將第 i 列的所有數值設為 100
  3. img[:100,:50].sum() # 計算前 100 行、前 50 列所有數值的和
  4. img[50:100,50:100] # 50~100 行,50~100 列(不包括第 100 行和第 100 列)
  5. img[i].mean() # 第 i 行所有數值的平均值
  6. img[:,-1] # 最後一列
  7. img[-2,:] (or im[-2]) # 倒數第二行

最後我們再看兩個對畫素值進行訪問和改變的例子:

例5:將lena圖片進行二值化,畫素值大於128的變為1,否則變為0


   
  1. from skimage import io,data,color
  2. img=data.lena()
  3. img_gray=color.rgb2gray(img)
  4. rows,cols=img_gray.shape
  5. for i in range(rows):
  6. for j in range(cols):
  7. if (img_gray[i,j]<=0.5):
  8. img_gray[i,j]=0
  9. else:
  10. img_gray[i,j]=1
  11. io.imshow(img_gray)

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

將彩色三通道圖片轉換成灰度圖,最後變成unit8, float轉換為unit8是有資訊損失的。


   
  1. img_path = 'data/dpclassifier/newtrain/test/1_0.png'
  2. import Image as img
  3. import os
  4. from matplotlib import pyplot as plot
  5. from skimage import io,transform, img_as_ubyte
  6. img_file1 = img.open(img_path)
  7. img_file1.show()
  8. img_file2 = io.imread(img_path)
  9. io.imshow(img_file2)
  10. print(type(img_file1),img_file1.mode, type(img_file2),img_file2.shape, img_file2.dtype,img_file2.max(),img_file2.min(),img_file2.mean())
  11. img_file22=skimage.color.rgb2gray(img_file2)
  12. print(type(img_file22),img_file22.shape,img_file22.dtype,img_file22.max(),img_file22.min(),img_file22.mean() )
  13. dst=img_as_ubyte(img_file22)
  14. print(type(dst),dst.shape,dst.dtype, dst.max(), dst.min(), dst.mean())

結果


   
  1. (<class 'PIL.PngImagePlugin.PngImageFile'>, 'RGB', < type<