作者:咕唧咕唧liukun321
来自:http://blog.csdn.net/liukun321
本质上说一张图像就是由数值组成的矩阵。Opencv 2.x由 cv::Mat 这个数据结构来表示一张图像。矩阵的每一个元素代表了一个像素。对于彩色图像而言矩阵的元素是一个三元数。对图像有了这个新的认识,下面可以试着借助opencv处理图像了。
先来看一下今天要处理的图像:今天的主题是存取像素,首先来看一下如何存取像素值。其实对于像素值的操作都可以由cv::Mat类中成员直接或间接实现,cv::Mat有若干成员函数可以获取图像的数据及属性。
操作单个像素方法:
at(int y, int x)
cv::mat的成员函数: at(int y, int x)可以用来存取图像中对应坐标为(x,y)的元素坐标。但是在使用它时要注意,在编译期必须要已知图像的数据类型,这是因为cv::mat可以存放任意数据类型的元素。因此at方法的实现是用模板函数来实现的。
使用方法:假设提前已知一幅图像img的数据类型为 unsigned char型灰度图(单通道),要对坐标为(10,12)的像素重新赋值为128,则对应操作如下:
img.at(12,10) = 128;
如果要操作的图片img是一幅数据类型同样为unsigned char的彩色图片,再次要求将坐标(10,12)的像素赋值为128。这个操作跟上面的就有点区别了,需要对这个像素三个通道的每个对应元素赋值,Opencv中图像三原色在内存中的排列顺序为B-G-R(见下面注释),操作过程如下:
img.at(12,10) [0]= 128;//B
img.at< cv::Vec3b >(12,10) [1]= 128;//G
img.at< cv::Vec3b >(12,10) [2]= 128;//R
了解了at方法的用法,下面就尝试一下使用at方法对刚才的图片做一个简单的处理(将图像中加入椒盐噪点)。椒盐噪点是一种特殊的噪点,是随机的将图像的部分像素设置为黑色或白色。
既然灰度图与彩色图像对单个元素的操作方式不同,这就需要有一个图像类型判断的过程。
cv::Mat image = cv::imread("test.jpg");
if(image.channles() == 1)
{
//灰度图
}else{
//彩色图
}
#include
#include
using namespace cv;
void salt(Mat &img,int saltNum)
{
int x,y;
int i ;
for(i = 0;i < saltNum; i++)
{
x = rand()%img.cols;
y = rand()%img.rows;
if(img.channels() == 1)
{
img.at(y,x) = 255;
}else if(img.channels() == 3)
{
img.at(y,x)[0] = 255;
img.at(y,x)[1] = 255;
img.at(y,x)[2] = 255;
}
}
}
int main()
{
Mat image = imread("../test.jpg");
Mat result;
result = image.clone();
salt(result,3000);
namedWindow("src(http://blog.csdn.net/liukun321)" , CV_WINDOW_AUTOSIZE);
imshow("src(http://blog.csdn.net/liukun321)", image);
imshow("dst(http://blog.csdn.net/liukun321)", result);
waitKey();
return 0;
}
程序运行后的效果图:
原图
加入椒盐噪声后效果
其实除了at方法操作像素,还可以使用opencv提供的类cv::Mat_ 来实现。cv::Mat_是一个模板子类。这个类定义了很多额外的方法,但是没有提供公共的成员变量。如果已知了矩阵的类型,使用cv::Mat_会带来很多便利。它的使用方法如下:
cv::Mat_ img = imread("test.jpg");
img(10,12) = 128;//10行 12列
还有一种操作像素的方法:使用Mat类的ptr()方法配合cols 、rows、step、elemSize等成员变量,直接进行指针操作。下面先来说说这几个成员变量
cols代表图像的列数
rows代表图像的高度
step 代表以字节为单位的图像宽度
elemSize 代表像素的大小 (比如一个三通道uchar 型矩阵,返回值为3)
prt()方法同样是个模板类,需要编译期已知像素点的类型:
cv::Mat_ img = imread("test.jpg");
uchar* addr = img.ptr(10);//返回10行的地址
addr +=12;//单通道灰度图
*addr = 128;
同样完成了对第10行第12列像素的操作。若图象为三通道彩色图:
cv::Mat_ img = imread("test.jpg");
uchar* addr = img.ptr(10);//返回10行的地址
addr +=12* img.elemSize;//单通道灰度图
*addr = 128;
addr +=12* img.elemSize是因为彩色图象在内存中的存储方式:图像缓冲区中的前三个字节对应图像左上角第一个像素的三个通道值,接下来的三个字节对应第一行的第二个像素,以此类推。而且注意Opencv默认是使用BGR的通道顺序。
到此已经介绍了3中操作图像中像素的方法。除这三种以外还有一种使用迭代器的操作。今天就不再介绍了。