一、访问像素值

利用Mat的at函数可以访问元素。因为Mat可以接受任何类型的元素,所以at函数被实现成一个模板函数,在调用时必须指定图像元素的类型:

image.at<uchar>(j,i)=0;
//或,对于彩色图像
image.at<cv::Vec3b>(j,i)[channel]=0;

channel索引用来指明三个通道的一个。因为彩色图像有3个通道,所以访问彩色图像的像素会返回一个向量。OpenCV定义这个短向量为cv::Vec3b,代表3个8位的数值。此外还有针对其它元素类型的向量,例如,浮点数类型cv::Vec3f。对于整型,最后的字母替换成i;对于短整型,替换成s;对于双精度,替换成d。

为了避免at函数冗长的感觉,可以使用cv::Mat的模板子类cv::Mat_,它可以直接通过operator()访问元素:

cv::Mat_<uchar> im(image);
im(1,1) = 0;
//或,对于彩色图像
cv::Mat_<cv::Vec3b> im(image);
im(1,1) [channel]= 0;

值得一提的是,at方法适合对像素点进行随机访问,当涉及像素的遍历时,考虑处理的性能,应该使用更高效的方法。

二、用指针遍历像素

int nl = image.rows;
int nc = image.cols*image.channels();
for (int j = 0; j < nl;j++) {uchar* pt = image.ptr<uchar>(j);for (int i = 0; i < nc; i++) {//对像素进行某些操作pt[i]=0;}}

如果弄清楚彩色图像中像素值数据的排列顺序,那么上述代码很容易理解。图像数据缓冲区的前3个字节表示左上角像素的三色通道,接下来的3个字节为第一行的第二个像素,依次类推。

对于连续图像,因为图像整个像素数据存储的地址是连续的,上述代码可改写为单个for循环:

uchar* pt = image.ptr<uchar>(0);
for (int i = 0; i < image.rows*image.cols*image.channels(); i++) {//对像素进行某些操作pt[i]=0;
}

这里要澄清一个概念,什么是连续图像?一个宽W高H的图像所需内存为W×H×3 uchar。然而出于性能的考虑,我们会用几个额外的像素来填补一行的长度,因为有些芯片处理图像时,若行的长度是4或8的整数倍,处理的性能就会更高。所以OpenCV Mat数据结构会有一个属性:step。直译就是步长,应该叫做有效宽度。当图像是连续图像时,即没有无效的数据填补行时,有效宽度等于实际的图像宽度。

检查图像的连续性,可以这样做:

//检查行的长度(字节数)与“列的个数×单个像素的字节数”是否相等
if(image.step==image.cols*image.elemSize()) {}

三、用迭代器遍历像素

cv::Mat_<uchar>::iterator it=image.begin<uchar>();
cv::Mat_<uchar>::iterator itend=image.end<uchar>();
for(;it!=itend;it++) {//对像素进行某些操作(*it)=0;
}

迭代器也可以这样定义:cv:MatIterator_<uchar> it;

使用迭代器的主要目的是简化代码,降低出错的可能性,测试显示,在时间效率上与指针操作的方式相比差一些。

四、邻域操作或块操作下的像素遍历

这里假设需要同时访问当前像素以及上下左右相邻的像素。

int nchannels=image.channels();
//处理除了首行和末行以外的所有行
for(int j=1;j<image.rows-1;j++) {uchar* previous=image.ptr<uchar>(j-1);//上一行uchar* current=image.ptr<uchar>(j);//当前行uchar* next=image.ptr<uchar>(j+1);//下一行//除去第一列和最后一列不处理for(int i=nchannels;i<(image.cols-1)*nchannels;i++) {current[i]=0;//当前像素current[i-nchannels]=0;//相邻左像素current[i+nchannels]=0;//相邻右像素previous[i]=0;//相邻上像素next[i]=0;//相邻下像素}
}

对像素邻域进行计算时,通常用一个核算子来表示。核算子的大小就是邻域大小(比如3×3),核算子每个单元格表示相关像素的乘法系数,像素应用核算子得到的结果,就是这些乘积的累加。核算子定义的运算叫做核运算(和卷积相似),这种操作叫做滤波。OpenCV里定义了相关的函数,即cv::filter2D。

五、操作像素值(滤波,混合等)

这里把两幅图像加权混合,可以使用cv::addWeighted函数:cv::addWeighted(image1,0.4,image2,0.7,0.,result);

下面就是两幅输入图像:

混合的结果为:

在OpenCV2中,大多数运算函数有对应的重载运算符。因此加权混合也可写为:result=0.4*image1+0.9*image2;

注意做加法的结果并不会使输出像素值超出255,因为函数调用了cv::saturate_cast函数。在对像素运算的场合都要使用这个函数,以确保结果在预定的像素范围之内。使用方法类似C++里的类型转换,比如results.at<uchar>(j,i)=cv::saturate_cast<uchar>(0.9*image1.at<uchar>(j,i)+0.9*image2.at<uchar>(j,i));

五、操作像素位置(重映射、变形等)

这类操作不会修改像素值,而是把每个像素的位置重新映射到新的位置。需要使用到OpenCV的remap函数。

//映射参数
cv::Mat srcX(image.rows,image.cols,CV_32F);
cv::Mat srcY(image.rows, image.cols, CV_32F);
//创建映射参数
for (int j = 0; j < image.rows;j++) {for (int i = 0; i < image.cols; i++) {srcX.at<float>(j, i) = i;//保持在同列srcY.at<float>(j, i) = j+7*sin(i/10.0);//保持在同列}
}
cv::Mat result;
cv::remap(image,result,srcX,srcY,cv::INTER_LINEAR);

为了构建新图像,需要知道新图像的每个像素在源图像中的原始位置。因此需要这样的映射函数,它能根据像素的新位置得到像素的原始位置,这个过程叫做反向映射。可以用两个映射参数来描述,在这里是srcX,srcY,一个针对x坐标,一个针对y坐标。值得注意的是参数包含的值为浮点数,即说明反向映射后的坐标可能并不为整数,这就需要使用像素插值技术,remap函数的最后的参数指明了使用的插值方法。

下面是一副输入图像:

运行程序的结果图像为:

OpenCV对像素的操作相关推荐

  1. OpenCv 如何对图像的像素进行操作

    对图像的像素进行操作,我们可以实现空间增强,反色等目的.让我们先来看一下内存空间中图像矩阵,也就是Mat的矩阵数值部分是怎么存储的: 如果图像是一幅灰度图像,他就像这样,从左到右,从上到下,依次是矩阵 ...

  2. OpenCV学习笔记(四十一)——再看基础数据结构core OpenCV学习笔记(四十二)——Mat数据操作之普通青年、文艺青年、暴力青年 OpenCV学习笔记(四十三)——存取像素值操作汇总co

    OpenCV学习笔记(四十一)--再看基础数据结构core 记得我在OpenCV学习笔记(四)--新版本的数据结构core里面讲过新版本的数据结构了,可是我再看这部分的时候,我发现我当时实在是看得太马 ...

  3. opencv学习记录——(5)图像像素的操作

    1.先补充几点opencv的相关知识点 1.1  通过Scalar来设置颜色 Scalar(b1, b2, b3, b4),前面的三个参数是依次设置BGR的,和RGB相反,第四个参数设置图片的透明度. ...

  4. Opencv开发笔记(一):操作图片像素

    在很多项目中我们会运用到对图形图像的像素处理,很文章我们来总结以下使用opencv对图片的像素进行操作从而达到自己想要的结果. 所谓的像素是图像的基本元素,从根本来说,一张图片就是由数值组成的矩阵,在 ...

  5. opencv简单的矩阵操作

    OpenCV的基本矩阵操作与示例 OpenCV中的矩阵操作非常重要,本文总结了矩阵的创建.初始化以及基本矩阵操作,给出了示例代码,主要内容包括: 创建与初始化 矩阵加减法 矩阵乘法 矩阵转置 矩阵求逆 ...

  6. opencv获取mat的指针_数字图像处理之opencv中Mat数据操作

    数字图像处理其实就是处理二维矩阵数据.利用opencv来学习处理算法是一种比较好的方式.学习opencv,主要就是调用其中的图像处理函数来实现各种操作.如果要得到想要的处理结果,还需要对图像处理算法有 ...

  7. OpenCV-图像像素遍历操作的三种方法对比(程序提速)

    作者:Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 场景需求 使用OpenCV,避免不了的就是对图像像素进行操作,遍历操作更是家常便饭,当图像数据不多时, ...

  8. 2、OpenCV图像的读写操作

    OpenCV图像的读写操作 概要 图像由像素组成. 像素可以被认为是非常小的正方形结构,当连接在一起时会生成图像. 它们是任何图像的最小组成部分. 如果您仔细查看前面的图像,您将能够在图像中看到一些正 ...

  9. 计算机视觉开源库OpenCV之利用开操作(Opening Operation)修复受损照片方法

    计算机视觉开源库OpenCV之利用开操作(Opening Operation)修复受损照片,开运算即为:先腐蚀再膨胀. 原图片,俄罗斯少女,挺漂亮的,但是照片上有白线.我们的任务就是去掉这些白线... ...

最新文章

  1. 怎么检测不到我的音频_检测不到硬盘怎么办?
  2. 小学计算机国培研修总结,小学数学国培研修总结
  3. 每天一道LeetCode-----计算小于n的素数个数
  4. IAAS: IT公司去IOE-Alibaba系统构架解读
  5. MySQL year()函数
  6. 层次聚类算法 算法_聚类算法简介
  7. 银河麒麟4安装MySQL8_银河麒麟4.0.2安装教程-电脑系统安装手册
  8. 粒子群优化算法(1)
  9. 激活golang编辑器
  10. 4万字的“整洁三部曲”干货,全浓缩在这一篇里了
  11. 2021字节秋招算法岗面经——抖音推荐
  12. 4.4.1 External and Internal Ratings
  13. html空格语言,HTML中如何键入空格
  14. win7设置自动关机
  15. igraph入门教程
  16. C++学习(三一七)ASCII码表
  17. linux常见桌面系统以及安装gnome远程桌面
  18. 微信公众号开发之加密解密
  19. Halcon 初体验
  20. 利用游程编码实现二值图像压缩

热门文章

  1. 投资30亿美元 IBM启动云计算大数据芯片研究计划
  2. Python+scrapy爬取36氪网
  3. 快速获取雪碧图的图标样式插件 - gulp-css-spriter教程
  4. 使用 Vanilla JavaScript 创建 Web 组件
  5. 小程序高级电商前端第2周深入理解REST API开发规范 开启三端分离编程之旅<二>----scroll-view组件的灵活应用、async和await问题探讨、spu-scroll自定义组件
  6. 计算机专业课程学习顺序
  7. 35、基于51单片机的金属探测器
  8. python十六进制排序_python十六进制
  9. 谈谈我用扫地机器人的心得
  10. cadence allegro导入dxf文件