为了编写计算机视觉应用,你必须会存取图像的内容,如修改或者创建图像。本章将教会你如何操作图像的基本元素,即所谓的像素。从根本上来说,一张图像是一个有数值组成的矩阵。这也是OpenCV 2用 cv :: Mat 这个数据结构来表示图像的原因。矩阵的每一个元素代表一个像素。对于灰度图像(仅包含“灰色”的图像)而言,像素由8位无符号数来表示,其中0代表黑色,255代表白色。对于彩色而言,每个像素需要三个这样的8位无符号数来表示三个颜色通道(红、绿、蓝)。因此,再这中情况下,矩阵的元素是一个三元数。
我们通过一个简单的函数来演示如何直接存取像素值。该函数会在图像中加入椒盐噪点。椒盐噪点是一种特殊的噪点,顾名思义,它随机地件该部分像素设置为白色或者为黑色。在传输过程中,如果部分像素值丢失,那么这种噪点就会出现。在我们的例子中,我们随机挑选若干个像素,并将他设为白色。
实现方法
我们创建一个函数,它的第一个参数就是一张输入图像,该函数会修改此图片。为达到这个目的,我们需要使用传引用的参数传递方式。这个函数的第二个参数是我们欲将其替换成白色相数点个数:
void salt(Mat &image, int n){
for (int k = 0; k < n; k++)
{
int i = rand() % image.cols;
int j = rand() % image.rows;
if (image.channels() == 1)//灰度图
{
image.at<uchar>(j, i) = 225;
}
else if (image.channels() == 3)//彩色图
{
image.at<Vec3b>(j, i)[0] = 255;
image.at<Vec3b>(j, i)[1] = 255;
image.at<Vec3b>(j, i)[2] = 255;
}
}
}
你可以先打开一个图像,然后将在调用这个函数时候传递给它。
int main()
{
Mat image = imread("girl.jpg");
salt(image, 3000);
namedWindow("随机白点");
imshow("随机白点", image);
waitKey();
}
处理前图片:
处理后的图片
作用原理
类cv::Mat 有若干个成员函数可以获取图像的属性。公有成员变量cols和rows给出了图像的宽和高。成员函数at(int y,int x)用来存取图像的元素。但是必须在编译期知道图像的数据类型,因为cv::Mat可以存放任意数据累心的元素。这也是这个元素用模板函数来实现的原因。也就是意味着,当调用该函数时,你需要使用一下方式指定数据类型:
image.at<uchar>(j,i)=255;
对于彩色图像,每个像素有三部分构成:红色通道、绿色通道、蓝色通道。因此,一个包含彩色图像的cv::Mat 会返回一个由三个8位数组成的向量。OpenCV将此类向量定义为cv:: Vec3b ,即由三个unsigned char 组成的向量。这也解释了为什么存取彩色图像像素的代码可以写成以下形式:
image.at<cv::Vec3b>(j,i)[chanbel]=value;
其中,索引值channel表明了颜色通道号。
注意:一定要确保指定的数据类型要和矩阵中的数据类型相符合。at方法本身不会进行任何数据类型的装换。
类似地,OpenCV还有二元速向量类型和四元素类型(CV::Vec2b 和CV::Vec4b )。OpenCV同样拥有针对其他数据类型的向量类型,如s代表short,i代表int,f代表float,d代表double。所有的这些类型都是使用模板类cv::Vect<T,N>定义的,其中T代表类型,N代表元素个数。
扩展阅读
cv:: Mat_ ...
cv::Mat_<uchar> im2=image;//im2指向image
im2(50,100)=0;//存取第50行,100列