OpenCV-Python教程:通道分离、通道合并(split、merge)

原文链接:http://www.juzicode.com/archives/5612

返回Opencv-Python教程

彩色图像是包含多通道的图像,比如用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数组的索引方式对图像进行分离和合并。

 

扩展阅读:

  1. OpenCV-Python教程

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注