美文网首页计算机视觉
OpenCV(C++)操作像素总结

OpenCV(C++)操作像素总结

作者: 有苦向瓜诉说 | 来源:发表于2018-12-07 17:01 被阅读25次

OpenCV中提供了许多操作图像的函数,但是有时候我们需要直接操作像素来实现我们的功能,这篇文章总结了OpenCV中常见的操作像素的方法。

像素类型

不同的图像有不同的像素类型,不过对于不同的像素类型,需要在模板参数传入不同的值。首先像素的数据类型包括CV_32U,CV_32S,CV_32F,CV_8U,CV_8UC3等,那这些类型都是什么含义呢。第一个数字表示比特数,第二个数字就表示C++中数据类型,如果还有后面两个字符,这两个字符表示通道数。例如对于CV_32U,表示具有32比特的unsigned int类型;对于CV_8UC3,表示具有8比特,并且有三个通道的unsigned char类型。对于这个类型,可以使用type()来获取。

根据这些类型,又可以分为两种,一种单通道的,一种多通道的。单通道的一个像素用一个数值表示即可,而多通道的一个像素需要用多个像素表示,最常用的三通道就需要RGB这三个数值来表示。那具体的通道顺序是什么呢?在OpenCV中,则是按BGR的顺序来存储的,用数字代替就是B用channels[0]来获取,G用channels[1]来获取,R用channels[2]来获取。Opencv的设计者就是这样设计的,记住就好了。

访问像素

cv::Mat有个at()方法,可以访问图像的单个像素,同时at()方法又是一个模板方法,所以在使用的时候需要传入图像像素的类型,而且这个类型不像C++中的运算类型一样可以自动转换,所以必须准确的传入图像元素类型。

对于单通道元素来说,元素类型为unsigned char的情况下,可以这样访问

image.at<uchar>(j,i)= value;

对于三通道元素彩色图像来说,那么可以这样

image.at<cv::Vec3b>(j,i)[channel]= value;

或者直接使用数组赋值还更加方便

image.at<cv::Vec3b>(j,i) = cv::Vec3b(a,b,c);

Vec是opencv中的向量类型,它模板是Vec<T,N>,所以Vec3b表示3个unsigned char组成的向量,Vec2f表示由两个float组成的向量,任何形式的向量都可以用这个Vec来表示的。

Mat_ 也是一个模板类,注意它有一个下划线,以与Mat作为区别。在实际使用中,Mat_ 与 Mat 的操作函数没有多大区别,只不过Mat_需要在创建时定义元素类型,以后再调用它的方法是就不需要再传入数据的类型,而且还定义了一个操作符()来获取元素的位置。

cv::Mat_<uchar> image(image1);
image(20,30) = value;
或者使用
image.at(20,30) = value;

这两个类之间的区别就是一个是定义时指定类型,一个是使用时指定类型,可以按照不同的情况来使用。

使用指针遍历像素

cv::Mat还有个访问指针的方法 ptr(),它能够返回指定行的地址,然后就可以移动指针访其他的像素。

uchar *data = image.ptr<uchar>(j);

上面代码中data或获取第j行的首地址。遍历时,前三个字节表示的是第一个像素的BGR值,注意BGR值顺序,接下来三个字节是第二个像素的值。那像素个数有限,想要停止怎么办?可以先提前获取这一行中像素的个数,然后到空指针了就停止这轮访问,然后在换到其他行进行访问。

int n = image.cols * image.channels();

用图像的列数与通道数相乘就获得了图像的每行的像素数。

而对于图像,有时候在内存中会为了对齐而对末尾的像素有填充,而有时候没有填充。可以使用isContinue()来访问图像是否有填充,对于没有填充的图像,即连续的图像来说,便利的时候就可以只要一层循环就可以了,他会自己换行将图像变成一维的来处理。

create()方法的用处,这个方法先检查Mat对象是否已经分配了数据缓存区,以及缓存区的数据类型与需要的类型是否相等。如果相同则可以直接返回已分配好的缓存区,否则重新创建一个再返回。可以在需要另外单独保存图片时使用,判断传入的result image参数是否已经分配数据缓存区。

使用迭代器进行遍历

C++中的STL便设计了一套迭代器以用来访问元素,Opencv中也按照STL的设计原则设计了一套迭代器来访问像素,用法基本与STL类似。

对Mat类型来说,他的迭代器类型可以使用MatIterator_或者Mat_::Iterator类型,具体使用如下

cv::MatIterator_ <cv::Vec3b> it;
或者
cv::Mat_<cv::Vec3b>::iterator it;

用这两个迭代器便可以指定Mat对象的迭代器,注意需要传入模板参数。对迭代器的初始化与C++中的STL一致。

it = image.begin<cv::Vec3b>();
it = image.end<cv::Vec3b>();

遍历也和前面指针一样,从图像左上角第一个像素开始遍历三个字节,然后第二个字节,依次遍历,到第一行遍历完后,就会到第二行来遍历。不过我们也可以修改迭代器的位置,而不需要一个一个遍历。

//跳过20个像素
it += 20;   
//跳到下一行同一位置
it += image.cols;

有时候不希望迭代器修改像素的值,则可以使用常量迭代器,即有const属性的迭代器,如果在遍历过程中试图修改像素值则会报错。

cv::MatConstIterator_<cv::Vec3b> it;
或者
cv::Mat_<cv::Vec3b>::const_iterator it;

以上便是Mat的迭代器的使用方法,在模板参数里都需要传入像素类型,前面讲过Mat_对象只需要在定义时指定像素类型,此后使用便不需要在指定类型,对于它的迭代器也是如此,请注意他与Mat对象的区别。

cv::Mat_<uchar> image(image1);
cv::MatIterator_ <cv::Vec3b> it = image.begin();

访问图像像素的几种方法也介绍完了,考虑到程序的运行速度方面,通常at方法适合于访问元素,但不适合遍历元素;指针或者迭代器适合用于遍历元素。

欢迎大家关注公众号“计算机视觉与机器学习”


计算机视觉和机器学习

相关文章

  • OpenCV(C++)操作像素总结

    OpenCV中提供了许多操作图像的函数,但是有时候我们需要直接操作像素来实现我们的功能,这篇文章总结了OpenCV...

  • 004 图像像素的读写操作

    本节内容:图像像素操作:遍历与访问 C++ 在C++中访问OpenCV Mat对象每个像素点的像素值有两种方式: ...

  • 2019个人学习计划

    2019年努力... 1.OpenCV图像处理人脸识别滤波处理,基底层C++代码实现;微像素OpenCV图片处理-...

  • Opencv操作像素示例

    下面的代码对图像中的B分量进行了增强 原始图像: 增强后的图像:

  • openCV操作像素的方式

    前言 openCV操作像素的方式有十几种,但常用的也就三种,今天就讲解一下三种方式. 1.使用指针(像素数组): ...

  • opencv (C++)图像访问的两种方式

    简介:opencv c++里面访问像素数据的方法不是很直观,不像python里面直接img[i,j]就可以,在c+...

  • openCV 改变图像的对比度和亮度

    原理: 在opencv改变图像的对比度和亮度本质是对像素点的操作,一个像素映射到另一个像素,用数学表示就是f(x,...

  • opencv库函数

    1,像素操作 2,opencv数据结构 CV_8U 0 8 16 24CV_8S 1 9 ...

  • OpenCV2 像素基本操作

    先上代码。。。 1.读图片 第二个参数是类型 2.Mat_类型和Mat很像,在初始的时候指定了矩阵的元素的类型。M...

  • 微像素-一个图像处理源码分享网址

    微像素 OpenCV图片处理-OpenCV探索之路(四):膨胀、腐蚀、开闭运算 openCV之高斯滤波(及代码实现...

网友评论

    本文标题:OpenCV(C++)操作像素总结

    本文链接:https://www.haomeiwen.com/subject/vkgthqtx.html