1.存取单个像素值

最通常的方法就是

img.at<uchar>(i,j) = 255;
img.at<Vec3b>(i,j)[0] = 255;

2.用指针扫描一幅图像

对于一幅图像的扫描,用at就显得不太好了,还是是用指针的操作方法更加推荐。先介绍一种上一讲提到过的

for (int j=0; j<nl; j++)
{
uchar* data= image.ptr<uchar>(j);
for (int i=0; i<nc; i++)
{
data[i] = 255;
}
}

更高效的扫描连续图像的做法可能是把W*H的衣服图像看成是一个1*(w*h)的一个一维数组,这个想法是不是有点奇葩,这里要利用isContinuous这个函数判断图像内的像素是否填充满,使用方法如下:

if (img.isContinuous())
{
nc = img.rows*img.cols*img.channels();
}
uchar* data = img.ptr<uchar>(0);
for (int i=0; i<nc; i++)
{
data[i] = 255;
}

更低级的指针操作就是使用Mat里的data指针,之前我称之为暴力青年,使用方法如下:

uchar* data = img.data;
// img.at(i, j)
data = img.data + i * img.step + j * img.elemSize();

3.用迭代器iterator扫描图像

和C++STL里的迭代器类似,Mat的迭代器与之是兼容的。是MatIterator_。声明方法如下:

cv::MatIterator_<Vec3b> it;

或者是:

cv::Mat_<Vec3b>::iterator it;

扫描图像的方法如下:

Mat_<Vec3b>::iterator it = img.begin<Vec3b>();
Mat_<Vec3b>::iterator itend = img.end<Vec3b>();
for (; it!=itend; it++)
{
(*it)[0] = 255;
}

4.高效的scan image方案总结

要想减少程序运行的时间,必要的优化包括如下几个方面:

(1)内存分配是个耗时的工作,优化之;

(2)在循环中重复计算已经得到的值,是个费时的工作,优化之;举例:

int nc = img.cols * img.channels();
for (int i=0; i<nc; i++)
{.......}
//**************************
for (int i=0; i<img.cols * img.channels(); i++)
{......}

后者的速度比前者要慢上好多。

(3)使用迭代器也会是速度变慢,但迭代器的使用可以减少程序错误的发生几率,考虑这个因素,可以酌情优化

(4)at操作要比指针的操作慢很多,所以对于不连续数据或者单个点处理,可以考虑at操作,对于连续的大量数据,不要使用它

(5)扫描连续图像的做法可能是把W*H的衣服图像看成是一个1*(w*h)的一个一维数组这种办法也可以提高速度。短的循环比长循环更高效,即使他们的操作数是相同的

以上的这些优化可能对于大家的程序运行速度提高并不明显,但它们毕竟是个得到速度提升的好的编程策略,希望大家能多采纳。

我这里测试了三种操作Mat数据的办法,套用流行词,普通青年,文艺青年,为啥第三种我不叫2b青年,大家慢慢往后看咯。

普通青年的操作的办法通常是M.at<float>(i, j)

文艺青年一般会走路线M.ptr<float>( i )[ j ]

暴力青年通常直接强制使用我第40讲提到的M.data这个指针

实验代码如下:

t = (double)getTickCount();
 Mat img1(1000, 1000, CV_32F);
 
 for (int i=0; i<1000; i++)
 {
  for (int j=0; j<1000; j++)
  {
   img1.at<float>(i,j) = 3.2f;
  }
 }
 t = (double)getTickCount() - t;
 printf("in %gms\n", t*1000/getTickFrequency());
 //***************************************************************
 t = (double)getTickCount();
 Mat img2(1000, 1000, CV_32F);

for (int i=0; i<1000; i++)
 {
  for (int j=0; j<1000; j++)
  {
   img2.ptr<float>(i)[j] = 3.2f;
  }
 }
 t = (double)getTickCount() - t;
 printf("in %gms\n", t*1000/getTickFrequency());
 //***************************************************************
 t = (double)getTickCount();
 Mat img3(1000, 1000, CV_32F);
 float* pData = (float*)img3.data;

for (int i=0; i<1000; i++)
 {
  for (int j=0; j<1000; j++)
  {
   *(pData) = 3.2f;
   pData++;
  }
 }
 t = (double)getTickCount() - t;
 printf("in %gms\n", t*1000/getTickFrequency());
 //***************************************************************
 t = (double)getTickCount();
 Mat img4(1000, 1000, CV_32F);

for (int i=0; i<1000; i++)
 {
  for (int j=0; j<1000; j++)
  {
   ((float*)img3.data)[i*1000+j] = 3.2f;
  }
 }
 t = (double)getTickCount() - t;
 printf("in %gms\n", t*1000/getTickFrequency());

最后两招可以都看成是暴力青年的方法,因为反正都是指针的操作,局限了各暴力青年手段就不显得暴力了。

在Debug、Release模式下的测试结果分别为:

测试结果
  Debug Release
普通青年 139.06ms 2.51ms
文艺青年 66.28ms 2.50ms
暴力青年1 4.95ms 2.28ms
暴力青年2 5.11ms 1.37ms

根据测试结果,普通青年的操作在Debug模式下果然缓慢,文艺青年的路线确实有提高。值得注意的是本来后两种办法确实是一种比较2b青年的做法,因为at操作符或者ptr操作符,其实都是有内存检查的,防止操作越界的,而直接使用data这个指针确实很危险。不过从速度上确实让人眼前一亮,所以我不敢称这样的青年为2b,尊称为暴力青年吧。

不过在Release版本下,几种办法的速度差别就不明显啦。所以如果大家最后发行程序的时候,可以不在意这几种操作办法的,推荐前两种哦,都是很好的写法,

推荐两种文艺青年的处理方案,测试了一下,先贴代码,再贴测试结果:

/*********加强版********/
 t = (double)getTickCount();
 Mat img5(1000, 1000, CV_32F);
 float *pData1;
 for (int i=0; i<1000; i++) 
 { 
  pData1=img5.ptr<float>(i);
  for (int j=0; j<1000; j++) 
  { 
   pData1[j] = 3.2f; 
  } 
 } 
 t = (double)getTickCount() - t;
 printf("in %gms\n", t*1000/getTickFrequency());
 /*******终极版*****/
 t = (double)getTickCount();
 Mat img6(1000, 1000, CV_32F);
 float *pData2;
 Size size=img6.size();
 if(img2.isContinuous())
 {
  size.width = size.width*size.height;
  size.height = 1;
 }
 size.width*=img2.channels();
 for(int i=0; i<size.height; i++)
 {
  pData2 = img6.ptr<float>(i);
  for(int j=0; j<size.width; j++)
  {
   pData2[j] = saturate_cast<float>(3.2f);
  }
 }
 t = (double)getTickCount() - t;
 printf("in %gms\n", t*1000/getTickFrequency());

测试结果:

  Debug Release
加强版文艺青年 5.74ms 2.43ms
终极版文艺青年 40.12ms 2.34ms

我的测试结果感觉这两种方案只是锦上添花的效果,也使大家的操作有了更多的选择,但感觉在速度上并没有数量级的提升,再次感谢箫铭对我blog的支持。后来箫铭说saturate_cast才把速度降下来,我很同意,就不贴上去测试结果了。但我查看资料了解了一下saturate_cast的作用。可以看成是类型的强制转换,比如对于saturate_cast<uchar>来说,就是把数据转换成8bit的0~255区间,负值变成0,大于255的变成255。如果是浮点型的数据,变成round最近的整数,还是很有用处的函数,推荐大家在需要的时候尝试。

http://blog.csdn.net/yang_xian521/article/details/7161335

opencv MAT数据操作的更多相关文章

  1. Opencv Mat的操作

    cout << mat 有错误的原因 You are using OpenCV built with VS10. The ostream operator << in the ...

  2. opencv Mat 像素操作

    1 cv::Mat cv::Mat是一个n维矩阵类,声明在<opencv2/core/core.hpp>中.   class CV_EXPORTS Mat { public: //a lo ...

  3. 转 OpenCV Mat 数据读写

    转:https://blog.csdn.net/u011520181/article/details/83831866 1.创建 Mat 对象: // 创建一个 320x240 的 8 位无符号型 4 ...

  4. Opencv Mat矩阵操作注意事项

    矩阵操作通常不会进行元素复制,应注意: Mat a=Mat(100,100,CV_32S); Mat b=Mat(100,100,CV_32S); b=a.col(8);//此时并未进行元素赋值,而只 ...

  5. Visual Studio 控制台应用程序 同时使用OpenCV和matlab mat文件操作

    matalb具有灵活的图像处理,代码编写起来简洁而高效.而OpenCV具有很多成熟的计算机视觉算法,能够处理很多实时的识别处理等问题,而且代码运行起来效率很高.所以如何结合两者之间的优点,是让很多学术 ...

  6. 快速遍历OpenCV Mat图像数据的多种方法和性能分析 | opencv mat for loop

    本文首发于个人博客https://kezunlin.me/post/61d55ab4/,欢迎阅读! opencv mat for loop Series Part 1: compile opencv ...

  7. OpenCV MAT基本图像容器

    参考博客: OpenCv中cv::Mat和IplImage,CvMat之间的转换 Mat - 基本图像容器 Mat类型较CvMat和IplImage有更强的矩阵运算能力,支持常见的矩阵运算(参照Mat ...

  8. 【转】OpenCV Mat数据结构

    转载自xiahouzuoxin原文 OpenCV基础篇之Mat数据结构 程序及分析 /* * FileName : MatObj.cpp * Author : xiahouzuoxin @163.co ...

  9. [OpenCV]Mat类详解

    http://blog.csdn.net/yang_xian521/article/details/7107786 Preface Mat:Matrix Mat类可以被看做是opencv中C++版本的 ...

随机推荐

  1. Python 数据分析(二 本实验将学习利用 Python 数据聚合与分组运算,时间序列,金融与经济数据应用等相关知识

    Python 数据分析(二) 本实验将学习利用 Python 数据聚合与分组运算,时间序列,金融与经济数据应用等相关知识 第1节 groupby 技术 第2节 数据聚合 第3节 分组级运算和转换 第4 ...

  2. 基于visual Studio2013解决C语言竞赛题之0804成绩筛选

     题目

  3. 调试出不来 断点不起作用 调试技巧 MyEclipse进不了调试

    1:今天遇到了web项目调试总是不起作用,后来经人指点才知,当调试的断点仅仅是一个小圆圈时断点是不起作用的,这是可以重启下tomcat服务器再重新访问断点才会起作用,这是你会发现断点的小圆点左下角有个 ...

  4. K&amp;R练习题6-1统计关键词出现的次数

    这道练习题训练了: 1.结构体数组 2.二分查找 3.指针操作 ---- 都不难.但非常基础,我认为非常好,做完了记到博客上来,题目见k&R,实现例如以下: /* * Practice of ...

  5. IE 下使用firebug

    javascript :var firebug=document.createElement('script');firebug.setAttribute('src','http://getfireb ...

  6. perl 类里的函数调用其他类的函数

    perl 类里的函数调用其他类的函数: package Horse; use base qw(Critter); sub new { my $invocant = shift; my $class = ...

  7. python模块介绍- binascii 二进制和ASCII转换

    python模块介绍-binascii二进制和ASCII转换 目录 项目简介 简介: Uu编码 Binhex编码 Base64编码 QP码 CRC校验和 二进制转换 其他实例 项目简介 Python中 ...

  8. 同一个form里,不管哪个 submit 都是直接提交form表单里的内容

    要达到你的目的,就不能用类型为 submit 的按钮,要用 button,然后加onclick 方法来自定义预处理参数,然后再调用 submit 方法提交表单,比如 <script type=& ...

  9. PHP学习之-正则表达式

    PHP学习之-正则表达式 1.什么是正则表达式 正则表达式是对字符串处理额一种逻辑公式,就是用特定的字符串组合成一个规则的字符串,称之为正则匹配模式 $p = '/apple/'; $str = '' ...

  10. python中文注释及输出出错

    今天开始接触python,中文报错,你懂的,不细说. 网上很多类似的解决方案,有不是很明确,例如:http://blog.csdn.net/chen861201/article/details/770 ...