《计算机视觉算法:基于OpenCV的计算机应用开发》 —2.5.3 访问像素
2.5.3 访问像素
除了上一节中使用ROI访问图像中矩形区域中的像素的方法之外,还有许多别的方法可以实现同样的目的,甚至访问图像中单个像素。访问图像(也就是Mat对象)中单个像素,可以使用at函数,示例如下:
在上面的例子中,在使用at函数时,必须将TYPE替换为一个与图像的颜色通道数和深度相关的有效类型名。将R替换为我们想访问的像素行数,将C替换为列数。这与我们常见的像素访问方法稍有不同,常见方法的第一个参数是X(或横向坐标),第二个参数是Y(或纵向坐标)。因此,参数位置是反过来的。这里列举了些不同种类的Mat对象访问单个像素的例子。
访问一个8位整数元素的单通道(灰度图像)Mat对象中的像素:
访问一个浮点元素的单通道Mat对象中的像素:
访问一个8位整数元素的三通道Mat对象中的像素:
在上面的代码中,使用了Vec3b(3字节的向量)的数据类型。为了使用方便,OpenCV定义了这个以及多种其他类似的向量类型。这里给出了OpenCV在使用at函数或其他情况下Vec的数据格式:
<N>可以用2、3、4、6或8替代(为1时省略不写),它表示Mat对象中的通道数量。<Type>可以是下面的任意一种,表示存储在像素每个通道中的数据的类型:
b 表示 uchar(无符号字符)。
s 表示 short(短整型)。
w 表示ushort(无符号短整型)。
i 表示 int(整型)。
f 表示 float (浮点型)。
d 表示 double (双精浮点型)。
例如,Vec4b可以用来访问一个无符号字符型4通道Mat对象的像素,Vec6f可以用来访问浮点型6通道Mat对象的像素。特别要注意的是,Vec数据类型也可以认为是一个访问单独通道的数组。这里给出一个例子,说明如何访问无符号字符型元素的3通道Mat对象的第二个通道:
注意,这里的“访问”是指对像素及其通道的读取和写入。例如,下面的例子是使用sepia滤镜处理图像:
首先,这里有几点需要注意,图像的rows和cols成员表示图像中的行数(高度)和列数(宽度)。另外,要注意at函数是如何提取通道中的数据以及把处理后的数据写入通道中的。无须担心本例为得到正确的褐***调所采用的乘法系数,因为它们的值本身是由特定色调决定的,可以对单个像素进行任何种类的运算,来改变像素本身。
下面的图像显示了在三通道彩***像中应用上述代码的结果(左边是原始图像,右边是过滤后的图像):
另外一个访问图像中像素的方法是使用Mat类中的forEach函数。forEach函数可在所有像素上进行并行运算,替代逐个遍历访问的方法。下面是一个简单的例子,展示了forEach是如何把所有像素值都除以5,这将会得到一个比源图像更深的灰度图像:
在上面的代码中,第二个参数,也就是位置参数(因为是不需要的,所以这里省略),是指向像素位置的指针。
使用前面的for循环,我们需要编写下面的代码:
OpenCV也允许使用STL风格的迭代器访问或更改图像上的像素。这里是用STL风格迭代器写的同一个例子:
有意思的是,前面三个示例中相同的运算也可以通过下面的简单语句来完成:
这是因为OpenCV中的Mat对象把这个语句视为元素级的除法运算,我们将在接下来的章节中了解更多相关内容。下图显示了在灰度图像上应用的结果(左边是原图,右边为更改后的图):
显然,forEach、C++的for循环以及STL风格的迭代器都能实现在Mat对象中访问和改变像素的目的。我们在本节讨论的Mat类的函数和成员足以应对后续学习,但请务必快速探索下Mat类提供的巨量图像处理功能和它们的基础特性。
- 点赞
- 收藏
- 关注作者
评论(0)