【OpenCV】访问Mat中每个像素的值(新)(III)

在《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<>函数得到一行的指针,并用[]操作符访问某一列的像素值。

[cpp] view
plain
copy

  1. // using .ptr and []  
  2. void colorReduce0(cv::Mat &image, int div=64) {  
  3.       int nr= image.rows; // number of rows  
  4.       int nc= image.cols * image.channels(); // total number of elements per line  
  5.       for (int j=0; j<nr; j++) {  
  6.           uchar* data= image.ptr<uchar>(j);  
  7.           for (int i=0; i<nc; i++) {  
  8.                   data[i]= data[i]/div*div + div/2;  
  9.             }                    
  10.       }  
  11. }  

方法一:.ptr和指针操作

除了[]操作符,我们可以移动指针*++的组合方法访问某一行中所有像素的值。

[cpp] view
plain
copy

  1. // using .ptr and * ++   
  2. void colorReduce1(cv::Mat &image, int div=64) {  
  3.       int nr= image.rows; // number of rows  
  4.       int nc= image.cols * image.channels(); // total number of elements per line  
  5.       for (int j=0; j<nr; j++) {  
  6.           uchar* data= image.ptr<uchar>(j);  
  7.           for (int i=0; i<nc; i++) {  
  8.                  *data++= *data/div*div + div/2;  
  9.             } // end of row                   
  10.       }  
  11. }  

方法二:.ptr、指针操作和取模运算

方法二和方法一的访问方式相同,不同的是color reduce用模运算代替整数除法

[cpp] view
plain
copy

  1. // using .ptr and * ++ and modulo  
  2. void colorReduce2(cv::Mat &image, int div=64) {  
  3.       int nr= image.rows; // number of rows  
  4.       int nc= image.cols * image.channels(); // total number of elements per line  
  5.       for (int j=0; j<nr; j++) {  
  6.           uchar* data= image.ptr<uchar>(j);  
  7.           for (int i=0; i<nc; i++) {  
  8.                   int v= *data;  
  9.                   *data++= v - v%div + div/2;  
  10.             } // end of row                   
  11.       }  
  12. }  

方法三:.ptr、指针运算和位运算

由于进行量化的单元div通常是2的整次方,因此所有的乘法和除法都可以用位运算表示。

[cpp] view
plain
copy

  1. // using .ptr and * ++ and bitwise  
  2. void colorReduce3(cv::Mat &image, int div=64) {  
  3.       int nr= image.rows; // number of rows  
  4.       int nc= image.cols * image.channels(); // total number of elements per line  
  5.       int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));  
  6.       // mask used to round the pixel value  
  7.       uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0  
  8.       for (int j=0; j<nr; j++) {  
  9.           uchar* data= image.ptr<uchar>(j);  
  10.           for (int i=0; i<nc; i++) {  
  11.             *data++= *data&mask + div/2;  
  12.             } // end of row                   
  13.       }  
  14. }  

方法四:指针运算

方法四和方法三量化处理的方法相同,不同的是用指针运算代替*++操作。

[cpp] view
plain
copy

  1. // direct pointer arithmetic  
  2. void colorReduce4(cv::Mat &image, int div=64) {  
  3.       int nr= image.rows; // number of rows  
  4.       int nc= image.cols * image.channels(); // total number of elements per line  
  5.       int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));  
  6.       int step= image.step; // effective width  
  7.       // mask used to round the pixel value  
  8.       uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0  
  9.       // get the pointer to the image buffer  
  10.       uchar *data= image.data;  
  11.       for (int j=0; j<nr; j++) {  
  12.           for (int i=0; i<nc; i++) {  
  13.             *(data+i)= *data&mask + div/2;  
  14.             } // end of row                   
  15.             data+= step;  // next line  
  16.       }  
  17. }  

方法五:.ptr、*++、位运算以及image.cols * image.channels()

这种方法就是没有计算nc,基本是个充数的方法。

[cpp] view
plain
copy

  1. // using .ptr and * ++ and bitwise with image.cols * image.channels()  
  2. void colorReduce5(cv::Mat &image, int div=64) {  
  3.       int nr= image.rows; // number of rows  
  4.       int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));  
  5.       // mask used to round the pixel value  
  6.       uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0  
  7.       for (int j=0; j<nr; j++) {  
  8.           uchar* data= image.ptr<uchar>(j);  
  9.           for (int i=0; i<image.cols * image.channels(); i++) {  
  10.             *data++= *data&mask + div/2;  
  11.             } // end of row                   
  12.       }  
  13. }  

 

方法六:连续图像

Mat提供了isContinuous()函数用来查看Mat在内存中是不是连续存储,如果是则图片被存储在一行中。

[cpp] view
plain
copy

  1. // using .ptr and * ++ and bitwise (continuous)  
  2. void colorReduce6(cv::Mat &image, int div=64) {  
  3.       int nr= image.rows; // number of rows  
  4.       int nc= image.cols * image.channels(); // total number of elements per line  
  5.       if (image.isContinuous())  {  
  6.           // then no padded pixels  
  7.           nc= nc*nr;   
  8.           nr= 1;  // it is now a 1D array  
  9.        }  
  10.       int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));  
  11.       // mask used to round the pixel value  
  12.       uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0  
  13.       for (int j=0; j<nr; j++) {  
  14.           uchar* data= image.ptr<uchar>(j);  
  15.           for (int i=0; i<nc; i++) {  
  16.             *data++= *data&mask + div/2;  
  17.             } // end of row                   
  18.       }  
  19. }  

方法七:continuous+channels

与方法六基本相同,也是充数的。

[cpp] view
plain
copy

  1. // using .ptr and * ++ and bitwise (continuous+channels)  
  2. void colorReduce7(cv::Mat &image, int div=64) {  
  3.       int nr= image.rows; // number of rows  
  4.       int nc= image.cols ; // number of columns  
  5.       if (image.isContinuous())  {  
  6.           // then no padded pixels  
  7.           nc= nc*nr;   
  8.           nr= 1;  // it is now a 1D array  
  9.        }  
  10.       int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));  
  11.       // mask used to round the pixel value  
  12.       uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0  
  13.       for (int j=0; j<nr; j++) {  
  14.           uchar* data= image.ptr<uchar>(j);  
  15.           for (int i=0; i<nc; i++) {  
  16.             *data++= *data&mask + div/2;  
  17.             *data++= *data&mask + div/2;  
  18.             *data++= *data&mask + div/2;  
  19.             } // end of row                   
  20.       }  
  21. }  

方法八:Mat _iterator

真正有区别的方法来啦,用Mat提供的迭代器代替前面的[]操作符或指针,血统纯正的官方方法~

[cpp] view
plain
copy

  1. // using Mat_ iterator   
  2. void colorReduce8(cv::Mat &image, int div=64) {  
  3.       // get iterators  
  4.       cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>();  
  5.       cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>();  
  6.       for ( ; it!= itend; ++it) {  
  7.         (*it)[0]= (*it)[0]/div*div + div/2;  
  8.         (*it)[1]= (*it)[1]/div*div + div/2;  
  9.         (*it)[2]= (*it)[2]/div*div + div/2;  
  10.       }  
  11. }  

 

方法九:Mat_ iterator 和位运算

把方法八中的乘除法换成位运算。

[cpp] view
plain
copy

  1. // using Mat_ iterator and bitwise  
  2. void colorReduce9(cv::Mat &image, int div=64) {  
  3.       // div must be a power of 2  
  4.       int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));  
  5.       // mask used to round the pixel value  
  6.       uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0  
  7.       // get iterators  
  8.       cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>();  
  9.       cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>();  
  10.       for ( ; it!= itend; ++it) {  
  11.         (*it)[0]= (*it)[0]&mask + div/2;  
  12.         (*it)[1]= (*it)[1]&mask + div/2;  
  13.         (*it)[2]= (*it)[2]&mask + div/2;  
  14.       }  
  15. }  

方法十:MatIterator_

和方法八基本相同。

[cpp] view
plain
copy

  1. // using MatIterator_   
  2. void colorReduce10(cv::Mat &image, int div=64) {  
  3.       cv::Mat_<cv::Vec3b> cimage= image;  
  4.       cv::Mat_<cv::Vec3b>::iterator it=cimage.begin();  
  5.       cv::Mat_<cv::Vec3b>::iterator itend=cimage.end();  
  6.       for ( ; it!= itend; it++) {   
  7.         (*it)[0]= (*it)[0]/div*div + div/2;  
  8.         (*it)[1]= (*it)[1]/div*div + div/2;  
  9.         (*it)[2]= (*it)[2]/div*div + div/2;  
  10.       }  
  11. }  

 

方法十一:图像坐标

[cpp] view
plain
copy

  1. // using (j,i)  
  2. void colorReduce11(cv::Mat &image, int div=64) {  
  3.       int nr= image.rows; // number of rows  
  4.       int nc= image.cols; // number of columns  
  5.       for (int j=0; j<nr; j++) {  
  6.           for (int i=0; i<nc; i++) {  
  7.                   image.at<cv::Vec3b>(j,i)[0]=     image.at<cv::Vec3b>(j,i)[0]/div*div + div/2;  
  8.                   image.at<cv::Vec3b>(j,i)[1]=     image.at<cv::Vec3b>(j,i)[1]/div*div + div/2;  
  9.                   image.at<cv::Vec3b>(j,i)[2]=     image.at<cv::Vec3b>(j,i)[2]/div*div + div/2;  
  10.             } // end of row                   
  11.       }  
  12. }  

方法十二:创建输出图像

之前的方法都是直接修改原图,方法十二新建了输出图像,主要用于后面的时间对比。

[cpp] view
plain
copy

  1. // with input/ouput images  
  2. void colorReduce12(const cv::Mat &image, // input image   
  3.                  cv::Mat &result,      // output image  
  4.                  int div=64) {  
  5.       int nr= image.rows; // number of rows  
  6.       int nc= image.cols ; // number of columns  
  7.       // allocate output image if necessary  
  8.       result.create(image.rows,image.cols,image.type());  
  9.       // created images have no padded pixels  
  10.       nc= nc*nr;   
  11.       nr= 1;  // it is now a 1D array  
  12.       int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));  
  13.       // mask used to round the pixel value  
  14.       uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0  
  15.       for (int j=0; j<nr; j++) {  
  16.           uchar* data= result.ptr<uchar>(j);  
  17.           const uchar* idata= image.ptr<uchar>(j);  
  18.           for (int i=0; i<nc; i++) {  
  19.             *data++= (*idata++)&mask + div/2;  
  20.             *data++= (*idata++)&mask + div/2;  
  21.             *data++= (*idata++)&mask + div/2;  
  22.           } // end of row                   
  23.       }  
  24. }  

方法十三:重载操作符

Mat重载了+&等操作符,可以直接将两个Scalar(B,G,R)数据进行位运算和数学运算。

[cpp] view
plain
copy

  1. // using overloaded operators  
  2. void colorReduce13(cv::Mat &image, int div=64) {  
  3.       int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));  
  4.       // mask used to round the pixel value  
  5.       uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0  
  6.       // perform color reduction  
  7.       image=(image&cv::Scalar(mask,mask,mask))+cv::Scalar(div/2,div/2,div/2);  
  8. }  

时间对比

通过迭代二十次取平均时间,得到每种方法是运算时间如下。

可以看到,指针*++访问和位运算是最快的方法;而不断的计算image.cols*image.channles()花费了大量重复的时间;另外迭代器访问虽然安全,但性能远低于指针运算;通过图像坐标(j,i)访问时最慢的,使用重载操作符直接运算效率最高。

(转载请注明作者和出处:http://blog.csdn.net/xiaowei_cqu 未经允许请勿用于商业用途)

【OpenCV】访问Mat中每个像素的值(新)

时间: 2024-08-13 16:45:35

【OpenCV】访问Mat中每个像素的值(新)(III)的相关文章

【OpenCV】访问图像中每个像素的值 (I)

最近要做的东西要对每个像素值进行处理,所以上网搜... 居然发现搜出来的好文章都是一个人写的,而且还是一个妹子..于是收藏之...按时间顺序发! 转载请注明出处:http://blog.csdn.net/xiaowei_cqu/article/details/7557063 !!此篇是基于IplImage* (C接口或者说2.1之前版本的接口,新的Mat的访问方式请参考博文: <访问Mat图像中每个像素的值>) IplImage是OpenCV中CxCore部分基础的数据结构,用来表示图像,其中

【OpenCV】访问Mat图像中每个像素的值 (II)

今天百度搜资料还搜到了自己的...<访问图像中每个像素的值>,这是之前写的了,用的也是2.0的风格IplImage*格式,不太适用后来Mat的格式,特此重写一篇. 以下例子源自<The OpenCV Tutorials --Release 2.4.2>2.2 How to scan images, lookup tables and time measurement with OpenCV 图像容器Mat 还是先看Mat的存储形式.Mat和Matlab里的数组格式有点像,但一般是二

ASP.NET中访问DataGrid中所有控件值的方法_实用技巧

本文实例讲述了ASP.NET中访问DataGrid中所有控件值的方法.分享给大家供大家参考,具体如下: <%@ Page Language="C#" %> <%@ import Namespace="System.Collections" %> <script runat="server"> void Page_Load(Object sender, EventArgs e) { if(!Page.IsPost

在ASP.NET中访问DataGrid中所有控件的值

asp.net|datagrid|访问|控件 要在ASP.NET中访问DataGrid中所有控件的值,可以遍历DataGrid中每个控件:下面就是实现这一功能的aspx代码和脚本代码[VB.NET]: <%@ Page Language="vb" AutoEventWireup="false" Codebehind="DataGridAccessValues.aspx.vb" Inherits="aspxWeb.DataGridA

jquery ajax跨域访问怎么修改header中的referer的值

问题描述 jqueryajax跨域访问怎么修改header中的referer的值:$.ajax({type:"get",url:"http://api.sceea.cn/Handler/GetSpcjkHandler.ashx",data:data,dataType:'jsonp',jsonp:'jsoncallback',beforeSend:function(xhr){//beforeSend定义全局变量xhr.setRequestHeader("Re

如何解决Ajax访问不断变化的session的值不一致以及HTTP协议中的GET、POST的区别_AJAX相关

今天在做一个进度条的时候遇到一个问题,我在session里面存放了一个计数器,当爬取到一条数据的时候这个值+1,然后前台每隔3s中获取一次session的这个值,但是问题出来了,在FF下面,得到的值都是正常的,但是在IE下面死活都是之前的值,只有当重新打开页面的时候才能获取到最新的 session值: 下面是我的proBar.jsp的代码: <%@ page language="java" import="java.util.*" pageEncoding=&

利用OpenCV检测图像中的长方形画布或纸张并提取图像内容

原文:利用OpenCV检测图像中的长方形画布或纸张并提取图像内容 基于知乎上的一个答案.问题如下: 也就是在一张照片里,已知有个长方形的物体,但是经过了透视投影,已经不再是规则的长方形,那么如何提取这个图形里的内容呢?这是个很常见的场景,比如在博物馆里看到一幅很喜欢的画,用手机找了下来,可是回家一看歪歪斜斜,脑补原画内容又觉得不对,那么就需要算法辅助来从原图里提取原来的内容了.不妨把应用的场景分为以下: 纸张四角的坐标(图中红点)已知的情况 也就是上面的左图中4个红点是可以准确获取,比如手动标注

http-mfc访问HTTP中的参数问题

问题描述 mfc访问HTTP中的参数问题 现在有一个链接如下:http://ip:port/context/alarm.tfc?method=sendAlarm&yjxh=&yjsj=&ywlb=&bklx=&bkzlx=&gcxh=&kkbh=&kkmc=&fxlx=&hpzl=&hphm=&gcsj=;'?'后面的是一系列参数,请问我要怎么用WinInet的相关函数去访问这个网址并且获得这些相关参数的值?直

c++-OpenCV 的 Mat 内存错误?

问题描述 OpenCV 的 Mat 内存错误? 新学习Mat类型,编示例程序 #include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> using namespace cv; int main(){ Mat image=imread("test.jpg"); imwrite("test1.jpg",image); } 结果运行时出错: "0x76322