原文链接:http://www.juzicode.com/opencv-python-split-merge
彩色图像是包含多通道的图像,比如用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数组的索引方式对图像进行分离和合并。