OpenCV轻松入门_面向python(第二章图像处理基础)
2.1图像的基本表示方法
1.二值图像
二值图像是指仅仅包含黑色和白色两种颜色的图像。
在计算机中,通过一个栅格状排列的数据集(矩阵)来表示和处理图像。如图,一个字母 A 的图像,计算机在处理该图像时,会首先将其划分为一个个的小方块,每一个小方块就是一个独立的处理单位,称为像素点。接下来,计算机会将其中的白色像素点(白色小方块区域)处理为“1”,将黑色像素点(黑色小方块区域)处理为“0”,以方便进行后续的存储和处理等操作。
2.灰度图像
二值图像表示起来简单方便,但是因为其仅有黑白两种颜色,所表示的图像不够细腻。如果想要表现更多的细节,就需要使用更多的颜色。如图 lena 图像是一幅灰度图像,它采用了更多的数值以体现不同的颜色,因此该图像的细节信息更丰富。
通常,计算机会将灰度处理为 256 个灰度级,用数值区间[0, 255]来表示。其中,数值255表示纯白色,数值0表示纯黑色,其余的数值表示从纯白到纯黑之间不同级别的灰度。
3.彩色图像
在 RGB 色彩空间中,存在 R(red,红色)通道、G(green,绿色)通道和 B(blue,蓝色)通道,共三个通道。每个色彩通道值的范围都在[0, 255]之间,我们用这三个色彩通道的组合表示颜色。可以调配出所有常见256×256×256=16 777 216种颜色。
R值 | G值 | B值 | RGB值 | 颜色名称 |
---|---|---|---|---|
0 | 0 | 0 | (0,0,0) | 纯黑色 |
255 | 255 | 255 | (255,255,255) | 纯白色 |
255 | 0 | 0 | (255,0,0) | 红色 |
0 | 255 | 0 | (0,255,0) | 绿色 |
0 | 0 | 255 | (0,0,255) | 蓝色 |
114 | 141 | 216 | (114,141,216) | 天蓝色 |
139 | 69 | 19 | (139,69,19) | 棕色 |
一般情况下,在 RGB 色彩空间中,图像通道的顺序是 R→G→B,即第 1 个通道是 R 通道,第 2 个通道是 G 通道,第 3 个通道是 B 通道。需要特别注意的是,在 OpenCV 中,通道的顺序是 B→G→R,即:
- 第 1 个通道保存 B 通道的信息。
- 第 2 个通道保存 G 通道的信息。
- 第 3 个通道保存 R 通道的信息。
2.2像素处理
二值图:
使用 Numpy
库生成一个元素值都是 0 的二维数组,用来模拟一幅黑色图像,并对其进行访问、修改。
分析:使用 Numpy 库中的函数 zeros()可以生成一个元素值都是 0 的数组,并可以直接使用数组的索引对其进行访问、修改。
import cv2
import numpy as np
img = np.zeros((8,8),dtype = np.uint8)
#np.uint8 是 NumPy 中的一个数据类型,用于表示 8 位无符号整数。
print("img=\n",img)
cv2.imshow("one",img)
print("读取像素点 img[0,3]=",img[0,3])
img[0,3]=255
print("修改后 img=\n",img)
print("读取修改后像素点 img[0,3]=",img[0,3])
cv2.imshow("two",img)
cv2.waitKey()
cv2.destroyAllWindows()
灰度图:
import cv2
img = cv2.imread("duo.webp",-1)
cv2.imshow("before",img)
for i in range(10,100):for j in range(80,100):img[i,j]=255
cv2.imshow("after",img)
cv2.waitKey()
cv2.destroyAllWindows()
彩色图像:
RGB 模式的彩色图像在读入 OpenCV 内进行处理时,会按照行方向依次读取该 RGB 图像的 B 通道、G 通道、R 通道的像素点,并将像素点以行为单位存储在 ndarray 的列中。例如,有一幅大小为 R 行×C 列的原始 RGB 图像,其在 OpenCV 内以 BGR 模式的三维数组形式存储。
使用 Numpy
生成三维数组,用来观察三个通道值的变化情况。
import cv2
import numpy as np
#-----------蓝色通道值--------------
blue = np.zeros((300,300,3),dtype=np.uint8)
blue[:, :, 0] = 255
print("blue=\n",blue)
cv2.imshow("blue",blue)
#-----------绿色通道值--------------
green =np.zeros((300,300,3),dtype=np.uint8)
green[:,:,1]=255
print("green=\n", green)
cv2.imshow("green",green)
#-----------红色通道值--------------
red =np.zeros((300,300,3),dtype=np.uint8)
red[:,:,2]=255
print("red=\n", red)
cv2.imshow("red",red)
cv2.waitKey()
cv2.destroyAllWindows()
使用 Numpy
生成"一个"三维数组,用来观察三个通道值的变化情况。
import cv2
import numpy as np
img = np.zeros((300,300,3),dtype=np.uint8)
img[:,0:100,0]=255
img[:,100:200,1]=255
img[:,200:300,2]=255
print("img=\n",img)
cv2.imshow("img",img)
cv2.waitKey()
cv2.destroyAllWindows()
使用Numpy
生成一个三维数组,用来模拟一幅 BGR 模式的彩色图像,并对其进行访问、修改。
import numpy as np
img = np.zeros((2,4,3),dtype=np.uint8)
print("img=\n",img)
print("读取像素点img[0,3]=\n",img[0,3])
print("读取像素点 img[1,2,2]=",img[1,2,2])
img[0,3]=255
img[0,0]=[66,77,88]
img[1,1,1]=3
img[1,2,2]=4
img[0,2,0]=5
print("修改后 img\n",img)
读取一幅彩色图像,并对其像素进行访问、修改。
import cv2
import numpy as np
img = cv2.imread("suo.jpg")
cv2.imshow("before",img)
print("访问 img[0,0]=",img[0,0])
print("访问 img[0,0,0]=",img[0,0,0])
print("访问 img[0,0,1]=",img[0,0,1])
print("访问 img[0,0,2]=",img[0,0,2])
print("访问 img[50,0]=",img[50,0])
print("访问 img[100,0]=",img[100,0])
#区域 1
for i in range(0,50):for j in range(0, 100):for k in range(0,3):img[i, j, k] = 255 #白色#区域 2
for i in range(50,100):for j in range(0,100):img[i,j]=[128,128,128] #灰色#区域 3
for i in range(100,150):for j in range(0, 100):img[i,j]=0 #黑色
cv2.imshow("after",img)
print("修改后 img[0,0]=",img[0,0])
print("修改后 img[0,0,0]=",img[0,0,0])
print("修改后 img[0,0,1]=",img[0,0,1])
print("修改后 img[0,0,2]=",img[0,0,2])
print("修改后 img[50,0]=",img[50,0])
print("修改后 img[100,0]=",img[100,0])
cv2.waitKey()
cv2.destroyAllWindows()
2.3使用使用 numpy.array
访问像素
1.二值图像及灰度图像
可以将二值图像理解为特殊的灰度图像,所以这里仅以灰度图像为例讨论像素点值的读取和修改。
函数 item()能够更加高效地访问图像的像素点,该函数的语法格式为:
item(行,列)
函数 itemset()可以用来修改像素值,其语法格式为:
itemset(索引值,新值)
使用 Numpy
生成一个二维随机数组,用来模拟一幅灰度图像,并对其像素进行访问、修改。使用 Numpy
中的 random.randint
可以生成一个随机数组,该随机数组对应一幅灰度图像。然后分别使用函数 item()
及函数itemset()
对其像素进行访问、修改。
import numpy as np
print(np.__version__)
import numpy as np
img = np.random.randint(10,99,size=[5,5],dtype=np.uint8)
print("img=\n",img)
print("读取像素点 img.item(3,2)=",img.item(3,2))
#img.itemset((3,2),255) itemset 方法在 NumPy 2.0 中已经被移除
img[3, 2] = 255
print("修改后 img=\n", img)
print("修改后像素点 img.item(3,2)=",img.item(3,2))
生成一个灰度图像,让其中的像素值均为随机数。
import numpy as np
import cv2
img = np.random.randint(0,256,size=[256,256],dtype=np.uint8)
cv2.imshow("demo",img)
cv2.waitKey()
cv2.destroyAllWindows()
读取一幅灰度图像,并对其像素值进行访问、修改
import cv2
import numpy as np
img = cv2.imread('duo.webp',0)
#测试读取、修改单个像素值
print("读取像素点 img.item(3,2)=",img.item(3,2))
img[3,2]=255
print("修改后像素点 img.item(3,2)=",img.item(3,2))
#测试修改一个区域的像素值
cv2.imshow("before",img)
for i in range(10,100):for j in range(80,100):img[i,j]=255
cv2.imshow("after",img)
cv2.waitKey()
cv2.destroyAllWindows()
2.彩色图像
使用 Numpy
生成一个由随机数构成的三维数组,用来模拟一幅 RGB 色彩空间的彩色图像,并使用函数 item()和 itemset()来访问和修改它。
import numpy as np
img=np.random.randint(10,99,size=[2,4,3],dtype=np.uint8)
print("img=\n",img)
print("读取像素点 img[1,2,0]=",img.item(1,2,0))
print("读取像素点 img[0,2,1]=",img.item(0,2,1))
print("读取像素点 img[1,0,2]=",img.item(1,0,2))
img[1,2,0]=255
img[0,2,1]=255
img[1,0,2]=255
print("修改后 img=\n",img)
print("修改后像素点 img[1,2,0]=",img.item(1,2,0))
print("修改后像素点 img[0,2,1]=",img.item(0,2,1))
print("修改后像素点 img[1,0,2]=",img.item(1,0,2))
生成一幅彩色图像,让其中的像素值均为随机数。
import cv2
import numpy as np
img=np.random.randint(0,256,size=[256,256,3],dtype=np.uint8)
cv2.imshow("demo",img)
cv2.waitKey()
cv2.destroyAllWindows()
读取一幅彩色图像,并对其像素进行访问、修改。
import cv2
import numpy as np
img=cv2.imread("suo.jpg")
cv2.imshow("before",img)
print("访问 img.item(0,0,0)=",img.item(0,0,0))
print("访问 img.item(0,0,1)=",img.item(0,0,1))
print("访问 img.item(0,0,2)=",img.item(0,0,2))
for i in range(0,50):for j in range(0,100):for k in range(0,3):img[i,j,k]=255 #白色
cv2.imshow("after",img)
print("修改后 img.item(0,0,0)=",img.item(0,0,0))
print("修改后 img.item(0,0,1)=",img.item(0,0,1))
print("修改后 img.item(0,0,2)=",img.item(0,0,2))
cv2.waitKey()
cv2.destroyAllWindows()
2.4感兴趣区域(ROI)
在图像处理过程中,我们可能会对图像的某一个特定区域感兴趣,该区域被称为感兴趣区域(Region of Interest,ROI)。在设定感兴趣区域 ROI 后,就可以对该区域进行整体操作。例如,将一个感兴趣区域 A 赋值给变量 B 后,可以将该变量 B 赋值给另外一个区域 C,从而达到在区域 C 内复制区域 A 的目的。
获取图像信息,并将其显示出来。
import cv2
a = cv2.imread('suo.jpg',cv2.IMREAD_UNCHANGED)
face=a[260:500,300:500]
cv2.imshow("original",a)
cv2.imshow("face",face)
cv2.waitKey()
cv2.destroyAllWindows()
对图像获取的信息进行打码。
import cv2
import numpy as np
a=cv2.imread("suo.jpg",cv2.IMREAD_UNCHANGED)
cv2.imshow("original",a)
face=np.random.randint(0,256,(240,200,3))
a[260:500,300:500]=face
cv2.imshow("result",a)
cv2.waitKey()
cv2.destroyAllWindows()
将一幅图像内的 ROI 复制到另一幅图像内。
#2.4.3
#将一幅图像内的 ROI 复制到另一幅图像内。
# 2.4.3 完整示例:将一幅图像的 ROI 复制到另一幅图像指定区域(确保大小匹配)
import cv2
import numpy as np
# 读取图像(路径请根据你的文件位置修改)
lena = cv2.imread("duo.webp", cv2.IMREAD_UNCHANGED)
dollar = cv2.imread("suo.jpg", cv2.IMREAD_UNCHANGED)# 检查图像是否读取成功
if lena is None:print("错误:无法读取 duo.webp,请检查路径")exit()
if dollar is None:print("错误:无法读取 suo.jpg,请检查路径")exit()# 显示原图(可选)
cv2.imshow("lena", lena)
cv2.imshow("dollar", dollar)# 选取 lena 图像中的 ROI 区域,示例这里取 100:300 行,0:200 列(200x200 区域)
face = lena[100:300, 0:200]# 获取 face 尺寸
h, w = face.shape[:2]# 将 face 复制到 dollar 指定区域,位置在 (200,300),大小必须匹配 face
dollar[200:200+h, 300:300+w] = face# 显示复制后的结果图
cv2.imshow("result", dollar)
cv2.waitKey(0)
cv2.destroyAllWindows()
2.5通道操作
1.通道拆分
通过索引拆分:
通过索引的方式,可以直接将各个通道从图像内提取出来。例如,针对 OpenCV 内的 BGR图像 img,如下语句分别从中提取了 B 通道、G 通道、R 通道。
import cv2
import numpy as np
lena = cv2.imread("D:\openCV\gzj.png")
cv2.imshow("lena",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()
通过函数拆分:
函数 cv2.split()能够拆分图像的通道。例如,可以使用如下语句拆分彩色 BGR 图像 img,得到 B 通道图像 b、G 通道图像 g 和 R 通道图像 r。
import cv2
import numpy as np
lena=cv2.imread("suo.jpg")
b,g,r=cv2.split(lena)
'''
等价于
b=cv2.split(a)[0]
g=cv2.split(a)[1]
r=cv2.split(a)[2]
'''
cv2.imshow("B",b)
cv2.imshow("G",g)
cv2.imshow("R",r)
cv2.waitKey()
cv2.destroyAllWindows()
2.通道合并
通道合并是通道拆分的逆过程,通过合并通道可以将三个通道的灰度图像构成一幅彩色图像。函数 cv2.merge()
可以实现图像通道的合并,例如有 B 通道图像 b、G 通道图像 g 和 R 通道图像 r,使用函数 cv2.merge()
可以将这三个通道合并为一幅 BGR 的三通道彩色图像。
import cv2
lena=cv2.imread("suo.jpg")
b,g,r=cv2.split(lena)
bgr=cv2.merge([b,g,r])
rgb=cv2.merge([r,g,b])
gbr=cv2.merge([g,b,r])
cv2.imshow("lena",lena)
cv2.imshow("bgr",bgr)
cv2.imshow("rgb",rgb)
cv2.imshow("gbr",gbr)
cv2.waitKey()
cv2.destroyAllWindows()
2.6获取图像属性
常见属性:
- shape: 如果是彩色图像,则返回包含行数、列数、通道数的数组;如果是二值图像或者灰度图像,则仅返回行数和列数。通过该属性的返回值是否包含通道数,可以判断一幅图像是灰度图像还是彩色图像。
- size: 返回图像的像素数目。其值为“行×列×通道数”,灰度图像或者二值图像的通道数为 1。
- dtype: 返回图像的数据类型。
import cv2
gray=cv2.imread("duo.webp",0)
color=cv2.imread("suo.jpg")
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)