测试环境:opencv3.1.0 + Visual Studio 2015 + win7 64位

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

1.      指针访问

2.      迭代器iterator

3.      动态地址计算

测试程序如下:

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

运行结果如下:

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组成的向量。这也解释了为什么存取彩色图像像素的代码可以写出如下形式

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)中是相反的。

参考文献

OpenCV3编程入门

OpenCV坐标系与操作像素的四种方法

Opencv中三种操作像素的方法相关推荐

  1. tomcat中三种部署项目的方法(转)

    tomcat中三种部署项目的方法 第一种方法:在tomcat中的conf目录中,在server.xml中的,<host/>节点中添加:  <Context path="/h ...

  2. QT中三种构建菜单栏的方法

    QT中三种构建菜单栏的方法 方法1 <C++ GUI programming with Qt 4, Second Edition>给出的一种方法:QMenum定义单个菜单,调用menuBa ...

  3. Android 中三种启用线程的方法

    多线程就是分时利用CPU,宏观上让所有线程一起执行 ,也叫并发 先调用start后调用run 1.start()方法来启动线程,真正实现了多线程运行. 这时无需等待run方法体代码执行完毕,可以直接继 ...

  4. Java Web开发Tomcat中三种部署项目的方法

    第一种方法:在tomcat中的conf目录中,在server.xml中的,<host/>节点中添加:  <Context path="/hello" docBas ...

  5. java swing 注册事件_比较Java Swing中三种注册事件的方法

    Swing 是目前Java中不可缺少的窗口工具组,是建立图形化用户界面(GUI)程序的强大工具.Java Swing组件自动产生各种事件来响应用户行为.Java将事件封装成事件类,并且为每个事件类定义 ...

  6. C++中三种产生随机数的方法

    第一种方法:使用时间做为生成随机数的种子 #include <iostream>using namespace std;// randomly generate 0 or 1 int ma ...

  7. tomcat中三种部署项目的方法

    第一种方法:在tomcat中的conf目录中,在server.xml中的,<host/>节点中添加:  <Context path="/hello" docBas ...

  8. java中三种转string的方法_java中int,char,string三种类型的相互转换

    如何将字串 String 转换成整数 int? int i = Integer.valueOf(my_str).intValue(); int i=Integer.parseInt(str); 如何将 ...

  9. 收藏夹导出至html,分享win7电脑中三种导出浏览器收藏夹地址方法

    使用win7电脑浏览器访问网站时为了更方便之后的访问用户都会讲有需要的网站收藏,但是有些用户在使用浏览器时并不习惯登陆账户就会导致收藏夹无法同步,之后电脑出现故障时或是浏览器出现问题收藏内容就会消失, ...

最新文章

  1. Hyperledger Fabric(术语表)
  2. linux ssh 隧道 tunnel 一般场景用法
  3. swift - xcode10 - 点击事件交互BUG - (手势和button的addTarget方法)
  4. java安全(二):JDBC|sql注入|预编译
  5. 索引更新:刚发布的文章就能被搜到,这是怎么做到的?
  6. 你知道这5年我怎么过的吗!谈谈我做测试开发的这些年……【总结】
  7. threading.Event
  8. 如何选择合适的大数据分析平台的类型
  9. 计算机网络第七版1-1
  10. nvidia driver 驱动重装教程
  11. 全网营销干货:物联网时代,为什么要关注线下大数据?
  12. Vieux-部分型号iPhone\iPad\iPod降级工具使用教程
  13. R语言缺失值判断与处理mice包-3
  14. 中国电信提前批(已offer)
  15. 大二文本分词过滤分类实验总结
  16. 网络爬虫——四种思维导图
  17. ABBYY FineReader OCR图文识别软件如何快速将纸质文档转为电子档教程
  18. BatchNorm和LayerNorm的区别
  19. 软件设计师考试(中级)考点
  20. 软交所助力国家级软件评测中心

热门文章

  1. boost::range_reverse_iterator相关的测试程序
  2. boost::mp11::mp_or相关用法的测试程序
  3. core::demangled_name的测试程序
  4. 基于Boost::beast模块的异步WebSocket服务器
  5. 基于Boost::beast模块的协程WebSocket 服务器
  6. VTK:图片之ImageDifference
  7. OpenCV EM clustering集群的实例(附完整代码)
  8. C语言实现pid算法(附完整源码)
  9. C语言实现数组Array(附完整源码)
  10. QT的QJSValue类的使用