原文鏈接:http://www.juzicode.com/archives/5612
彩色圖像是包含多通道的圖像,比如用BGR三通道表示的彩色圖像,或者是包含了alpha通道的BGRA四通道圖像。有時做圖像處理時如果多通道同時處理,可能並不能達到很好的效果,但是如果分離出某一個通道出來處理可能會有更好的效果,一個例子是在 來看看怎么用OpenCV解構Twitter大牛jagarikin的視覺錯覺圖 一文中可以看到在做二值化時只處理HSV色彩空間中的S分量效果更好。
1、通道分離split()
通道分離可以用於彩色圖像的處理,圖像對象可以是普通的3通道BGR彩色圖像,分離后分別為b、g、r的3個通道。如果是帶alpha通道的BGRA 4通道圖像,分離后分別為b、g、r、a。如果圖像是其他色彩空間的圖像比如HSV圖像,分離后的3個圖像則分別為h、s、v。
下面的例子將lena.jpg和opencv-logo.png做通道分離,並將各分量顯示出來,在代碼中加入了通道數的判斷,如果是3通道返回結果用b,g,r= cv2.split(img)接收分離結果,如果是4通道用b,g,r,a = cv2.split(img)接收分離結果:
import cv2
print('VX公眾號: 桔子code / juzicode.com')
print('cv2.__version__:',cv2.__version__)
def show_img(win_name,img,wait_time=0,img_ratio=0.5,is_show=True):
if is_show is not True:
return
rows = img.shape[0]
cols = img.shape[1]
cv2.namedWindow(win_name, cv2.WINDOW_NORMAL )#cv2.WINDOW_AUTOSIZE)
cv2.resizeWindow(win_name,(int(cols*img_ratio),int(rows*img_ratio)))
cv2.imshow(win_name,img)
if wait_time >= 0:
cv2.waitKey(wait_time)
img = cv2.imread('..\\lena.jpg')
#img = cv2.imread('..\\opencv-logo.png',cv2.IMREAD_UNCHANGED)
if img is not None and len(img.shape)==3: #彩色圖像才可以做通道分離
print('img.shape:',img.shape)
show_img('img',img,-1)
if img.shape[2] == 3: #如果是3通道,分離出3個圖像實例
b,g,r = cv2.split(img)
show_img('b',b,-1)
show_img('g',g,-1)
show_img('r',r,-1)
cv2.waitKey(0)
elif img.shape[2] == 4: #如果是4通道
b,g,r,a = cv2.split(img)
show_img('b',b,-1)
show_img('g',g,-1)
show_img('r',r,-1)
show_img('a',a,-1)
cv2.waitKey(0)
lena.jpg運行結果:
opencv-logo.png運行結果:
2、索引方式通道分離
另外一種方法是利用numpy數組的切片或索引操作,比如用img[:,:,0]分離出0通道或b通道,img[:,:,1]對應g通道,img[:,:,2]對應r通道,如果有img[:,:,3]則對應alpha通道。
if img.shape[2] == 3: #如果是3通道,分離出3個圖像實例
b = img[:,:,0]
g = img[:,:,1]
r = img[:,:,2]
show_img('b',b,-1)
show_img('g',g,-1)
show_img('r',r,-1)
cv2.waitKey(0)
elif img.shape[2] == 4: #如果是4通道
b = img[:,:,0]
g = img[:,:,1]
r = img[:,:,2]
a = img[:,:,3]
show_img('b',b,-1)
show_img('g',g,-1)
show_img('r',r,-1)
show_img('a',a,-1)
cv2.waitKey(0)
3、通道合並merge()
用已有的多個通道圖像構造成一個元組傳遞給merge(),可以實現圖像的合並。
下面這個例子先分離出bgr通道再合並后顯示合成圖像:
import cv2
print('VX公眾號: 桔子code / juzicode.com')
print('cv2.__version__:',cv2.__version__)
img = cv2.imread('..\\lena.jpg')
b = img[:,:,0]
g = img[:,:,1]
r = img[:,:,2]
img2 = cv2.merge((b,g,r)) #傳入bgr構成的元組
cv2.imshow('merged',img2)
cv2.waitKey(0)
運行結果:
下面這個例子特意將bgr通道順序做調換再合並:
img = cv2.imread('..\\lena.jpg')
b = img[:,:,0]
g = img[:,:,1]
r = img[:,:,2]
img2 = cv2.merge((b,g,r)) #傳入bgr構成的元組
cv2.imshow('merged',img2)
img2 = cv2.merge((r,g,b))
cv2.imshow('merged-rgb',img2)
img2 = cv2.merge((r,b,g))
cv2.imshow('merged-rbg',img2)
img2 = cv2.merge((g,b,r))
cv2.imshow('merged-gbr',img2)
cv2.waitKey(0)
合並后圖像的效果和原圖對比:
4、索引方式通道合並
和用索引方式進行通道分離一樣,也可以用索引方式完成通道合並:
import numpy as np
import cv2
print('VX公眾號: 桔子code / juzicode.com')
print('cv2.__version__:',cv2.__version__)
img = cv2.imread('..\\lena.jpg')
b,g,r = cv2.split(img)
rows,cols,channels = img.shape[0],img.shape[1],img.shape[2]
img2 = np.zeros((rows,cols,channels),np.uint8) #創建全0的numpy數組
img2[:,:,0]=b #填充各個通道
img2[:,:,1]=g
img2[:,:,2]=r
cv2.imshow('merged',img2)
cv2.waitKey()
5、“分離”灰度圖
在前面介紹的圖像分離中都是針對彩色圖像做多通道的分離,如果被分離的圖像是單通道的灰度圖,會是什么結果呢?
下面這個例子讀入lena.jpg時轉換為灰度圖,再使用split()進行分離:
import cv2
print('VX公眾號: 桔子code / juzicode.com')
print('cv2.__version__:',cv2.__version__)
img = cv2.imread('..\\lena.jpg',cv2.IMREAD_GRAYSCALE)
print('img.shape:',img.shape)
res = cv2.split(img)
print(type(res))
print(res)
運行結果:
cv2.__version__: 4.5.2
img.shape: (512, 512)
<class 'list'>
[array([[163, 162, 161, ..., 170, 154, 130],
[162, 162, 162, ..., 173, 155, 126],
[162, 162, 163, ..., 170, 155, 128],
...,
[ 43, 42, 51, ..., 103, 101, 99],
[ 41, 42, 55, ..., 103, 105, 106],
[ 42, 44, 57, ..., 102, 106, 109]], dtype=uint8)]
從運行結果看,單通道的灰度圖用split()分離后,實際得到的是一個包含了array類型的list,效果和對一個numpy數組做split操作是類似的。
下面這個例子展示的是對一個numpy數組做split操作,不過numpy的split()方法還需要傳入第2個位置參數,表示要切割成多少個array。
import numpy as np
a = np.arange(0,50,1,np.uint8).reshape(5,10)
print(type(a))
print(a)
x = np.split(a,1) #切割成1個array
print(type(x))
print(x)
x = np.split(a,5) #切割成5個array
print(type(x))
print(x)
運行結果:
<class 'numpy.ndarray'>
[[ 0 1 2 3 4 5 6 7 8 9]
[10 11 12 13 14 15 16 17 18 19]
[20 21 22 23 24 25 26 27 28 29]
[30 31 32 33 34 35 36 37 38 39]
[40 41 42 43 44 45 46 47 48 49]]
<class 'list'>
[array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49]], dtype=uint8)]
<class 'list'>
[array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]], dtype=uint8), array([[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]], dtype=uint8), array([[20, 21, 22, 23, 24, 25, 26, 27, 28, 29]], dtype=uint8), array([[30, 31, 32, 33, 34, 35, 36, 37, 38, 39]], dtype=uint8), array([[40, 41, 42, 43, 44, 45, 46, 47, 48, 49]], dtype=uint8)]
小結:split()可以用來對彩色圖像進行通道分離,merge()方法可以用來合並圖像,注意傳入給merge()的入參為多通道圖像組成的一個元組;因為圖像表示為numpy數組,所以也可以用numpy數組的索引方式對圖像進行分離和合並。