目录

1、指针访问像素

2、迭代器操作像素

3、动态地址计算


OpenCV中,有三种方式访问图像像素:

  1. 指针访问:C操作符[];
  2. 迭代器iterator
  3. 动态地址计算

上述方法在访问速度上略有差异。debug模式下,差异非常明显,在release模式下,差异就不太明显。

下边通过一组例子来说明这三种方法的使用,程序的作用是减少颜色的数量,比如原来的图像是256种颜色,我们希望将它变成64中颜色,只需要将原来的颜色除以4(整除)以后再乘以4即可。

主程序代码如下:

//---------------------------------【头文件、命名空间包含部分】--------------------------
//      描述:包含程序所使用的头文件和命名空间
//---------------------------------------------------------------------------------------
#include <opencv2/opencv.hpp>
#include <iostream>  using namespace std;
using namespace cv;//-----------------------------------【全局函数声明部分】-----------------------------------
//          描述:全局函数声明
//------------------------------------------------------------------------------------------
//减少颜色
void colorReduce(Mat& inputImage, Mat& outputImage, int div);//--------------------------------------【main( )函数】---------------------------------------
//          描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main()
{//【1】创建原始图并显示Mat srcImage = imread("1.jpg");imshow("原始图像", srcImage);//【2】按原始图的参数规格来创建创建效果图Mat dstImage;dstImage.create(srcImage.rows, srcImage.cols, srcImage.type());//效果图的大小、类型与原图片相同 //【3】记录起始时间double time0 = static_cast<double>(getTickCount());//【4】调用颜色空间缩减函数colorReduce(srcImage, dstImage, 32);//【5】计算运行时间并输出time0 = ((double)getTickCount() - time0) / getTickFrequency();cout << "\t此方法运行时间为: " << time0 << "秒" << endl;  //输出运行时间//【6】显示效果图imshow("效果图", dstImage);waitKey(0);
}

1、指针访问像素

指针访问像素利用的是C语言中的操作符[]。这种方法最快,但是略有点抽象。实验条件下单词运行时间为0.00370487秒,代码如下:

//---------------------------------【colorReduce( )函数】---------------------------------
//          描述:使用【指针访问:C操作符[ ]】方法版的颜色空间缩减函数
//----------------------------------------------------------------------------------------------
void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{//参数准备outputImage = inputImage.clone();  //拷贝实参到临时变量int rowNumber = outputImage.rows;  //行数int colNumber = outputImage.cols*outputImage.channels();  //列数 x 通道数=每一行元素的个数//双重循环,遍历所有的像素值for (int i = 0; i < rowNumber; i++)  //行循环{uchar* data = outputImage.ptr<uchar>(i);  //获取第i行的首地址for (int j = 0; j < colNumber; j++)   //列循环{// ---------【开始处理每个像素】-------------     data[j] = data[j] / div*div;// ----------【处理结束】---------------------}  //行处理结束}
}

分析讲解上述代码:

Mat类属性:

  • 公有变量cols和rows给出图像的宽和高
  • channels():返回图像的通道数。灰度图通道数为1,彩色通道数为3
  • ptr()函数:得到任意行的首地址。ptr是一个模板函数,它返回第i行的首地址:uchar* data = outputImage.ptr<uchar>(i);  //获取第i行的首地址

每行的像素值个数以下语句得到:

int colNumber = outputImage.cols*outputImage.channels();  //列数 x 通道数=每一行元素的个数

运行结果:

原始图

效果图


2、迭代器操作像素

迭代器需要做的仅仅是获得图像矩阵的begin和end,然后增加迭代直至从begin到end。将 * 操作符添加在迭代指针前,即可访问当前指向的内容。

相比使用指针可能越界问题,迭代器绝对是非常安全的方法。

//-------------------------------------【colorReduce( )函数】-----------------------------
//      描述:使用【迭代器】方法版的颜色空间缩减函数
//----------------------------------------------------------------------------------------------
void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{//参数准备outputImage = inputImage.clone();  //拷贝实参到临时变量//获取迭代器Mat_<Vec3b>::iterator it = outputImage.begin<Vec3b>();  //初始位置的迭代器Mat_<Vec3b>::iterator itend = outputImage.end<Vec3b>();  //终止位置的迭代器//存取彩色图像像素for (; it != itend; ++it){// ------------------------【开始处理每个像素】--------------------(*it)[0] = (*it)[0] / div*div;  //蓝色通道(*it)[1] = (*it)[1] / div*div;  //绿色通道(*it)[2] = (*it)[2] / div*div;  //红色通道// ------------------------【处理结束】----------------------------}
}

运行结果:

原始图

效果图


3、动态地址计算

动态地址运算配合at方法。这种方法简单明了,符合我们对像素的认识。

//----------------------------------【colorReduce( )函数】-------------------------------
//          描述:使用【动态地址运算配合at】方法版本的颜色空间缩减函数
//----------------------------------------------------------------------------------------------
void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{//参数准备outputImage = inputImage.clone();  //拷贝实参到临时变量int rowNumber = outputImage.rows;  //行数int colNumber = outputImage.cols;  //列数//存取彩色图像像素for (int i = 0; i < rowNumber; i++){for (int j = 0; j < colNumber; j++){// ------------------------【开始处理每个像素】--------------------outputImage.at<Vec3b>(i, j)[0] = outputImage.at<Vec3b>(i, j)[0] / div*div;  //蓝色通道outputImage.at<Vec3b>(i, j)[1] = outputImage.at<Vec3b>(i, j)[1] / div*div;  //绿色通道outputImage.at<Vec3b>(i, j)[2] = outputImage.at<Vec3b>(i, j)[2] / div*div;  //红是通道// -------------------------【处理结束】----------------------------}  // 行处理结束     }
}

分析讲解代码:

Mat:

  • 成员函数at(int y, int x):用来存储图像元素,但是必须在编译期知道图像的数据类型。需要注意的是,一定要确保指定的数据类型和矩阵中的数据类型符合,因为at方法本身不会对任何数据类型进行转换。

Vec3b:

  • 一个图像的Mat会返回一个由三个8位数组成的向量,,将其定义为Vec3b,即由三个unsigned char组成的向量,所以存取彩色图像像素的代码可以写出如下形式:
image.at<Vec3b>(i, j)[chanel] = value;  //索引值channel标明了颜色通道号

运行结果:

原始图

效果图

【OpenCV】OpenCV实战从入门到精通之 -- 指针访问、迭代器iterator、动态地址计算配合at元素相关推荐

  1. 【OpenCV】OpenCV实战从入门到精通之 -- 访问图像中的像素

    目录 1.图像在内存之中的存储方式 2.颜色空间缩减 3.LUT函数:Look up table操作 4.计时函数 5.访问图像中像素的三类方法 5.1.指针访问像素 5.2.迭代器操作像素 5.3. ...

  2. 【Python】Python实战从入门到精通之二 -- 教你使用Python中列表操作

    本文是Python实战–从入门到精通系列的第二篇文章: [Python]Python实战从入门到精通之一 – 教你深入理解Python中的变量和数据类型 Python实战从入门到精通之二 – 教你使用 ...

  3. c语言指针易错情况,C语言/C++从入门到精通之指针易错点总结

    指针是C语言的灵魂,所以学好指针很关键,本篇主要介绍了C语言/C++从入门到精通之指针易错点总结,通过具体的内容向大家展现,希望对大家C语言/C++的学习有所帮助. 学习C语言肯定会碰到指针,指针是C ...

  4. 颜色缩减 -利用指针、迭代器、动态地址实现访问像素

    为什么要使用颜色缩减 在对单通道图像进行处理时,像素的可能值为256个,但处理多通道时,像素的处理就会相当麻烦,其实用这些颜色中具有代表性的一小部分就可以达到同样的效果,所以颜色空间缩减就可以派上用场 ...

  5. 【OpenCV】OpenCV实战从入门到精通之 -- 显示创建Mat对象的七种方法

    目录 1.使用Mat()构造函数 2.C\C++中构造函数进行初始化 3.为已经存在的IplImage指针创建信息头 4.利用Create()函数 5.Matlab方式的初始化 6.对小矩阵使用逗号分 ...

  6. 【OpenCV】OpenCV实战从入门到精通之 -- 输入输出XML和YAML文件详解

    1.XML和YAML文件简介 XML文件是一种元标记语言,即开发者可以根据自身需要定义自己的标记.它是一种语义和结构语言,描述了文档的语义和结构. YAML以数据为中心,是一个可读性高,用来表达资料序 ...

  7. 【OpenCV】OpenCV实战从入门到精通之 -- 基本图像绘制

    目录 1.DrawEllipse()函数的写法 2.DrawFilledCircle()函数的写法 3.DrawPolygon()函数的写法 4.DrawLine()函数的写法 基本绘制图形代码: m ...

  8. 【OpenCV】OpenCV实战从入门到精通之 -- 常用数据结构和函数(Point、Scalar、Size、Rect、cvtColor)

    目录 1.点的表示:Point类 2.颜色的表示:Scalar类 3.尺寸的表示:Size类 4.矩形的表示:Rect类 5.颜色空间转换:cvtColor()函数 1.点的表示:Point类 Poi ...

  9. 【OpenCV】OpenCV实战从入门到精通之 -- 离散傅里叶变换相关函数详解

    目录 1.dft()函数 2.返回DFT最优尺寸大小:getOptimalDFTSize()函数 3.扩充图像边界:copyMakeBorder()函数 4.计算二维矢量的幅值:magnitude() ...

最新文章

  1. CentOS 6.3 64bit上测试ATS 5.3.0中的正则刷新插件regex_revalidate
  2. 小冰公司CEO李笛:强大的AI工具不应该给企业,应该给劳动者 | MEET2021
  3. linux命令之上传文件和下载文件
  4. QT的QTechnique类的使用
  5. 史上卖得最多的芯片......原来是这个!
  6. 【转载】浅谈React编程思想
  7. LeetCode MySQL 512. 游戏玩法分析 II
  8. 【转载】简直可爱极了的即时通讯
  9. N点虚拟主机管理系统安装图解
  10. poj2635 同余定理 + 素数筛法
  11. 图书管理系统-借书操作
  12. 网红必备神器,抖音短视频去水印秘籍-抖音-快手-微视-全名小视频
  13. 安卓 java hook 免root_[原创]利用VirtualApp实现免Root注入Hook(一)
  14. 关于maven仓库的配置步骤
  15. 河南大学计算机学院吴哲2008年,计算机与信息工程学院86级校友荣归母校
  16. 实战:HPA(Pod 水平自动伸缩)-2021.11.23
  17. 因为文件目录存在空格导致kafka运行错误:提示找不到或者无法加载主类错误
  18. mysql统计每半小时内的数据(查寻某段时间内的数据)
  19. TEACH_NLP——开篇
  20. 无法定位程序输入点 except_电脑定时程序

热门文章

  1. md5加密工具类_贼好用的 Java 工具类库! GitHub 星标 10k+,你在用吗?
  2. 我的世界末日求生系列服务器,末日生存 少年pi
  3. java中的集合_你真的了解Java中的集合类么?
  4. java为什么不能输入钢筋符号_input.nextDouble();找不到符号
  5. linux添加硬盘不重启(vmware下或者虚拟机下面)
  6. css如何调整红心样式_CSS3跳动的红心
  7. java buqi_Java 异常
  8. CSS3表达式calc( )
  9. 吴恩达机器学习课程笔记章节二单变量线性回归
  10. JS判断IE6/IE7/IE8系列的写法