因为OpenCV的版本一直在更新,2.2之前的版本(老方法)和2.2之后版本(新方法)访问图像像素的方法有所不同;2.2之前的更多的是用C来写的,2.2之后用了更多的C++;形式也向matlab靠拢;老的方法可以再新的版本下用,下面分别把两种访问方式的各种方法总结如下:
老方法
方法一:用IplImage结构体来访问图像像素,用结构体里的数据指针imageDate来访问像素(直接访问)
程序例子如下:
<span style="font-size:24px;">IplImage* img=cvLoadImage("D:\\matlabpic\\005.bmp",0);//第二个参数0是一通道,1(默认)是3通道
for (int i=0;i<img->height;i++) //直接访问
{
for (int j=0;j<img->width;j++)
{
((uchar *)(img->imageData+i*img->widthStep))[j]=255;
}
}</span>
这段程序作用非常简单,就是将载入的图像的每个像素都弄成白色,可以很清楚的看出是否真的访问到了每个像素点。
若是多通道,是每个像素的1、2、3、4通道,然后下一个像素,这样储存的。
还有一种写法是这样的
<span style="font-size:24px;">uchar* data=(uchar *)img->imageData;
int step = img->widthStep/sizeof(uchar);
for(int i=0;i<img->height;i++)
for(int j=0;j<img->width;j++)
data[i*step+j]=0;</span>
跟上边的那段程序没有本质区别,都是用到结构体IplImage中的数据指针imageDate,然后利用一维数组的方法访问。只是看着更清晰一些。
方法二:使用cvGet2D()函数和cvSet2D()函数访问(间接访问)
cvGet2D()函数获取像素值;返回值类型是CvScalar类型的结构体
程序例子:
<span style="font-size:24px;"> CvScalar s;
for(int y = 0; i < img->height; y++)
{
for(int x = 0; j < img->width; x++)
{ s = cvGet2D(img, i, j);
}
} </span>
s.val[0],s.val[1],s.val[2],s.val[3],输出不同通道的值,类型为double.
也可以这样写
<span style="font-size:24px;">double data;
for(int i=0;i<img->height;i++)
for(int j=0;j<img->width;j++)
data =cvGet2D(img,i,j).val[0]; </span>
cvSet2D同理
程序例子:
CvScalar s;
s.val[0]=0;
for(int i=0;i<img->height;i++)
for(int j=0;j<img->width;j++)
cvSet2D(img,i,j,s);
新方法
2.2之后引进了类Mat,跟MATLAB中的矩阵有点像,
两条虚线之间是转来的,原po主写的很好了,我也懒的画图了
—— —— —— ——
还是先看Mat的存储形式。Mat和Matlab里的数组格式有点像,但一般是二维向量,如果是灰度图,一般存放
<uchar>类型;如果是RGB彩色图,存放
<Vec3b>类型。
单通道灰度图数据存放格式:
多通道的图像中,每列并列存放通道数量的子列,如RGB三通道彩色图:
注意通道的顺序反转了:BGR。通常情况内存足够大的话图像的每一行是连续存放的,也就是在内存上图像的所有数据存放成一行,这中情况在访问时可以提供很大方便。可以用
isContinuous()函数来判断图像数组是否为连续的。
—— —— —— ——
访问方法如下:
方法一:
Mat类中的成员函数at
程序例子
单通道
Mat img=imread("D:\\matlabpic\\01.jpg"); //连函数名字都起的和MATLAB一样
<span style="white-space:pre"> </span>imshow("img",img);
for(int i=0;i<img.rows;i++)
for(int j=0;j<img.cols;j++)
img.at<uchar>(i,j)=0;
多通道
for(int i=0;i<img.rows;i++)
for(int j=0;j<img.cols;j++)
//img.at<uchar>(i,j)=0;
{
img.at<Vec3b>(i,j)[0]=10;
img.at<Vec3b>(i,j)[1]=20;
img.at<Vec3b>(i,j)[2]=50;
}
方法二
Mat类中的成员函数ptr
单通道
for(int i=0;i<img.rows;i++)
for(int j=0;j<img.cols* img.channels();j++)
img.ptr<uchar>(i)[j]=0;
多通道
for(int i=0;i<img.rows;i++)
for(int j=0;j<img.cols*img.channels();j++)
{img.ptr<uchar>(i)[j*img.channels()+0]=16;
img.ptr<uchar>(i)[j*img.channels()+1]=123;
img.ptr<uchar>(i)[j*img.channels()+2]=211;
}
还有一点要注意,OPenCV里面多通道是保存的顺序是BGR,刚好和MATLAB里面的RGB相反
找了资料,学习,整理,刚好一天,小疲惫,不过还是蛮开心的。