(转)OpenCV 访问Mat中每个像素的值
转自:http://blog.csdn.net/xiaowei_cqu/article/details/19839019
在《OpenCV 2 Computer Vision Application Programming Cookbook》看到的例子,非常不错,算是对之前的文章<访问Mat图像中每个像素的值>的回顾和补充。
Color Reduce
还是使用经典的Reduce Color的例子,即对图像中的像素表达进行量化。如常见的RGB24图像有256×256×256中颜色,通过Reduce Color将每个通道的像素减少8倍至256/8=32种,则图像只有32×32×32种颜色。假设量化减少的倍数是N,则代码实现时就是简单的value/N*N,通常我们会再加上N/2以得到相邻的N的倍数的中间值,最后图像被量化为(256/N)×(256/N)×(256/N)种颜色。
方法零:.ptr和[]操作符
Mat最直接的访问方法是通过.ptr<>函数得到一行的指针,并用[]操作符访问某一列的像素值。
- // using .ptr and []
- void colorReduce0(cv::Mat &image, int div=64) {
- int nr= image.rows; // number of rows
- int nc= image.cols * image.channels(); // total number of elements per line
- for (int j=0; j<nr; j++) {
- uchar* data= image.ptr<uchar>(j);
- for (int i=0; i<nc; i++) {
- data[i]= data[i]/div*div + div/2;
- }
- }
- }
方法一:.ptr和指针操作
除了[]操作符,我们可以移动指针*++的组合方法访问某一行中所有像素的值。
- // using .ptr and * ++
- void colorReduce1(cv::Mat &image, int div=64) {
- int nr= image.rows; // number of rows
- int nc= image.cols * image.channels(); // total number of elements per line
- for (int j=0; j<nr; j++) {
- uchar* data= image.ptr<uchar>(j);
- for (int i=0; i<nc; i++) {
- *data++= *data/div*div + div/2;
- } // end of row
- }
- }
方法二:.ptr、指针操作和取模运算
方法二和方法一的访问方式相同,不同的是color reduce用模运算代替整数除法
- // using .ptr and * ++ and modulo
- void colorReduce2(cv::Mat &image, int div=64) {
- int nr= image.rows; // number of rows
- int nc= image.cols * image.channels(); // total number of elements per line
- for (int j=0; j<nr; j++) {
- uchar* data= image.ptr<uchar>(j);
- for (int i=0; i<nc; i++) {
- int v= *data;
- *data++= v - v%div + div/2;
- } // end of row
- }
- }
方法三:.ptr、指针运算和位运算
由于进行量化的单元div通常是2的整次方,因此所有的乘法和除法都可以用位运算表示。
- // using .ptr and * ++ and bitwise
- void colorReduce3(cv::Mat &image, int div=64) {
- int nr= image.rows; // number of rows
- int nc= image.cols * image.channels(); // total number of elements per line
- int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
- // mask used to round the pixel value
- uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
- for (int j=0; j<nr; j++) {
- uchar* data= image.ptr<uchar>(j);
- for (int i=0; i<nc; i++) {
- *data++= *data&mask + div/2;
- } // end of row
- }
- }
方法四:指针运算
方法四和方法三量化处理的方法相同,不同的是用指针运算代替*++操作。
- // direct pointer arithmetic
- void colorReduce4(cv::Mat &image, int div=64) {
- int nr= image.rows; // number of rows
- int nc= image.cols * image.channels(); // total number of elements per line
- int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
- int step= image.step; // effective width
- // mask used to round the pixel value
- uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
- // get the pointer to the image buffer
- uchar *data= image.data;
- for (int j=0; j<nr; j++) {
- for (int i=0; i<nc; i++) {
- *(data+i)= *data&mask + div/2;
- } // end of row
- data+= step; // next line
- }
- }
方法五:.ptr、*++、位运算以及image.cols * image.channels()
这种方法就是没有计算nc,基本是个充数的方法。
- // using .ptr and * ++ and bitwise with image.cols * image.channels()
- void colorReduce5(cv::Mat &image, int div=64) {
- int nr= image.rows; // number of rows
- int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
- // mask used to round the pixel value
- uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
- for (int j=0; j<nr; j++) {
- uchar* data= image.ptr<uchar>(j);
- for (int i=0; i<image.cols * image.channels(); i++) {
- *data++= *data&mask + div/2;
- } // end of row
- }
- }
方法六:连续图像
Mat提供了isContinuous()函数用来查看Mat在内存中是不是连续存储,如果是则图片被存储在一行中。
- // using .ptr and * ++ and bitwise (continuous)
- void colorReduce6(cv::Mat &image, int div=64) {
- int nr= image.rows; // number of rows
- int nc= image.cols * image.channels(); // total number of elements per line
- if (image.isContinuous()) {
- // then no padded pixels
- nc= nc*nr;
- nr= 1; // it is now a 1D array
- }
- int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
- // mask used to round the pixel value
- uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
- for (int j=0; j<nr; j++) {
- uchar* data= image.ptr<uchar>(j);
- for (int i=0; i<nc; i++) {
- *data++= *data&mask + div/2;
- } // end of row
- }
- }
方法七:continuous+channels
与方法六基本相同,也是充数的。
- // using .ptr and * ++ and bitwise (continuous+channels)
- void colorReduce7(cv::Mat &image, int div=64) {
- int nr= image.rows; // number of rows
- int nc= image.cols ; // number of columns
- if (image.isContinuous()) {
- // then no padded pixels
- nc= nc*nr;
- nr= 1; // it is now a 1D array
- }
- int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
- // mask used to round the pixel value
- uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
- for (int j=0; j<nr; j++) {
- uchar* data= image.ptr<uchar>(j);
- for (int i=0; i<nc; i++) {
- *data++= *data&mask + div/2;
- *data++= *data&mask + div/2;
- *data++= *data&mask + div/2;
- } // end of row
- }
- }
方法八:Mat _iterator
真正有区别的方法来啦,用Mat提供的迭代器代替前面的[]操作符或指针,血统纯正的官方方法~
- // using Mat_ iterator
- void colorReduce8(cv::Mat &image, int div=64) {
- // get iterators
- cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>();
- cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>();
- for ( ; it!= itend; ++it) {
- (*it)[0]= (*it)[0]/div*div + div/2;
- (*it)[1]= (*it)[1]/div*div + div/2;
- (*it)[2]= (*it)[2]/div*div + div/2;
- }
- }
方法九:Mat_ iterator 和位运算
把方法八中的乘除法换成位运算。
- // using Mat_ iterator and bitwise
- void colorReduce9(cv::Mat &image, int div=64) {
- // div must be a power of 2
- int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
- // mask used to round the pixel value
- uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
- // get iterators
- cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>();
- cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>();
- for ( ; it!= itend; ++it) {
- (*it)[0]= (*it)[0]&mask + div/2;
- (*it)[1]= (*it)[1]&mask + div/2;
- (*it)[2]= (*it)[2]&mask + div/2;
- }
- }
方法十:MatIterator_
和方法八基本相同。
- // using MatIterator_
- void colorReduce10(cv::Mat &image, int div=64) {
- cv::Mat_<cv::Vec3b> cimage= image;
- cv::Mat_<cv::Vec3b>::iterator it=cimage.begin();
- cv::Mat_<cv::Vec3b>::iterator itend=cimage.end();
- for ( ; it!= itend; it++) {
- (*it)[0]= (*it)[0]/div*div + div/2;
- (*it)[1]= (*it)[1]/div*div + div/2;
- (*it)[2]= (*it)[2]/div*div + div/2;
- }
- }
方法十一:图像坐标
- // using (j,i)
- void colorReduce11(cv::Mat &image, int div=64) {
- int nr= image.rows; // number of rows
- int nc= image.cols; // number of columns
- for (int j=0; j<nr; j++) {
- for (int i=0; i<nc; i++) {
- image.at<cv::Vec3b>(j,i)[0]= image.at<cv::Vec3b>(j,i)[0]/div*div + div/2;
- image.at<cv::Vec3b>(j,i)[1]= image.at<cv::Vec3b>(j,i)[1]/div*div + div/2;
- image.at<cv::Vec3b>(j,i)[2]= image.at<cv::Vec3b>(j,i)[2]/div*div + div/2;
- } // end of row
- }
- }
方法十二:创建输出图像
之前的方法都是直接修改原图,方法十二新建了输出图像,主要用于后面的时间对比。
- // with input/ouput images
- void colorReduce12(const cv::Mat &image, // input image
- cv::Mat &result, // output image
- int div=64) {
- int nr= image.rows; // number of rows
- int nc= image.cols ; // number of columns
- // allocate output image if necessary
- result.create(image.rows,image.cols,image.type());
- // created images have no padded pixels
- nc= nc*nr;
- nr= 1; // it is now a 1D array
- int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
- // mask used to round the pixel value
- uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
- for (int j=0; j<nr; j++) {
- uchar* data= result.ptr<uchar>(j);
- const uchar* idata= image.ptr<uchar>(j);
- for (int i=0; i<nc; i++) {
- *data++= (*idata++)&mask + div/2;
- *data++= (*idata++)&mask + div/2;
- *data++= (*idata++)&mask + div/2;
- } // end of row
- }
- }
方法十三:重载操作符
Mat重载了+&等操作符,可以直接将两个Scalar(B,G,R)数据进行位运算和数学运算。
- // using overloaded operators
- void colorReduce13(cv::Mat &image, int div=64) {
- int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
- // mask used to round the pixel value
- uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
- // perform color reduction
- image=(image&cv::Scalar(mask,mask,mask))+cv::Scalar(div/2,div/2,div/2);
- }
时间对比
通过迭代二十次取平均时间,得到每种方法是运算时间如下。
可以看到,指针*++访问和位运算是最快的方法;而不断的计算image.cols*image.channles()花费了大量重复的时间;另外迭代器访问虽然安全,但性能远低于指针运算;通过图像坐标(j,i)访问时最慢的,使用重载操作符直接运算效率最高。
(转)OpenCV 访问Mat中每个像素的值的更多相关文章
- opencv-访问Mat中每个像素的值
参考:[OpenCV]访问Mat中每个像素的值(新) 膜拜大佬 以下例子代码均针对8位单通道灰度图. 1 .ptr和[]操作符 Mat最直接的访问方法是通过.ptr<>函数得到一行的指 ...
- 【OpenCV】访问图像中每个像素的值
http://blog.csdn.net/xiaowei_cqu/article/details/7557063
- OpenCV(2)-Mat数据结构及访问Mat中像素
Mat数据结构 一开始OpenCV是基于C语言的,在比较早的教材例如<学习OpenCV>中,讲解的存储图像的数据结构还是IplImage,这样需要手动管理内存.现在存储图像的基本数据结构是 ...
- 【opencv学习笔记七】访问图像中的像素与图像亮度对比度调整
今天我们来看一下如何访问图像的像素,以及如何改变图像的亮度与对比度. 在之前我们先来看一下图像矩阵数据的排列方式.我们以一个简单的矩阵来说明: 对单通道图像排列如下: 对于双通道图像排列如下: 那么对 ...
- 【opencv基础】OpenCV从Mat中提取某些行或列
这两个函数返回的是指向原矩阵内部位置的指针,类似于浅拷贝: code cv::Mat align_mean(cv::Mat mean, cv::Rect facebox, float scaling_ ...
- 访问图像中的像素[OpenCV 笔记16]
再更一发好久没更过的OpenCV,不过其实写到这个部分对计算机视觉算法有所了解的应该可以做到用什么查什么了,所以后面可能会更的慢一点吧,既然开了新坑,还是机器学习更有研究价值吧... 图像在内存中的存 ...
- nginx访问日志中添加接口返回值
因为nginx作为web服务器时,会代理后端的一些接口,这时访问日志中只能记录访问接口的status码,也就是说,只能获得200.404 这些的值 那么如何获得接口返回的response值呢? 下面开 ...
- 【OpenCV】访问Mat中的每个像素值
其中注意i,j的位置,写错了好几次.第二个for循环中的if语句用异或来判断图像中哪些像素点发生了改变.
- opencv 3 core组件进阶(1 访问图像中的像素)
访问图像像素的三类方法 ·方法一 指针访问:C操作符[ ]; ·方法二 迭代器iterator; ·方法三 动态地址计算. #include <opencv2/core/core.hpp> ...
随机推荐
- python基础----析构函数__del__
析构方法,当对象在内存中被释放时,自动触发执行. 注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构 ...
- input 拍照上传
<input id="up2" type="file" accept="image/*" capture="camera&q ...
- POJ--3461
原题链接:http://poj.org/problem?id=3461 分析:求一个串在另一个串中出现的次数,显然用KMP可以解决. #include<cstdio> #include&l ...
- Chiaki Sequence Revisited HDU - 6304 lowbit找规律法
Problem Description Chiaki is interested in an infinite sequence a1,a2,a3,..., which is defined as f ...
- Dell 戴尔预装Windows8改成Windows7
UEFI模式启动: 添加启动方式,正确路径为: 另外: Ubuntu启动gpt由gpt10变为gpt9 dd
- 详解 Cookie 和 Session 关系和区别
在技术面试中,经常被问到“说说Cookie和Session的区别”,大家都知道,Session是存储在服务器端的,Cookie是存储在客户端的,然而如果让你更详细地说明,你能说出几点?今天个推君就和大 ...
- rename table table1 to table2;
1. MYSQL rename table table1 to table2;
- duilib 增加gif控件(基于gdi+,可控制播放暂停,自动设置大小)
转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/42502081 因为项目需要我需要给duilib增加一个gif控件,目前已 ...
- 赤池信息量准则 ( Akaike information criterion)
sklearn实战-乳腺癌细胞数据挖掘(博主亲自录制视频) https://study.163.com/course/introduction.htm?courseId=1005269003& ...
- [吴恩达机器学习笔记]14降维3-4PCA算法原理
14.降维 觉得有用的话,欢迎一起讨论相互学习~Follow Me 14.3主成分分析原理Proncipal Component Analysis Problem Formulation 主成分分析( ...