1. 存取像素值

在opencv中能够直接对cv::Mat类型的图像调用at函数读取或赋值某个像素,我们用个简单的案例来说明:
//在一张图像上增加椒盐噪声,image为输入图像。n为噪点个数
void salt(Mat &image, int n)
{for(int k = 0;k < n;k++){//随机产生白色噪点int i = qrand()%image.cols;int j = qrand()%image.rows;//假设是灰度图每一个像素的存取类型为uchar,即8bit整型数if(image.channels() == 1){     image.at<uchar>(j,i) = 255;}//彩色图像有三个通道,像素存取类型为cv::Vec3b,即由三个uchar组成的向量。这里用下标[i]訪问每一个通道else{image.at<Vec3b>(j,i)[0] = 255;image.at<Vec3b>(j,i)[1] = 255;image.at<Vec3b>(j,i)[2] = 255;}}
}

效果例如以下:

能够看到有非常多白色的噪声点,像雪花一样^_^
2. 指针遍历图像
我们用颜色缩减函数来说明用行首地址的方式遍历整个图像的像素。颜色缩减就是将每一个通道的颜色数减少,假设每一个通道的强度都是有unsigned char表示。那么就有256*256*256个颜色数目,假设将每一个通道的颜色数减少为原先的1/8,那个总颜色数就是32*32*32。大概就是这个意思。
//颜色缩减函数,image为输入图像。div为缩减的倍数
void colorReduce(Mat&image, int div = 64)
{int nl = image.rows; //图像的行数//图像每行的像素数int nc = image.cols * image.channels();for(int j =0;j<nl;j++){//得到第j行的首地址uchar* data = image.ptr<uchar>(j);//遍历每行的像素for(int i =0;i<nc;i++){data[i] = data[i]/div*div;    //将每一个像素值都变为div的倍数,即将颜色数缩减了div倍}}
}

效果例如以下:

当输入图像为连续的时候,即没有对图像行尾填补元素,这时就能够将整个图像看成是一个长为W*H的一维数组。即用第一行的行首指针就能遍历到整个图像的像素:
//颜色缩减函数。image为输入图像,div为缩减的倍数
void colorReduce(Mat&image, int div = 64)
{int nl = image.rows; //图像的行数//图像每行的像素数int nc = image.cols * image.channels();//假设图像连续if(image.isContinuous()){//reshape函数用于改变矩阵维度//图像行数为1,列数为原先的行数乘上列数image.reshape(1,image.cols*image.rows);}for(int j =0;j<nl;j++){//得到第j行的首地址uchar* data = image.ptr<uchar>(j);//遍历每行的像素for(int i =0;i<nc;i++){data[i] = data[i]/div*div;    //将每一个像素值都变为div的倍数,即将颜色数缩减了div倍}}
}

当然opencv还有更为底层的指针。在cv::Mat中。图像数据以unsigned char形式保存在一块内存中。

这块内存的首地址能够通过data成员变量得到。data是一个unsigned char型的指针,所以循环能够用下面方式:

    //获得图像指针uchar *data  = image.data;//获得第j行,第i列个像素值,step代表图像的行宽(包含填补像素)data = image.data + j*image.step + i*image.elemSize();

3. 迭代器遍历图像
事实上说到遍历。非常多人都会想到用迭代器来实现,迭代器是一种特殊的类。专门用来遍历集合中的各个元素,openCV相同为cv::Mat提供了与STL迭代器兼容的迭代器,以下我们还是用颜色缩减为例说明迭代器的使用:
//颜色缩减函数。image为输入图像。div为缩减的倍数
void colorReduce(Mat&image, int div = 64)
{//得到初始位置的迭代器Mat_<Vec3b>::iterator it = image.begin<Vec3b>();//得到终止位置的迭代器Mat_<Vec3b>::iterator itend = image.end<Vec3b>();//遍历全部像素for(; it != itend; ++it){(*it)[0] = (*it)[0]/div*div;(*it)[1] = (*it)[1]/div*div;(*it)[2] = (*it)[2]/div*div;}
}

效果与用指针遍历的一样。

4. 以上四种存取像素方式效率对照

opencv中能够用getTickCount()来測量一段代码的执行时间,此函数返回从上次开机算起的时钟周期数,getTickFrequency()能够得到每秒内的时钟周期数,有这两个函数就能得到随意一段代码的执行时间了。
我们还是以颜色衰减函数为例,分别用以上四种方法遍历实现。看看执行时间有何不同:
//at方法
void colorReduce1(Mat&image, int div = 64)
{int nl = image.rows; //图像的行数//图像每行的像素数int nc = image.cols * image.channels();for(int j =0;j<nl-2;j++){for(int i =0;i<nc-2;i++){image.at<Vec3b>(j,i)[0] = image.at<Vec3b>(j,i)[0]/div*div;image.at<Vec3b>(j,i)[1] = image.at<Vec3b>(j,i)[1]/div*div;image.at<Vec3b>(j,i)[2] = image.at<Vec3b>(j,i)[2]/div*div;}}
}//行首指针方法
void colorReduce2(Mat&image, int div = 64)
{int nl = image.rows; //图像的行数//图像每行的像素数int nc = image.cols * image.channels();for(int j =0;j<nl;j++){//得到第j行的首地址uchar* data = image.ptr<uchar>(j);//遍历每行的像素for(int i =0;i<nc;i++){data[i] = data[i]/div*div;    //将每一个像素值都变为div的倍数,即将颜色数缩减了div倍}}
}//一维数组
void colorReduce3(Mat&image, int div = 64)
{int nl = image.rows; //图像的行数//图像每行的像素数int nc = image.cols * image.channels();//假设图像连续if(image.isContinuous()){//reshape函数用于改变矩阵维度//图像行数为1,列数为原先的行数乘上列数image.reshape(1,image.cols*image.rows);}for(int j =0;j<nl;j++){//得到第j行的首地址uchar* data = image.ptr<uchar>(j);//遍历每行的像素for(int i =0;i<nc;i++){data[i] = data[i]/div*div;    //将每一个像素值都变为div的倍数,即将颜色数缩减了div倍}}
}//迭代器方法
void colorReduce4(Mat&image, int div = 64)
{//得到初始位置的迭代器Mat_<Vec3b>::iterator it = image.begin<Vec3b>();//得到终止位置的迭代器Mat_<Vec3b>::iterator itend = image.end<Vec3b>();//遍历全部像素for(; it != itend; ++it){(*it)[0] = (*it)[0]/div*div;(*it)[1] = (*it)[1]/div*div;(*it)[2] = (*it)[2]/div*div;}
}//測试4种像素遍历方式执行时间
void calrunTime(int v,Mat&image)
{double duration;duration = static_cast<double>(getTickCount());for(int i = 0;i<10;i++)   //执行十次取平均值{switch(v){case 1:colorReduce1(image);break;case 2:colorReduce2(image);break;case 3:colorReduce3(image);break;case 4:colorReduce4(image);break;default:break;}}duration = static_cast<double>(getTickCount()) - duration;duration /= getTickFrequency()/100;        //执行时间,以ms为单位qDebug()<<"duration"<<v<<":"<<duration<<"ms";
}

可见用at的方式读取像素效率最低,用迭代器速度也比較慢。效率最高的方式还是使用指针读取。
好了,本篇就到此结束吧。过两天继续更^_^
參考书籍
《openCV2计算机视觉编程手冊》

(转载请注明作者和出处:Shawn-HT  http://blog.csdn.net/shawn_ht 未经同意请勿用于商业用途)

【从零学习openCV】opecv操作像素相关推荐

  1. 快速系统从零学习OpenCV 4路线图

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 转眼间,小白学视觉就要成立三周年了,小白一直是很感谢小伙伴们的支持 ...

  2. 【从零学习openCV】IOS7下的人脸检測

    前言: 人脸检測与识别一直是计算机视觉领域一大热门研究方向,并且也从安全监控等工业级的应用扩展到了手机移动端的app,总之随着人脸识别技术获得突破,其应用前景和市场价值都是不可估量的,眼下在学习ope ...

  3. opencv4 c++ 提取图片中的白色区域_修正!【从零学习OpenCV 4】分割图像——分水岭法...

    点击上方"小白学视觉",选择"星标"公众号重磅干货,第一时间送达 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<OpenCV 4开 ...

  4. cv2.error: opencv(4.4.0)_【从零学习OpenCV 4】图像金字塔

    点击上方"小白学视觉",选择"星标"公众号 重磅干货,第一时间送达 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<从零学习Open ...

  5. 【从零学习openCV】IOS7下的人脸检测

    前言: 人脸检测与识别一直是计算机视觉领域一大热门研究方向,而且也从安全监控等工业级的应用扩展到了手机移动端的app,总之随着人脸识别技术获得突破,其应用前景和市场价值都是不可估量的,目前在学习ope ...

  6. 【从零学习openCV】IOS7根据人脸检测

    前言: 人脸检測与识别一直是计算机视觉领域一大热门研究方向,并且也从安全监控等工业级的应用扩展到了手机移动端的app.总之随着人脸识别技术获得突破,其应用前景和市场价值都是不可估量的,眼下在学习ope ...

  7. 【从零学习OpenCV 4】Mat类构造与赋值

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门 ...

  8. 【从零学习OpenCV 4】Mat类介绍

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门 ...

  9. 【从零学习OpenCV 4】了解OpenCV的模块架构

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门 ...

  10. 【从零学习OpenCV 4】Image Watch插件的使用

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门 ...

最新文章

  1. C#如何把List of Object转换成List of T具体类型
  2. 虚拟机安装Vmware-tools
  3. 【Java数据结构与算法】第十一章 顺序存储二叉树、线索二叉树和堆
  4. 自定义----损失函数与优化器
  5. Eclipse里面导工程的时候报错faceted project problem
  6. HTML5技术的调研以及贴吧应用总结
  7. 10 个最佳 GIS 软件应用程序
  8. linux7.6安装gcc,Centos7.6 安装gcc9
  9. 什么是App分发?有哪些分发平台可以选择?
  10. 安卓使用usb连接外设
  11. 中文文本分类 传统机器学习+深度学习
  12. HTML标签的基本使用:无序列表、有序列表、定义列表
  13. Android刘海屏适配
  14. vue项目整合UEditor看这一篇就够了
  15. 2011 Esri中国开发者大会
  16. 关于MongoDB使用的优化总结
  17. Firefox 3.5 在Windows下启动太慢的解决方法
  18. Electron教程-程序目录结构
  19. 电源管理芯片:nxp电源管理芯片的参考与设计
  20. 国内图书分类号、国际图书分类号、DOI查询

热门文章

  1. 【ARM】arm串行通信
  2. HDU 6052 To my boyfriend(容斥+单调栈)
  3. 7 种常用的排序算法直观感受
  4. shell 实现memcache缓存命中率监控脚本
  5. 【随想】_无关技术_你是合格的项目经理人吗?
  6. java动态代理(JDK和cglib)详解
  7. [转载]开源网管软件对比 - Nagios OpenNMS Zenoss
  8. sql 优化之:聚集索引的重要性和如何选择聚集索引(系列五)
  9. Docker 容器技术 — 安装
  10. SpringBoot 实战 (八) | 使用 Spring Data JPA 访问 Mysql 数据库