1. 程式人生 > >Python 讀取顯示儲存圖片----python skimage影象處理

Python 讀取顯示儲存圖片----python skimage影象處理

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

 本文主要介紹了影象的讀取,顯示,儲存,色彩轉換,批量處理,縮放,對比度調,直方圖均衡化等操作。

1,skimage包的子模組

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

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

程式自帶圖片

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

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

 顯示這些圖片可用如下程式碼,圖片名對應的就是函式名。

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

2,影象基本操作

2.1 讀取

 影象的讀取可以使用imread函式,返回的是浮點型別影象陣列,程式碼如下

#常見的顯示模組
import matplotlib.pyplot as plt
#使用skimage的io子模組中的imread,所以需要匯入io模組
from skimage import io

# 圖片檔案的路徑
filename = 'XXXXX'
# 使用imread讀取影象
img = io.imread(filename)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2.2 顯示

 影象的顯示可以使用plt子模組中的imshow函式,程式碼如下:

#設定影象的大小
plt.figure(figsize = (10,10))
# 使用灰度方式顯示圖片
plt.imshow(image,'gray')
  • 1
  • 2
  • 3
  • 4

 也可以使用io子模組下的imshow函式,程式碼如下:

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

2.3 儲存

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

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

圖片資訊

 可以獲得影象中的型別,尺寸,高度,寬度,通道數,總畫素個數,最大畫素值,最小畫素值,畫素平均值等資訊,程式碼如下:

from skimage import io, data
img = data.chelsea()
io.imshow(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())    #畫素平均值
print(img[0][0])     #影象的畫素值
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2.4 影象色彩的轉換

 使用了color模組的rgb2gray()函式,將色彩三通道圖片轉換成灰度圖,轉換結果為float64型別的陣列,範圍為[0,1]之間,將彩色三通道圖片轉換成灰度圖,最後變成uint8,float64轉換成uint8是有資訊損失的。程式碼如下;

from skimage import io,color,img_as_ubyte,data

filename = 'XXXXX'
#讀取影象,結果為M*N*3的矩陣,彩色形式
img = io.imread(filename)
# 彩色形式轉成灰色形式,結果為M*N的矩陣,元素型別為float64,[0,1]
img_gray = color.rgb2grey(img)
# 將浮點型別轉換成uint8型,[0,155],轉換後有資訊損失。
img_uint = img_as_ubyte(img)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

影象資料型別:

 在skimage中,一張圖片就是一個簡單的numpy陣列,陣列的資料型別有很多中,相互之間也可以轉換。型別及取值範圍如下:

資料型別 範圍 資料型別 範圍 資料型別 範圍
uint8 0 to 255 uint16 0 to 65535 uint32 0 to 232
float -1 to 1 or 0 to 1 int8 -128 to 127 int16 -32768 to 32767
int32 -231 to 231 - 1

 灰色圖片預設的畫素範圍是[0,255],所以預設使用uint8,可以用如下程式碼檢視資料型別:

from skimage import data
img=data.chelsea()
print(img.dtype.name)
  • 1
  • 2
  • 3

 常見的資料型別轉換函式:

函式名稱 描述
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

 型別轉換還可以使用color模組下的convert_colorspace函式,程式碼如下:

from skimage import io,data,color
img=data.lena()
# 從RGB顏色空間轉到gray顏色空間
img_gray=color.convert_colorspace(img,'RGB','Gray')
io.imshow(img_gray)
  • 1
  • 2
  • 3
  • 4
  • 5

 另外,label2rgb()函式可以根據標籤紙對圖片進行著色。

2.5 影象的批量處理

 如果需要對一批圖片進行處理,可以呼叫程式自帶的圖片集合ImageCollection來處理。語法為:

skimage.io.ImageCollection(load_pattern,load_func=None)
  • 1

 這個函式是放在io模組內的,帶兩個引數,第一個引數是load_pattern,表示圖片組的路徑,可以是一個str字串,第二個引數load_func是一個回撥函式,預設是imread()函式,即預設這個函式是批量讀取圖片。程式碼是:

import skimage.io as io
from skimage import data_dir
str=data_dir + '/*.png'
coll = io.ImageCollection(str)
  • 1
  • 2
  • 3
  • 4

 如果在一個資料夾裡,既有jpg格式的圖片,又有png的圖片,想把它們都讀出來,可用下面的程式碼:

import skimage.io as io
from skimage import data_dir
# 圖片之間用冒號隔開
str='d:/pic1/*.jpg:d:/pic2/*.png'
coll = io.ImageCollection(str)
  • 1
  • 2
  • 3
  • 4
  • 5

 如果想對圖片進行批量操作,比如轉為灰度圖,可以用下面的程式碼:

from skimage import data_dir,io,color
def convert_gray(f): 
       rgb=io.imread(f) 
       return color.rgb2gray(rgb) 

str=data_dir+'/*.png'
coll = io.ImageCollection(str,load_func=convert_gray)
io.imshow(coll[10])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2.6 圖片的形變與縮放

 影象的形變與縮放,可以使用skimagetransform模組,函式比較多,功能齊全。

改變圖片尺寸

 改變圖片尺寸可以使用resize函式,語法為:skimage.transform.resize(image, output_shape)

其中,image是需要改變尺寸的圖片,output_shape是新的圖片的尺寸,程式碼如下:

from skimage import transform,data
img = data.camera()
dst=transform.resize(img, (80, 60))
  • 1
  • 2
  • 3

圖片縮放

 縮放圖片可以使用rescale函式,語法為:skimage.transform.rescale(image, scale[, ...])

scale引數可以是單個float函式,表示縮放的倍數,也可以是一個float型的tuple,例子如下:

from skimage import transform,data
img = data.camera()
print(img.shape) #圖片原始大小 
print(transform.rescale(img, 0.1).shape) #縮小為原來圖片大小的0.1
print(transform.rescale(img, [0.5,0.25]).shape) #縮小為原來圖片行數一半,列數四分之一
print(transform.rescale(img, 2).shape) #放大為原來圖片大小的2倍
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

 結果為:

(512, 512)
(51, 51)
(256, 128)
(1024, 1024)
  • 1
  • 2
  • 3
  • 4

影象旋轉

 影象旋轉可以使用roate函式,語法為:skimage.transform.rotate(image, angle[, ...],resize=False)

  • angle引數是個float型別數,表示旋轉的度數
  • resize用於控制在旋轉時,是否改變大小 ,預設為False

 程式碼如下:

from skimage import transform,data
img = data.camera()
img1=transform.rotate(img, 60) #旋轉90度,不改變大小 
img2=transform.rotate(img, 30,resize=True) #旋轉30度,同時改變大小
  • 1
  • 2
  • 3
  • 4

2.7 對比度與亮度調整

 影象亮度與對比度的調整,是放在skimage包裡的exposure模組裡面。

gamma調整

 原理:O=IγO=Iγ

 對原影象的畫素,進行冪運算,得到新的畫素值,公式中的g就是gamma值。如果gamma大於1,新影象比原影象暗,如果gamma<1,新影象比原影象亮。語法為:skimage.exposure.adjust_gamma(image, gamma=1)

gamma引數預設為1,原影象不發生變化。例子如下:

from skimage import data, exposure, img_as_float
image = img_as_float(data.moon())
gam1= exposure.adjust_gamma(image, 2) #調暗
gam2= exposure.adjust_gamma(image, 0.5) #調亮
  • 1
  • 2
  • 3
  • 4

log對數調整

 這個剛好和gamma相反,原理O=gain∗log(1+I)O=gain∗log(1+I),例子如下:

from skimage import data, exposure, img_as_float
image = img_as_float(data.moon())
gam1= exposure.adjust_log(image) #對數調整
  • 1
  • 2
  • 3

判斷影象對比度是否偏低

 函式:is_low_contrast(img),返回一個bool型值。

from skimage import data, exposure
image =data.moon()
result=exposure.is_low_contrast(image)
print(result)
  • 1
  • 2
  • 3
  • 4

 輸出為False

調整強度

 函式為rescale_intensity

 語法為skimage.exposure.rescale_intensity(image, in_range='image', out_range='dtype')

in_range表示輸入圖片的強度範圍,預設為’image’, 表示用影象的最大/最小畫素值作為範圍 out_range 表示輸出圖片的強度範圍,預設為’dype’, 表示用影象的型別的最大/最小值作為範圍  預設情況下,輸入圖片的[min,max]範圍被拉伸到[dtype.min, dtype.max],如果dtype=uint8, 那麼dtype.min=0, dtype.max=255

 例子為:

import numpy as np
from skimage import exposure
image = np.array([51, 102, 153], dtype=np.uint8)
mat=exposure.rescale_intensity(image)
print(mat)
  • 1
  • 2
  • 3
  • 4
  • 5

2.8 直方圖與均衡化

 在影象處理中,直方圖是非常重要的,也是非常有用的一個處理要素。在skimage庫中,對直方圖的處理,是放在exposure這個模組中。

計算直方圖

 語法為:skimage.exposure.histogram(image, nbins=256)

 在numpy包中,也提供了一個計算直方圖的函式histogram(),兩者大同小義。  返回一個tuple(hist, bins_center), 前一個數組是直方圖的統計量,後一個數組是每個bin的中間值

import numpy as np
from skimage import exposure,data
image =data.camera()*1.0
hist1=np.histogram(image, bins=2) #用numpy包計算直方圖hist2=exposure.histogram(image, nbins=2) #用skimage計算直方圖
print(hist1)
print(hist2)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

直方圖均衡化

 如果一副影象的畫素佔有很多的灰度級而且分佈均勻,那麼這樣的影象往往有高對比度和多變的灰度色調。直方圖均衡化就是一種能僅靠輸入影象直方圖資訊自動達到這種效果的變換函式。它的基本思想是對影象中畫素個數多的灰度級進行展寬,而對影象中畫素個數少的灰度進行壓縮,從而擴充套件取值的動態範圍,提高了對比度和灰度色調的變化,使影象更加清晰。例子如下:

from skimage import data,exposure
import matplotlib.pyplot as plt
img=data.moon()
plt.figure("hist",figsize=(8,8))
arr=img.flatten()
plt.subplot(221)
plt.imshow(img,plt.cm.gray) #原始影象
plt.subplot(222)
plt.hist(arr, bins=256, normed=1,edgecolor='None',facecolor='red') #原始影象直方圖
img1=exposure.equalize_hist(img) #進行直方圖均衡化
arr1=img1.flatten() #返回陣列摺疊成一維的副本
plt.subplot(223)
plt.imshow(img1,plt.cm.gray) #均衡化影象
plt.subplot(224)
plt.hist(arr1, bins=256, normed=1,edgecolor='None',facecolor='red') #均衡化直方圖
plt.show()