在OpenCV-C++环境下,图像的存储容器是Mat对象,所以对图像像素的遍历,就是对Mat对象每一个数据元素的遍历。

关于Mat对象的详细介绍,可以参见博文 https://www.hhai.cc/thread-70-1-1.html

本文提供四种方式实现对OpenCV的Mat类矩阵元素的遍历。

以下四个代码通过对矩阵元素的遍历实现图像的反色操作。

四个代码中用到的图像的下载链接如下:

https://pan.baidu.com/s/1JEy2tiuwCKDi4n9TfuVyTA 提取码:201q

下面的四种方法的代码中会经常用到名字“Vec3b”,关于“Vec3b”的详细介绍,可参见下面这篇博文:
https://www.hhai.cc/thread-80-1-1.html

方法一:下标遍历法,格式为M.at<typename>(i,j)

这种方法实际上就是用Mat类的成员函数at()实现,
关于成员函数at()的详细介绍,
大家可参考博文 https://www.hhai.cc/thread-75-1-1.html (打开页面后搜索关键字“成员函数Mat:at()”)

这种方法是OpenCV-C++中对图像像素值访问和遍历最常用的方法。

这种方法的示例代码请参见下面这篇博文:

https://www.hhai.cc/thread-110-1-1.html

方法二:利用行指针遍历

//出处:昊虹AI笔记网(hhai.cc)
//用心记录计算机视觉和AI技术//博主微信/QQ 2487872782
//QQ群 271891601
//欢迎技术交流与咨询//OpenCV版本 OpenCV3.0#include <opencv2/opencv.hpp>
#include <iostream>using namespace std;
using namespace cv;cv::Mat inverseColor2(cv::Mat srcImage)
{cv::Mat tempImage = srcImage.clone();int row = tempImage.rows;// 由于图像是三通道图像,所以要作下面这样的处理int nStep = tempImage.cols * tempImage.channels();for (int i = 0; i < row; i++){// 取源图像的第i行指针const uchar* pSrcData = srcImage.ptr<uchar>(i);// 取目标图像的第i行指针uchar* pResultData = tempImage.ptr<uchar>(i);for (int j = 0; j < nStep; j++){pResultData[j] = cv::saturate_cast<uchar>(255 - pSrcData[j]);}}return tempImage;
}int main()
{// 装载图像cv::Mat srcImage = cv::imread("F:/material/images/P0028-flower-02.jpg");cv::Mat dstImage;if (!srcImage.data)return -1;cv::imshow("srcImage", srcImage);dstImage = srcImage.clone();dstImage = inverseColor2(srcImage);cv::imshow("dstImage", dstImage);cv::waitKey(0);return 0;
}

行指针遍历法的代码补充说明:
image.ptr<uchar>(i):取出图像中第i行数据的指针。
使用这种方法有一个前提:那就是图像每一行的数据在内存里是连续存储的,并且每个像素的三个通道数据按顺序存储。

方法三:利用数据的头指针直接按序遍历
这种方法的效率很高,但是要求不仅每一行的数据在内存里是连续存储的,行与行间也是连续的。
使用这种方法应先用Mat类的成员函数isContinuous()判断数据是否是连续存储的,满足此条件,才可使用该方法。
示例代码如下:

//出处:昊虹AI笔记网(hhai.cc)
//用心记录计算机视觉和AI技术//博主微信/QQ 2487872782
//QQ群 271891601
//欢迎技术交流与咨询//OpenCV版本 OpenCV3.0#include <opencv2/opencv.hpp>
#include <iostream>using namespace std;
using namespace cv;cv::Mat inverseColor3(cv::Mat srcImage)
{int row = srcImage.rows;int col = srcImage.cols;cv::Mat tempImage = srcImage.clone();// 判断是否是连续图像,即是否有像素填充if (srcImage.isContinuous() && tempImage.isContinuous()){row = 1;// 按照行展开col = col * srcImage.rows * srcImage.channels();}// 遍历图像的每个像素for (int i = 0; i < row; i++){// 设定图像数据源指针及输出图像数据指针const uchar* pSrcData = srcImage.ptr<uchar>(i);uchar* pResultData = tempImage.ptr<uchar>(i);for (int j = 0; j < col; j++){*pResultData++ = 255 - *pSrcData++;}}return tempImage;
}int main()
{// 装载图像cv::Mat srcImage = cv::imread("F:/material/images/P0028-flower-02.jpg");cv::Mat dstImage;if (!srcImage.data)return -1;cv::imshow("srcImage", srcImage);dstImage = srcImage.clone();dstImage = inverseColor3(srcImage);cv::imshow("dstImage", dstImage);cv::waitKey(0);return 0;
}

方法四:使用OpenCV的迭代器来遍历

OpenCV的迭代器使用很简单,大家看了大家的代码就知道怎么用了,这里就不多叙述了。

//出处:昊虹AI笔记网(hhai.cc)
//用心记录计算机视觉和AI技术//博主微信/QQ 2487872782
//QQ群 271891601
//欢迎技术交流与咨询//OpenCV版本 OpenCV3.0#include <opencv2/opencv.hpp>
#include <iostream>using namespace std;
using namespace cv;cv::Mat inverseColor4(cv::Mat srcImage)
{cv::Mat tempImage = srcImage.clone();// 初始化源图像迭代器cv::MatConstIterator_<cv::Vec3b> srcIterStart = srcImage.begin<cv::Vec3b>();cv::MatConstIterator_<cv::Vec3b> srcIterEnd = srcImage.end<cv::Vec3b>();// 初始化输出图像迭代器cv::MatIterator_<cv::Vec3b> resIterStart = tempImage.begin<cv::Vec3b>();cv::MatIterator_<cv::Vec3b> resIterEnd = tempImage.end<cv::Vec3b>();// 遍历图像反色处理while (srcIterStart != srcIterEnd){(*resIterStart)[0] = 255 - (*srcIterStart)[0];(*resIterStart)[1] = 255 - (*srcIterStart)[1];(*resIterStart)[2] = 255 - (*srcIterStart)[2];// 迭代器递增srcIterStart++;resIterStart++;}return tempImage;
}int main()
{// 装载图像cv::Mat srcImage = cv::imread("F:/material/images/P0028-flower-02.jpg");cv::Mat dstImage;if (!srcImage.data)return -1;cv::imshow("srcImage", srcImage);dstImage = srcImage.clone();dstImage = inverseColor4(srcImage);cv::imshow("dstImage", dstImage);cv::waitKey(0);return 0;
}

四种方法的运行结果都是一样的,如下:

用我在博文 https://www.hhai.cc/thread-111-1-1.html 中给出的C++代码段运行时间测量代码,可以测试出运行时间最短的是方法三(数据头指针法),其次依次是方法二(行指针法)、方法一(at法),用时最多的是方法四(迭代器法)。

延伸阅读:Python-OpenCV对图像的遍历操作示例代码

OpenCV-C++对图像像素的四种遍历操作相关推荐

  1. Opencv3编程入门学习笔记(三)之访问图像像素的三种方法

    访问图像像素的三种方法:指针访问,迭代器访问,动态地址访问.访问最快的为指针访问,以下算法在几毫秒,但指针访问容易造成内存泄漏:其次为迭代器访问:最后为动态地址访问. 以下程序是根据<OpenC ...

  2. 二叉树的四种遍历方式

    二叉树的四种遍历方式: 二叉树的遍历(traversing binary tree)是指从根结点出发,按照某种次序依次访问二叉树中所有的结点,使得每个结点被访问依次且仅被访问一次. 四种遍历方式分别为 ...

  3. 二叉树的存储结构及四种遍历(C语言)

    二叉树的存储结构: typedef struct TNode *Position; typedef Position BinTree; /* 二叉树类型 */ struct TNode{ /* 树结点 ...

  4. map的四种遍历方式

    Map四种遍历的代码示例 (1)数据准备 HashMap<String, String> map = new HashMap<String,String>(); map.put ...

  5. java中高效遍历list_Java中四种遍历List的方法总结(推荐)

    实例如下: package com.ietree.basic.collection.loop; import java.util.ArrayList; import java.util.Iterato ...

  6. 常用数据结构之二叉树及树的四种遍历方式

    1.树 我们选择一种数据结构,不仅要能存储数据,而且要能体现数据之间的关系.目前数据主要有是三种关系一对一.一对多.多对多:之前我们讨论了线性表(数组.链表.栈.队列),其中的元素具有一对一的关系,通 ...

  7. Java的四种遍历方式

    package API;import java.util.Iterator; import java.util.List; import java.util.ArrayList;public clas ...

  8. List集合四种遍历方式

    目录 一.List四种遍历方式 一.List四种遍历方式 public class Demo {public static void main(String[] args) {List<Stri ...

  9. java遍历list_Java中四种遍历List的方法总结(推荐)

    实例如下: package com.ietree.basic.collection.loop; import java.util.ArrayList; import java.util.Iterato ...

最新文章

  1. 题解 CF682C 【Alyona and the Tree】
  2. mysql 分表后排序_MySQL优化分库分表,为什么要分表,分表以后如何进行排序查询,业务如何设计?...
  3. 查看各类型数据库版本的SQL(Oracle/DB2/SQL Server/PG/MySQL)
  4. 卧式储罐液位体积计算公式excel_2020晋中化工防腐储罐订做欢迎来电-环保设备...
  5. 强悍的 Linux —— linux 中 bin 和 sbin 目录的主要区别
  6. 2021-08-15 reponse文件下载路径
  7. python垃圾回收机制与很多_你了解Python的 垃圾回收 机制吗?
  8. 18.Linux软件安装之Rpm安装
  9. oracle创建PDB数据库
  10. 常见测试概念-分级测试、灰度测试、AB测试
  11. win10目标文件夹访问被拒绝怎么办
  12. 黑之契约者OP《Howling》完整版歌词
  13. Linux命令调整显存,nVidia多显卡多GPU在Linux下的超频设置
  14. java编写GUI计算器
  15. 记录更换固态硬盘免重装系统和环境的操作
  16. 百度文库文件等待下载
  17. 嵌入式 BT656/BT601/BT1120协议差异小结
  18. 给新手学习MySQL的建议
  19. 如何在PDF里添加页码,添加页码的步骤
  20. Android传感器利用Senser实现不同的传感器

热门文章

  1. PIM-SM协议初探(三)SPT构建
  2. 二叉搜索树的最近公共祖先
  3. PIE-Engine 教程:水稻面积提取2—监督分类(宿迁市)
  4. SAP-SE37执行结果格数据导出EXCEL
  5. 硬核玩家的必备!vivo Z3才是实至名归的游戏机
  6. if、switch小练习1
  7. presto 0.166概述
  8. Makeblock召开2018新品发布会,正式启用中文品牌名童心制物
  9. HTML 网站优化三大标签(title ,description ,keywords)
  10. 你评论,我赠书~【哈士奇赠书 - 15期】〖HTML5+CSS3+JavaScript从入门到精通(微课精编版)(第2版)〗等你来拿