像素是图像构成的基本单位,像素处理是图像处理的基本操作,可以通过位置索引的形式对图像内的元素进行访问、处理。
1.二值图像及灰度图像
需要说明的是,在 OpencV中,最小的数据类型是无符号的8 位数,因此,在 OpencV中实际上并没有二值图像这种数据类型,二值图像经常是通过处理得到的,然后使用0 表示黑色, 使用 255 表示白色
可以将二值图像理解为特殊的灰度图像,这里仅以灰度图像为例讨论像素的读取和修改通过 2.1 节的分析可知,可以将图像理解为一个矩阵,在面向 Python的 Opencv( OpenCV for Python)中,图像就是 Numpy 库中的数组。一个 OpenCv 灰度图像是一个二维数组,可以使用表达式访问其中的像素值,例如,可以使用 image[0,0]访间图像 image第0 行第0 列位置上的像素点。第0 行第0 列位于图像的左上角,其中第1 个索引表示第0行,第2 个索
引表示第0列.
为了方便理解,我们首先使用 Numpy 库来生成一个 8x8 大小的数组,用来模拟一个黑色图像,并对其进行简单处理。
【例 21】使用 Numpy 库生成一个元素值都是0 的二维数组,用来模拟一幅黑色图像,并对其进行访问、修改。
分析:使用 Numpy 库中的函数 zeros() 可以牛成一个元素值都是0 的数组,并可以直接使
用数组的索引对其进行访问、修改。
根据题目要求及分析,编写代妈如下:
import cv2
import numpy as np
img=np.zeros((8,8),dtype=np.uint8)
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()
代码分析如下
1.使用函数 zeros 生成了一个 8×8 大小的二维数组,其中所有的值都是 0.数值类型是np.uint8.根据该数组的属性,可以将其看成一个黑色的图像
2.语句img[0,3]访问的是 img第0 行第3 列的像素点,需要注意的是,行序号、列序号都是从0 开始的
3.语句img[0,3] =255 将img第0 行第3 列的像素点的像素值设置为"255"
运行上述程序,会出现名为 one和 two 的两个非常小的窗口,其中:
4.名为 one的窗口是一个纯黑色的图像,
5.名为 two 的窗口在顶部靠近中间位置有一个白点(对应修改后的值 255),其他地方也都是纯黑的图像
同时,在控制台会输出如下内容:
通过本例中两个窗口显示的图像可知,二维数组与图像之间存在对应关系,因为窗口太小在纸质图书上可能无法直接观察效果,请大家在计算机上运行上述程序,观察效果
【例 2.2】读取一个灰度图像,并对其像素进行访问、修改
根据题目要求,编写代码如下
import cv2
img=cv2.imread("lena.bmp",0)
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()
在本例中。使用了一个嵌套循环语句,将图像中“第 10 行到 99 行与第80 列到99列”交义区域内的像素值设置为 255 从图像 img 上来看,该交又区域被设置为白色
运行结果
1.左侧为原始图像
2.右侧为修改后的图像
2彩色图像
RGB 模式的彩色图像在读入 Opencv 内进行处理时,会按照行方向依次读取该 RGB 图像的B 通道、G 通道、R 通道的像素点,并将像素点以行为单位存储在 ndarray 的列中,例如,有一幅大小为R行×C 列的原始 RGB 图像,其在 OpenCV 内以 BGR 模式的三维数组形式存储。
可以使用表达式访问数组内的值。例如,可以使用image[0,0,0]访问图像的B通道内的第0 行第0 列上的像素点,式中:
1.第1个索引表示第0行
2第2 个索引表示第0列
3.第3 个素引表示第0 个颜色通道
根据上述分析可知,假设有一个红色(其R 通道值为 255,G 通道值为 0,B 通道值为0)
- image[0,0]访问图像 image第0 行第0 列像素点的 BGR值,图像是BGR格式的,得到的数值为 [0,0,255].
2.image[0,0,0]访问图像 image第0 行第0 列第0 个通道的像素值 ,图像是BGR格式的,所以第0个通道是B通道,会得到B通道内第0行第0列的位置所对应的值0。
3.image[0,0,1]访问图像 image第0 行第0 列第1 个通道的像素值 ,图像是BGR格式的,所以第1个通道是G通道,会得到G通道内第0行第0列的位置所对应的值0。
4.image[0,0,2]访问图像 image第0 行第0 列第2 个通道的像素值 ,图像是BGR格式的,所以第2个通道是R通道,会得到G通道内第0行第0列的位置所对应的值255。
为了方使理解,我们首先使用 numpy库来生成一个 2×4×3 大小的数组,用它模拟一幅黑色图像,并对其进行简单处理
【例 2.3】 使用numpy生成三维数组,用来观察三个通道值的变化情况
根据题目要求 编写代码如下
import numpy as np
import cv2
#-----------蓝色通道值--------------
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()
在本例中,分别生成了blue,green,red三个数组,期初始值都是0,接下来,分别改变个通道的值。
1.针对数组blue,将其第0个通道的值设置为255。从图像的角度来看,图像blue的B通道值为 255.其余两个通道值为0,因此图像 blue为蓝色图像
- 针对数组 gem,将其第1个通道的值设置为255。从图像的角度来看,图像green的G通道值为 255,其余两个通道值为 0.因此图像 green为绿色图像
3.针对数组 red,将其第2个道道的值设置为 255.从图像角度来看,图像 red的R通道值为 255,其余两个通道值为 0,因此图像 red 为红色图像
运行上述程序,会最示颜色为蓝色、绿色、红色的三幅图像,分别对应数组 bue、数组 green
数组 red 因为黑白印剧无法显示彩色图像,所以请读者运行程序后观察结果
除了显示图像,还会显示每个数组的轮出值,部分输出结果如图 2-8 所示。
blue=
[[[255 0 0]
[255 0 0]
[255 0 0]
...
[255 0 0]
[255 0 0]
[255 0 0]]
[[255 0 0]
[255 0 0]
[255 0 0]
...
green=
[[[ 0 255 0]
[ 0 255 0]
[ 0 255 0]
...
[ 0 255 0]
[ 0 255 0]
[ 0 255 0]]
[[ 0 255 0]
[ 0 255 0]
[ 0 255 0]
...
red=
[[[ 0 0 255]
[ 0 0 255]
[ 0 0 255]
...
【例 2.4】使用numpy生成三维数组,用来观察三个通道值的变化情况
根据题目要求 编写代码如下
import numpy as np
import cv2
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()
输出结果如图
【例 2.5】使用numpy 生成一个三维数组,用来模拟一幅 BGR 模式的彩色图像,并对其进行访问,修改,
分析:使用 Numpy 中的 zeros(函数可以生成一个元素值都是0 的数组。可以直接使用数组的索引形式对其进行访问、修改。
根据题日要求及分析,编写代码如下
import numpy as np
img=np.zeros((2,4,3),dtype=np.uint8)
print("img=\n",img)
print("读取像素点img[0,3]=",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)
print("读取修改后像素点img[1,2,2]=",img[1,2,2])
本程序进行了如下操作
1.第2 行使用 zeros0 生成一个 2×4×3 大小的数组,其对应一个“2行4列3 个通道”的BGR 图像
2.第3 行使用 print语句显示(打印)当前图像(数组)的值。
3.第4 行中的 img[0,3],语句会访问第0 行第3 列位置上的B 通道、G 通道、R 通道三个像素点。
4.第5 行的 img[1,2,2]语句会访问第1 行第2 列第2 个通道位置上的像素点
5.第6 行的 img[0,3]=255 语句会修改 img 中第0 行第3 列位置上的像素值,该位置上的B通道、G 通道、R 通道三个像素点的值都会被修改为 255
6.第7 行的 img[0,0]=[66,77,88] 语句会修改 img 中第0 行第0 列位置上的B 通道、G 通道、R 通道上三个像素点的值,将它们修改为[66,77,88]
7.第8 行的img[1,1,1]=3 语句会修改 img 中第1 行第1 列第1 个通道(G 通道)位置上的像素值,将其修改为3
8.第9 行的img[1,2,2]=4 语句会修改 img 中第1 行第2 列第2 个通道(R 通道)位置上的像素值,将其修改为4。
9.第 10 行的img[0.2.0]=5 语句会修改 img 中第0 行第2 列第0 个通道(B 通道)位置上的像素值,将其修改为5
10.最后两行使用 print 语句观察 img和img[1,2,2]的值
运行结果如下:
img=
[[[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]]
[[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]]]
读取像素点img[0,3]= [0 0 0]
读取像素点img[1,2,2]= 0
修改后img
[[[ 66 77 88]
[ 0 0 0]
[ 5 0 0]
[255 255 255]]
[[ 0 0 0]
[ 0 3 0]
[ 0 0 4]
[ 0 0 0]]]
读取修改后像素点img[1,2,2]= 4
在本例中,为了方便说明问题,设置的数组比较小,在实际中可以定义稍大的数组,并使用cv2.imshow()将其显示出来,进一步观察处理结果,加深理解。
【例 2.6】读取一副彩色图像,并对其像素进行访问,修改
根据题目要求,编写代码如下:
import cv2
img=cv2.imread("lenacolor.png")
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()
上述程序进行了如下操作,
1.第2 行使用 imread() 函数读取当前目录下的一幅彩色 RGB 图像
2.第4 行的 img[0,0] 语句会访问 img中第0 行第0 列位置上的B 通道、G 通道、R通道三个像素
3.第 5-7 行分别会访间 img中第0 行第0 列位置上的B 通道、G 通道、R 通道三个像素
4.第8 行的img[50,0] 语句会访间第 50 行第0 列位置上的B 通道、G 通道、R 通道三个像素点
5.第9 行的 img[100,0] 句会访问第 100 行第0 列位置上的B 通道、G 通道、R通道三个像素点
6.第 10-14 行使用三个 for 句的嵌套循环,对图像左上角区域(即“第0 行到第 49行”与“第0 列到第 99列”的行列交叉区域,我们称之为区域 1)内的像素值进行设定借助 img[i,j,k]=255语句将该区域内的三个通道的像素值都设置为 255,让该区域变为白色
7.第 15-18 行使用两个for 语句的嵌套循环,对图像左上角位于区域1 正下方的区域(即“第 50 行到第 99行”与“第0 列到第 99列”的行列交叉区域,我们称之为区域2)内的像素值进行设定,做游识 img[i,j]=[128,128,128] 语句将该区域内的三个通道的像素值都设置为 128,让该区域变为灰色
8.第 19~21 行使用两个 for 语句的嵌套循环,对图像左上角位于区域2 正下方的区域(即 第 100 行到第 149行”与“第0 列到第 99列”的行列交叉区域,我们称之为区域 3)内的像素值进行设定,借助 img[i,j]=0 语句将该区域内的三个通道的像素值都设置为0 让该区域变为黑色
运行程序,结果如图 2-1 所示,其中左图是读取的原始图像,右图是经过修改后的图像
访问img[0,0]= [125 137 226]
访问img[0,0,0]= 125
访问img[0,0,1]= 137
访问img[0,0,2]= 226
访问img[50,0]= [114 136 230]
访问img[100,0]= [ 75 55 155]
修改后img[0,0]= [255 255 255]
修改后img[0,0,0]= 255
修改后img[0,0,1]= 255
修改后img[0,0,2]= 255
修改后img[50,0]= [128 128 128]
修改后img[100,0]= [0 0 0]