opencv像素遍历

opencv中有3中方法可以访问/修改图像的像素值,分别为:

1.      指针访问

2.      迭代器iterator

3.      动态地址计算

 

测试程序如下:

[cpp]  view plain  copy
  1. #include "opencv2/opencv.hpp"  
  2. #include "iostream"  
  3.   
  4. using namespace std;  
  5. using namespace cv;  
  6.   
  7.   
  8. int main()  
  9. {  
  10.     //原始图像初始化  
  11.     Mat image(240, 320, CV_8UC3, Scalar(0, 0, 0));  
  12.     imshow("原始图像", image);  
  13.   
  14.       
  15.     //------------------指针操作-------------------------  
  16.     double start = static_cast<double>(getTickCount());  
  17.   
  18.     int rowNumber = image.rows;//行数  
  19.     int colNumber = image.cols * image.channels();//每一行元素个数 = 列数 x 通道数  
  20.     for (int i = 0; i < rowNumber; i++)//行循环  
  21.     {  
  22.         uchar* data = image.ptr<uchar>(i);//获取第i行的首地址  
  23.         for (int j = 0; j < colNumber; j++)//列循环  
  24.         {  
  25.             //开始处理  
  26.             data[j] = 255;  
  27.         }  
  28.     }  
  29.   
  30.     double end = static_cast<double>(getTickCount());  
  31.     double time = (end - start) / getTickFrequency();  
  32.     cout << "指针操作运行时间为:" << time << "秒" << endl;  
  33.     imshow("指针操作", image);  
  34.     //---------------------------------------------------  
  35.   
  36.     //-----------------迭代器操作------------------------  
  37.     start = static_cast<double>(getTickCount());  
  38.   
  39.     Mat_<Vec3b>::iterator it = image.begin<Vec3b>();//初始位置的迭代器  
  40.     Mat_<Vec3b>::iterator itend = image.end<Vec3b>();//终止位置的迭代器  
  41.     for (; it != itend; it++)  
  42.     {  
  43.         //处理BGR三个通道  
  44.         (*it)[0] = 255;//B  
  45.         (*it)[1] = 255;//G  
  46.         (*it)[2] = 0;//R  
  47.     }  
  48.   
  49.     end = static_cast<double>(getTickCount());  
  50.     time = (end - start) / getTickFrequency();//计算时间  
  51.     cout << "迭代器操作运行时间为:" << time << "秒" << endl;  
  52.     imshow("迭代器操作", image);  
  53.     //---------------------------------------------------  
  54.   
  55.     //----------------动态地址计算-----------------------  
  56.     start = static_cast<double>(getTickCount());  
  57.   
  58.     rowNumber = image.rows;  
  59.     colNumber = image.cols;  
  60.     for (int i = 0; i < rowNumber; i++)  
  61.         for (int j = 0; j < colNumber; j++)  
  62.         {  
  63.             //处理BGR三个通道  
  64.             image.at<Vec3b>(i, j)[0] = 0;//B  
  65.             image.at<Vec3b>(i, j)[1] = 255;//G  
  66.             image.at<Vec3b>(i, j)[2] = 0;//R  
  67.         }  
  68.   
  69.     end = static_cast<double>(getTickCount());  
  70.     time = (end - start) / getTickFrequency();//计算时间  
  71.     cout << "动态地址操作运行时间为:" << time << "秒" << endl;  
  72.     imshow("动态地址操作", image);  
  73.     //---------------------------------------------------  
  74.   
  75.     cvWaitKey(0);  
  76.     return 1;  
  77.   
  78. }  

运行结果如下:



Debug模式下运行时间如下:


Release模式下运行时间如下:



可以看到指针操作在Debug模式和Release模式下均是最快的,动态地址和迭代器操作稍微慢点。

 

一些说明:

1.      RGB颜色模型的矩阵如下(opencv中通道顺序为BGR):


因此,指针操作的时候,每行的元素个数为:列数x通道数。

Mat类提供了ptr函数可以得到图像任意行的首地址。

 

2.      在迭代法中,我们所需要做的仅仅是获得图像矩阵的begin和end,然后迭代从begin到end。将*操作符添加在迭代指针前,即可以访问当前指向的内容。相比于指针直接访问可能出现越界问题,迭代器绝对是非常安全的方法。

3.      成员函数at(int y, int x)可以用来存取图像元素,但是必须在编译期知道图像的数据类型。对于彩色图像,每个像素由三个部分构成:蓝色通道、绿色通道和红色通道(BGR)。因此,对于一个包含彩色图像的Mat,会返回一个由三个8位数组成的向量。Opencv将此类型的向量定义为Vec3b,即由三个unsigned char组成的向量。这也解释了为什么存取彩色图像像素的代码可以写出如下形式

[cpp]  view plain  copy
  1. image.at<Vec3b>(j, i)[channel] = value;  


另外:

而对于单通道的灰度图像就简单很多了:

image.at<uchar>(i,j); 

这里要注意at中(i,j)的顺序表示的是第i行第j列,跟Point(i,j)和Rect(i,j)中表示第j行第i列是相反的,如果把这个搞混了,很容易导致内存异常,还不容易发现错误。

 

补充说明一下:OpenCV中坐标体系中的零点坐标定义为图片的左上角,X轴为图像矩形的上面那条水平线,从左往右;Y轴为图像矩形左边的那条垂直线,从上往下。在Point(x,y)和Rect(x,y)中,第一个参数x代表的是元素所在图像的列数,第二个参数y代表的是元素所在图像的行数,而在at(x,y)中是相反的。








猜你喜欢

转载自blog.csdn.net/weixin_41484240/article/details/80163046