OpenCV轻松入门:面向Python【1.3】
摘要:本文介绍了OpenCV中RGB图像的通道操作与图像属性获取方法。主要内容包括:1)通道拆分与合并操作,演示了通过索引和cv2.split()函数拆分BGR通道,以及使用cv2.merge()合并通道的不同效果;2)图像属性获取方法,如shape、size、dtype等属性的含义及使用示例;3)图像加法运算的两种方式("+"运算符和cv2.add()函数)的区别及实际应用;
2.5 通道操作
在 RGB 图像中,图像是由 R 通道、 G 通道、 B 通道三个通道构成的。需要注意的是,在OpenCV 中,通道是按照 B 通道→G 通道→R 通道的顺序存储的。
在图像处理过程中,可以根据需要对通道进行拆分和合并。本节就来介绍如何对通道进行拆分和合并。
2.5.1 通道拆分
针对 RGB 图像,可以分别拆分出其 R 通道、 G 通道、 B 通道。在 OpenCV 中,既可以通过索引的方式拆分通道,也可以通过函数的方式拆分通道。
1. 通过索引拆分
通过索引的方式,可以直接将各个通道从图像内提取出来。例如,针对 OpenCV 内的 BGR图像 img,如下语句分别从中提取了 B 通道、 G 通道、 R 通道。
b = img[ : , : , 0 ]
g = img[ : , : , 1 ]
r = img[ : , : , 2 ]
【例 2.16】 编写程序,演示图像通道拆分及通道值改变对彩色图像的影响。根据题目要求,编写代码如下:
import cv2
lena=cv2.imread("lenacolor.png")
cv2.imshow("lena1",lena)
b=lena[:,:,0]
g=lena[:,:,1]
r=lena[:,:,2]
cv2.imshow("b",b)
cv2.imshow("g",g)
cv2.imshow("r",r)
lena[:,:,0]=0
cv2.imshow("lenab0",lena)
lena[:,:,1]=0
cv2.imshow("lenab0g0",lena)
cv2.waitKey()
cv2.destroyAllWindows()
本例实现了通道拆分和通道值
语句 b=lena[:,:,0]获取了图像 img 的 B 通道。
语句 g=lena[:,:,0]获取了图像 img 的 G 通道。
语句 r=lena[:,:,0]获取了图像 img 的 R 通道。
语句 lena[:,:,0]=0 将图像 img 的 B 通道值设置为 0。
语句 lena[:,:,1]=0 将图像 mg 的 G 通道值设置为 0。
运行上述程序,得到如图 2- 21 所示的结果,其中:
图(a)是原始图像 lena。
图(b)是原始图像 lena 的 B 通道图像 b。
图(c)是原始图像 lena 的 G 通道图像 g。
图(d)是原始图像 lena 的 R 通道图像 r。
图(e)是将图像 lena 中 B 通道值置为 0 后得到的图像。
图(f)是将图像 lena 中 B 通道值、 G 通道值均置为 0 后得到的图像。
由于本书为黑白印刷,所以为了更好地观察运行效果,请大家亲自上机运行程序。
2. 通过函数拆分
函数 cv2.split()能够拆分图像的通道。例如,可以使用如下语句拆分彩色 BGR 图像 img,得到 B 通道图像 b、 G 通道图像 g 和 R 通道图像 r。
b,g,r=cv2.split(img)
上述语句与如下语句是等价的:
b=cv2.split(a)[0]
g=cv2.split(a)[1]
r=cv2.split(a)[2]
【例 2.17】 编写程序,使用函数 cv2.split()拆分图像通道。根据题目要求,编写代码如下:
import cv2
lena=cv2.imread("lenacolor.png")
b,g,r=cv2.split(lena)
cv2.imshow("B",b)
cv2.imshow("G",g)
cv2.imshow("R",r)
cv2.waitKey()
cv2.destroyAllWindows()
运行上述程序,得到如图 2-22 所示的三个通道图像,其中:
左图是 B 通道图像 b。
中间的图是 G 通道图像 g。
右图是 R 通道图像 r。
由于本书为黑白印刷,所以为了更好地观察运行效果,请大家亲自上机运行程序。
2.5.2 通道合并
通道合并是通道拆分的逆过程,通过合并通道可以将三个通道的灰度图像构成一幅彩色图像。函数 cv2.merge()可以实现图像通道的合并,例如有 B 通道图像 b、 G 通道图像 g 和 R 通道图像 r,使用函数 cv2.merge()可以将这三个通道合并为一幅 BGR 的三通道彩色图像。其实现的语句为:
bgr=cv2.merge([b,g,r])
【例 2.18】 编写程序,演示使用函数 cv2.merge()合并通道。
根据题目要求,编写代码如下:
import cv2
lena=cv2.imread("lenacolor.png")
b,g,r=cv2.split(lena)
bgr=cv2.merge([b,g,r])
rgb=cv2.merge([r,g,b])
cv2.imshow("lena",lena)
cv2.imshow("bgr",bgr)
cv2.imshow("rgb",rgb)
cv2.waitKey()
cv2.destroyAllWindows()
在本例中,首先对 BGR 图像进行了拆分,接下来又对其进行了两种不同形式的合并。
语句 b,g,r=cv2.split(lena)对图像 lena 进行拆分,得到 b、 g、 r 这三个通道。
语句 bgr=cv2.merge([b,g,r])对通道 b、 g、 r 进行合并,合并顺序为 B 通道→G 通道→R
通道,得到图像 bgr。
语句 rgb=cv2.merge([r,g,b])对通道 r、 g、 b 进行合并,合并顺序为 R 通道→G 通道→B
通道,得到图像 rgb。
运行上述程序,得到如图 2-23 所示的图像,其中:
左图是原始图像 lena。
中间的图是 lena 图像经过通道拆分、合并后得到的 BGR 通道顺序的彩色图像 bgr。
右图是 lena 图像经过通道拆分、合并后得到的 RGB 通道顺序的彩色图像 rgb。
由于本书为黑白印刷,所以为了更好地观察运行效果,请大家亲自上机运行程序。
通过本例可以看出,改变通道顺序后,图像显示效果会发生变化。
2.6 获取图像属性
在图像处理过程中,经常需要获取图像的属性,例如图像的大小、类型等。这里介绍几个常用的属性。
shape:如果是彩色图像,则返回包含行数、列数、通道数的数组;如果是二值图像或者灰度图像,则仅返回行数和列数。通过该属性的返回值是否包含通道数,可以判断一
幅图像是灰度图像(或二值图像)还是彩色图像。
size:返回图像的像素数目。其值为“行×列×通道数”,灰度图像或者二值图像的通道数为 1。
dtype:返回图像的数据类型。
【例 2.19】 编写程序,观察图像的常用属性值。根据题目要求,编写代码如下:
import cv2
gray=cv2.imread("lena.bmp",0)
color=cv2.imread("lenacolor.png")
print("图像 gray 属性: ")
print("gray.shape=",gray.shape)
print("gray.size=",gray.size)
print("gray.dtype=",gray.dtype)
print("图像 color 属性: ")
print("color.shape=",color.shape)
print("color.size=",color.size)
print("color.dtype=",color.dtype)
在本例中,分别读取了灰度图像 gray 和彩色图像 color,并分别观察了它们的 shape、 size、dtype 属性。
运行程序, 控制台会输出如下结果:
图像 gray 属性:
gray.shape= (256, 256)
gray.size= 65536
gray.dtype= uint8
图像 color 属性:
color.shape= (512, 512, 3)
color.size= 786432
color.dtype= uint8
第 3 章 图像运算
针对图像的加法运算、位运算都是比较基础的运算。但是,很多复杂的图像处理功能正是借助这些基础的运算来完成的。所以,牢固掌握基础操作,对于更好地实现图像处理是非常有帮助的。本章简单介绍了加法运算、位运算,并使用它们实现了位平面分解、图像异或加密、数字水印、脸部打码/解码等实例。
3.1 图像加法运算
在图像处理过程中,经常需要对图像进行加法运算。可以通过加号运算符“+”对图像进行加法运算,也可以通过 cv2.add()函数对图像进行加法运算。
通常情况下,在灰度图像中,像素用 8 个比特位(一个字节)来表示,像素值的范围是[0,255]。两个像素值在进行加法运算时,求得的和很可能超过 255。上述两种不同的加法运算方式,对超过 255 的数值的处理方式是不一样的。
3.1.1 加号运算符
使用加号运算符“+”对图像 a(像素值为 a)和图像 b(像素值为 b)进行求和运算时,遵循以下规则:
式中, mod()是取模运算,“mod(a+b, 256)”表示计算“a+b 的和除以 256 取余数”。根据上述规则,两个点进行加法运算时:
如果两个图像对应像素值的和小于或等于 255,则直接相加得到运算结果。例如,像素值 28 和像素值 36 相加,得到计算结果 64。
如果两个图像对应像素值的和大于 255,则将运算结果对 256 取模。例如 255+58=313,
大于 255,则计算(255+58)% 256 = 57,得到计算结果 57。
当然,上述公式也可以简化为𝑎 + 𝑏 = mod(𝑎 + 𝑏, 256),在运算时无论相加的和是否大于255,都对数值 256 取模。
【例 3.1】 使用随机数数组模拟灰度图像,观察使用“+”对像素值求和的结果。
分析:通过将数组的数值类型定义为 dtype=np.uint8,可以保证数组值的范围在[0,255]之间。
根据题目要求及分析,编写程序如下:
import numpy as np
img1=np.random.randint(0,256,size=[3,3],dtype=np.uint8)
img2=np.random.randint(0,256,size=[3,3],dtype=np.uint8)
print("img1=\n",img1)
print("img2=\n",img2)
print("img1+img2=\n",img1+img2)
运行程序,得到如下计算结果:
img1=
[[178 83 29]
[202 200 158]
[ 27 177 162]]
img2=
[[ 26 48 57]
[ 52 153 8]
[ 10 232 7]]
img1+img2=
[[204 131 86]
[254 97 166]
[ 37 153 169]]
从上述程序可以看到,使用“+”计算两个 256 级灰度图像内像素值的和时,运算结果会对 256 取模。
需要注意,本例题中的加法要进行取模,这是由数组的类型 dtype=np.uint8 所规定的。
3.1.2 cv2.add()函数
函数 cv2.add()可以用来计算图像像素值相加的和,其语法格式为:
计算结果=cv2.add(像素值 a,像素值 b)
使用函数 cv2.add()对像素值 a 和像素值 b 进行求和运算时,会得到像素值对应图像的饱和值(最大值)。例如, 8 位灰度图像的饱和值为 255, 因此,在对 8 位灰度图的像素值求和时,遵循以下规则:
根据上述规则,在 256 级的灰度图像(8 位灰度图)中的两个像素点进行加法运算时:
如果两个像素值的和小于或等于 255,则直接相加得到运算结果。例如,像素值 28 和
像素值 36 相加,得到计算结果 64。
如果两个像素值的和大于 255,则将运算结果处理为饱和值 255。例如 255+58=313, 大于 255,则得到计算结果 255。
需要注意,函数 cv2.add()中的参数可能有如下三种形式。
形式 1:计算结果=cv2.add(图像 1,图像 2),两个参数都是图像,此时参与运算的图像大小和类型必须保持一致。
形式 2:计算结果=cv2.add(数值,图像),第 1 个参数是数值,第 2 个参数是图像,此时将超过图像饱和值的数值处理为饱和值(最大值)。
形式 3:计算结果=cv2.add(图像,数值),第 1 个参数是图像,第 2 个参数是数值,此时将超过图像饱和值的数值处理为饱和值(最大值)。上述三种形式将在本章的后续小节中进一步介绍。
【例 3.2】 使用随机数组模拟灰度图像,观察函数 cv2.add()对像素值求和的结果。根据题目要求,编写程序如下:
import numpy as np
import cv2
img1=np.random.randint(0,256,size=[3,3],dtype=np.uint8)
img2=np.random.randint(0,256,size=[3,3],dtype=np.uint8)
print("img1=\n",img1)
print("img2=\n",img2)
img3=cv2.add(img1,img2)
print("cv2.add(img1,img2)=\n",img3)
运行程序,得到如下计算结果:
img1=
[[136 212 1]
[ 47 234 85]
[197 107 169]]
img2=
[[109 212 62]
[ 19 218 245]
[ 19 103 137]]
cv2.add(img1,img2)=
[[245 255 63]
[ 66 255 255]
[216 210 255]]
【例 3.3】 分别使用加号运算符和函数 cv2.add()计算两幅灰度图像的像素值之和,观察处理结果。
根据题目要求,编写程序如下:
import cv2
a=cv2.imread("lena.bmp",0)
b=a
result1=a+b
result2=cv2.add(a,b)
cv2.imshow("original",a)
cv2.imshow("result1",result1)
cv2.imshow("result2",result2)
cv2.waitKey()
cv2.destroyAllWindows()
在本例中,首先读取了图像 lena 并将其标记为变量 a;接下来,使用语句“b=a”将图像lena 复制到变量 b 内;最后,分别使用“+”和函数 cv2.add()计算 a 和 b 之和。
运行程序,得到如图 3-1 所示的运行结果,其中:
左图是原始图像 lena。
中间的图是使用加号运算符将图像 lena 自身相加的结果。
右图是使用函数 cv2.add()将图像 lena 自身相加的结果。
从上述运算结果可以看出:
使用加号运算符计算图像像素值的和时,将和大于 255 的值进行了取模处理,取模后大于 255 的这部分值变得更小了,导致本来应该更亮的像素点变得更暗了,相加所得的图像看起来并不自然。
使用函数 cv2.add()计算图像像素值的和时,将和大于 255 的值处理为饱和值 255。图像像素值相加后让图像的像素值增大了,图像整体变亮。
3.2 图像加权和
所谓图像加权和,就是在计算两幅图像的像素值之和时,将每幅图像的权重考虑进来,可以用公式表示为: dst = saturate(src1 × 𝛼 + src2 × 𝛽 + 𝛾)
式中, saturate()表示取饱和值(最大值)。图像进行加权和计算时,要求 src1 和 src2 必须大小、类型相同,但是对具体是什么类型和通道没有特殊限制。它们可以是任意数据类型,也可以有任意数量的通道(灰度图像或者彩色图像),只要二者相同即可。
OpenCV 中提供了函数 cv2.addWeighted(),用来实现图像的加权和(混合、融合),该函数的语法格式为:
dst=cv2.addWeighted(src1, alpha, src2, beta, gamma)
其中, 参数 alpha 和 beta 是 src1 和 src2 所对应的系数,它们的和可以等于 1,也可以不等于 1。该函数实现的功能是 dst = src1×alpha + src2×beta + gamma。需要注意,式中参数 gamma 的值可以是 0,但是该参数是必选参数, 不能省略。可以将上式理解为“结果图像=图像 1×系数 1+
图像 2×系数 2+亮度调节量”。
【例 3.4】 使用数组演示函数 cv2.addWeighted()的使用。根据题目要求,编写程序如下:
1. import cv2
2. import numpy as np
3. img1=np.ones((3,4),dtype=np.uint8)*100
4. img2=np.ones((3,4),dtype=np.uint8)*10
5. gamma=3
6. img3=cv2.addWeighted(img1,0.6,img2,5,gamma)
7. print(img3)
本例中的各行代码功能如下。
第 3 行生成一个 3×4 大小的、元素数值都是 100 的二维数组,对应一个灰度图像 img1。
第 4 行生成一个 3×4 大小的、元素数值都是 10 的二维数组,对应一个灰度图像 img2。
第 5 行将调节亮度参数 gamma 的值设置为 3。 第 6 行计算“img1×0.6+img2×5+3”的混合值。运行程序,得到如下运行结果:
[[113 113 113 113] [113 113 113 113] [113 113 113 113]]
【例 3.5】 使用函数 cv2.addWeighted()对两幅图像进行加权混合,观察处理结果。根据题目要求,编写程序如下:
import cv2
a=cv2.imread("boat.bmp")
b=cv2.imread("lena.bmp")
result=cv2.addWeighted(a,0.6,b,0.4,0)
cv2.imshow("boat",a)
cv2.imshow("lena",b)
cv2.imshow("result",result)
cv2.waitKey()
cv2.destroyAllWindows()
本程序使用 cv2.addWeighted()函数,对图像 boat 和图像 lena 分别按照 0.6 和 0.4 的权重进行混合。
运行程序,得到如图 3-2 所示的结果,其中:
左图是原始图像 boat。
中间的图是原始图像 lena。
右图是图像 boat 和图像 lena 加权混合后的结果图像。
【例 3.6】 使用函数 cv2.addWeighted()将一幅图像的 ROI 混合在另外一幅图像内。根据题目要求,编写程序如下:
import cv2
lena=cv2.imread("lena512.bmp",cv2.IMREAD_UNCHANGED)
dollar=cv2.imread("dollar.bmp",cv2.IMREAD_UNCHANGED)
cv2.imshow("lena",lena)
cv2.imshow("dollar",dollar)
face1=lena[220:400,250:350]
face2=dollar[160:340,200:300]
add=cv2.addWeighted(face1,0.6,face2,0.4,0)
dollar[160:340,200:300]=add
cv2.imshow("result",dollar)
cv2.waitKey()
cv2.destroyAllWindows()
在本例中, face1 是图像 lena 中的面部部分, face2 是图像 dollar 中的面部部分。通过函数cv2.addWeighted()将 lena 图像内的面部 face1 与 dollar 图像内的面部 face2 进行了混合计算。
运行程序,会得到如图 3-3 所示的结果,其中:
左图是原始图像 lena。
中间的图是原始图像 dollar。
右图是图像 lena 的面部与图像 dollar 的面部加权混合得到的图像。

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。
更多推荐
所有评论(0)