OpenCV轻松入门:面向Python(第2版)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.2 像素处理

像素是图像构成的基本单位,像素处理是图像处理的基本操作,可以通过位置索引的形式对图像内的元素进行访问、处理。

1.二值图像及灰度图像

需要说明的是,在OpenCV中,最小的数据类型是无符号的8位二进制数。因此,在OpenCV中,实际上并没有仅用一位二进制来表示一个像素值(0或1)的二值图像的数据类型。二值图像经常是通过处理得到的,一般使用0表示黑色,使用255表示白色。

可以将二值图像理解为特殊的灰度图像,这里仅以灰度图像为例讨论像素的读取和修改。通过2.1节的分析可知,可以将图像理解为一个矩阵,在面向Python的OpenCV(OpenCV for Python)中,图像就是Numpy库中的数组。一个OpenCV灰度图像是一个二维数组,可以使用表达式访问其中的像素值。例如,可以使用image[0,0]访问图像image第0行第0列位置上的像素点。第0行第0列位于图像的左上角,其中第1个索引值“0”表示第0行,第2个索引值“0”表示第0列。

为了方便理解,我们首先使用Numpy库来生成一个8×8大小的数组,用来模拟一个黑色图像,并对其进行简单的处理。

【例2.1】使用Numpy库生成一个元素值都是0的二维数组,用来模拟一幅黑色图像,并对其进行访问、修改。

分析:使用Numpy库中的函数zeros()可以生成一个元素值都是0的数组,并可以直接使用数组的索引对其进行访问、修改。

根据题目要求及分析,编写代码如下:

代码分析如下:

● 使用函数zeros()生成了一个8×8大小的二维数组,其中所有的值都是0,数值类型是np.uint8。根据该数组的属性,可以将其看成一个黑色的图像。

● 语句img[0,3]访问的是img第0行第3列的像素点,需要注意的是,行序号、列序号都是从0开始的。

● 语句img[0,3]=255将img中第0行第3列的像素点的像素值设置为“255”。

运行上述程序,会出现名为one和two的两个非常小的窗口,其中:

● 名为one的窗口是一个纯黑色的图像。

● 名为two的窗口在顶部靠近中间位置有一个白点(对应修改后的值255),其他地方也都是纯黑的图像。

同时,在控制台会输出如下内容:

通过本例中两个窗口显示的图像可知,二维数组与图像之间存在对应关系。因为窗口太小,在此处展示并不能直接观察到效果,所以没有把窗口在此展示。请大家在计算机上运行上述程序,观察效果。

【例2.2】读取一个灰度图像,并对其像素进行访问、修改。

根据题目要求,编写代码如下:

在本例中,使用了一个嵌套循环语句,将图像img中“第10行到99行”与“第80列到99列”交叉区域内的像素值设置为255。从图像img上来看,该交叉区域被设置为白色。

运行程序,结果如图2-6所示,其中:

● 图2-6(a)是读取的原始图像。

● 图2-6(b)是经过修改后的图像。

图2-6 像素修改示例

2.彩色图像

RGB模式的彩色图像在读入OpenCV内进行处理时,会按照行方向依次读取该RGB图像的B通道、G通道、R通道的像素点,并将像素点以行为单位存储在ndarray的列中。例如,有一幅大小为R行×C列的原始RGB图像,其在OpenCV内以BGR模式的三维数组形式存储,如图2-7所示。

图2-7 RGB图像以三维数组形式存储的情况说明

可以使用表达式访问数组内的值。例如,可以使用image[0,0,0]访问图像image的B通道内的第0行第0列上的像素点,式中:

● 第1个索引表示第0行。

● 第2个索引表示第0列。

● 第3个索引表示第0个颜色通道。

根据上述分析可知,假设有一幅红色图像(其B通道值为0,G通道值为0,R通道值为255),不同的访问方式得到的值如下。

● img[0,0]:访问图像img第0行第0列像素点的BGR值。图像是BGR模式的,得到的数值为[0,0,255]。

● img[0,0,0]:访问图像img第0行第0列第0个通道的像素值。图像是BGR模式的,所以第0个通道是B通道,会得到B通道内第0行第0列的位置所对应的值0。

● img[0,0,1]:访问图像img第0行第0列第1个通道的像素值。图像是BGR模式的,所以第1个通道是G通道,会得到G通道内第0行第0列的位置所对应的值0。

● img[0,0,2]:访问图像img第0行第0列第2个通道的像素值。图像是BGR模式的,所以第2个通道是R通道,会得到R通道内第0行第0列的位置所对应的值255。

为了方便理解,我们首先使用Numpy库来生成一个2×4×3大小的数组,用它模拟一幅黑色图像,并对其进行简单的处理。

【例2.3】使用Numpy生成三维数组,用来观察三个通道值的变化情况。

根据题目要求,编写代码如下:

在本例中,分别生成了blue、green、red三个数组,其初始值都是0。接下来,分别改变它们不同通道的值。

● 针对数组blue,将其第0个通道的值设置为255。从图像角度来看,图像blue的B通道值为255,其余两个通道值为0,因此图像blue为蓝色图像。

● 针对数组green,将其第1个通道的值设置为255。从图像角度来看,图像green的G通道值为255,其余两个通道值为0,因此图像green为绿色图像。

● 针对数组red,将其第2个通道的值设置为255。从图像角度来看,图像red的R通道值为255,其余两个通道值为0,因此图像red为红色图像。

运行上述程序,会显示颜色为蓝色、绿色、红色的三幅图像,分别对应数组blue、数组green、数组red。[1]

除了显示图像,还会显示每个数组的输出值,部分输出结果如图2-8所示。

图2-8 【例2.3】程序的部分输出结果

【例2.4】使用Numpy生成一个三维数组,用来观察三个通道值的变化情况。

根据题目要求,编写代码如下:

运行上述程序,会显示如图2-9所示的图像。[2]

图2-9 【例2.4】程序的运行结果

除了显示图像,还会显示img值的情况,部分输出结果如图2-10所示。

图2-10 【例2.4】程序的部分输出结果

【例2.5】使用Numpy生成一个三维数组,用来模拟一幅BGR模式的彩色图像,并对其进行访问、修改。

分析:使用Numpy中的zeros()函数可以生成一个元素值都是0的数组。可以直接使用数组的索引形式对其进行访问、修改。

根据题目要求及分析,编写代码如下:

本程序进行了如下操作。

● 第2行使用zeros()生成一个2×4×3大小的数组,其对应一个“2行4列3个通道”的BGR图像。

● 第3行使用print语句显示(打印)当前图像(数组)的值。

● 第4行中的img[0,3]语句会访问第0行第3列位置上的B通道、G通道、R通道三个像素点。

● 第5行的img[1,2,2]语句会访问第1行第2列第2个通道位置上的像素点。

● 第6行的img[0,3]=255语句会修改img中第0行第3列位置上的像素值,该位置上的B通道、G通道、R通道三个像素点的值都会被修改为255。

● 第7行的img[0,0]=[66,77,88]语句会修改img中第0行第0列位置上的B通道、G通道、R通道上三个像素点的值,将它们分别修改为[66,77,88]。

● 第8行的img[1,1,1]=3语句会修改img中第1行第1列第1个通道(G通道)位置上的像素值,将其修改为3。

● 第9行的img[1,2,2]=4语句会修改img中第1行第2列第2个通道(R通道)位置上的像素值,将其修改为4。

● 第10行的img[0,2,0]=5语句会修改img中第0行第2列第0个通道(B通道)位置上的像素值,将其修改为5。

● 最后两行使用print语句观察img和img[1,2,2]的值。

运行上述程序,会在控制台输出如下结果:

在本例中,为了方便说明问题,设置的数组比较小。在实际中可以定义稍大的数组,并使用cv2.imshow()将其显示出来,进一步观察处理结果,加深理解。

【例2.6】读取一幅彩色图像,并对其像素进行访问、修改。

根据题目要求,编写代码如下:

上述程序进行了如下操作。

● 第2行使用imread()函数读取当前目录下的一幅彩色RGB图像。

● 第4行的img[0,0]语句会访问img中第0行第0列位置上的B通道、G通道、R通道三个像素点。

● 第5~7行分别会访问img中第0行第0列位置上的B通道、G通道、R通道三个像素点。

● 第8行的img[50,0]语句会访问第50行第0列位置上的B通道、G通道、R通道三个像素点。

● 第9行的img[100,0]语句会访问第100行第0列位置上的B通道、G通道、R通道三个像素点。

● 第10~14行使用三个for语句的嵌套循环,对图像左上角区域(即“第0行到第49行”与“第0列到第99列”的行列交叉区域,我们称之为区域1)内的像素值进行设定。借助img[i,j,k]=255语句将该区域内的三个通道的像素值都设置为255,让该区域变为白色。

● 第15~18行使用两个for语句的嵌套循环,对图像左上角位于区域1正下方的区域(即“第50行到第99行”与“第0列到第99列”的行列交叉区域,我们称之为区域2)内的像素值进行设定。借助img[i,j]=[128,128,128]语句将该区域内的三个通道的像素值都设置为128,让该区域变为灰色。

● 第19~21行使用两个for语句的嵌套循环,对图像左上角位于区域2正下方的区域(即“第100行到第149行”与“第0列到第99列”的行列交叉区域,我们称之为区域3)内的像素值进行设定。借助img[i,j]=0语句将该区域内的三个通道的像素值都设置为0,让该区域变为黑色。

运行程序,结果如图2-11所示,其中图2-11(a)是读取的原始图像,图2-11(b)是经过修改后的图像。

图2-11 【例2.6】程序的运行结果

同时,在控制台会输出如下内容: