欢迎转载。尊重原创,因此,请注明出处:

http://blog.csdn.net/bendanban/article/details/30527785

本文讲述了OpenCV中几种訪问矩阵元素的方法,在指定平台上给出性能比較,分析每种矩阵元素訪问方法的代码复杂度,易用性。

一、预备设置

本文假设你已经正确配置了OpenCV的环境,为方便大家实验,在文中也给出了编译源程序的Makefile,其内容如代码段1所看到的。

採用如代码段2所看到的的计时函数,这段代码你能够在我之前的博文中找到。abtic() 能够返回微秒(10^-6秒)级,并且兼容WindowsLinux系统。

本文使用彩色图像做实验,所以矩阵是2维的3通道的。

CC = g++
CPPFLAGS = -O3 `pkg-config --cflags opencv`
CPPLIB = `pkg-config --libs opencv` OBJS = test.o main.exe : $(OBJS)
$(CC) $(CPPFLAGS) $^ -o $@ $(CPPLIB) test.o: test.cpp
$(CC) -c $(CPPFLAGS) $^ -o $@ clean:
rm -rf *.out main.exe *.o run:
./main.exe

代码段 1. Makefile文件的内容

#if defined(_WIN32) && defined(_MSC_VER)
#include <windows.h>
double abtic() {
__int64 freq;
__int64 clock;
QueryPerformanceFrequency( (LARGE_INTEGER *)&freq );
QueryPerformanceCounter( (LARGE_INTEGER *)&clock );
return (double)clock/freq*1000*1000;
}
#else
#include <time.h>
#include <sys/time.h>
double abtic() {
double result = 0.0;
struct timeval tv;
gettimeofday( &tv, NULL );
result = tv.tv_sec*1000*1000 + tv.tv_usec;
return result;
}
#endif /* _WIN32 */

代码段 2. 计时函数abtic()的定义

二、測试算法

文中用于測试的算法:将矩阵中每一个元素乘以一个标量,写入一个新的矩阵,每一个通道操作独立。

假设用im(r,c,k)表示矩阵im的第r行、第c列、第k个通道的值的话。算法为:om(r,c,k) = im(r,c,k)*scale;当中scale是一个大于0、小于1的浮点数。

三、五种Mat元素的訪问方法

方法1、使用Mat的成员函数at<>()

    Mat的成员函数at()是一个模板函数,我们这里用的是二维矩阵。所以我们使用的at()函数的声明如代码段3所看到的(取自OpenCV的源文件)。

template<typename _Tp> _Tp& at(int i0, int i1);

代码段3 .at()函数的声明

代码段4是本文第二部分描写叙述的算法的实现。矩阵元素使用at<>()函数来索引。

  Vec3b pix;
for (int r = 0; r < im.rows; r++)
{
for (int c = 0; c < im.cols; c++)
{
pix = im.at<Vec3b>(r,c);
pix = pix*scale;
om.at<Vec3b>(r,c) = pix;
}
}

代码段4. 使用at<>()函数訪问矩阵元素

注意:使用at函数时,应该知道矩阵元素的类型和通道数,依据矩阵元素类型和通道数来确定at函数传递的类型,代码段4中使用的是Vec3b这个元素类型,他是一个包括3个unsigned char类型向量。

之所以採用这个类型来接受at的返回值,是由于,我们的矩阵im是3通道,类型为unsigned char类型的。

方法2、使用Mat的成员函数ptr<>()

此函数也是模板函数,我们将会用到的ptr函数声明如代码段5所看到的。此函数返回指定的数据行的首地址。

template<typename _Tp> _Tp* ptr(int i0=0);

代码段 5. ptr成员函数的声明

使用ptr<>()成员函数完毕本文第二部分所述算法的代码如代码段6所看到的。

  Vec3b *ppix_im(NULL);
Vec3b *ppix_om(NULL);
for (int r = 0; r < im.rows; r++)
{
ppix_im = im.ptr<Vec3b>(r);
ppix_om = om.ptr<Vec3b>(r);
for (int c = 0; c < im.cols; c++)
{
ppix_om[c] = ppix_im[c]*scale;
}
}

代码段 6. 使用ptr訪问矩阵元素

方法3、使用迭代器

这里使用的迭代器是OpenCV自定义的。

使用迭代器完毕第二部分所述算法的代码如代码段7所看到的。

  MatIterator_<Vec3b> it_im, itEnd_im;
MatIterator_<Vec3b> it_om;
it_im = im.begin<Vec3b>();
itEnd_im = im.end<Vec3b>();
it_om = om.begin<Vec3b>();
for (; it_im != itEnd_im; it_im++, it_om++)
{
*it_om = (*it_im)*scale;
}

代码段 7. 使用迭代器訪问矩阵元素

方法4、使用Mat_简化索引

Mat_这个类的元素訪问比較easy一点,把原Mat类的对象能够直接赋值给Mat_对象,当然赋值操作并不会开辟新的数据空间,这点大家放心。也就是说使用Mat_时。不会在内存拷贝上花时间。使用这样的方法完毕第二部分所述算法的代码如代码段8所看到的。

  Mat_<Vec3b> im_, om_;
im_ = im;
om_ = om;
for (int r = 0; r < im.rows; r++)
{
for (int c = 0; c < im.cols; c++)
{
om_(r,c) = im_(r,c) * scale;
}
}

代码段 8. 使用Mat_訪问矩阵数据元素

方法5、使用OpenCV原有的实现

我们的算法实际上OpenCV中已经有实现。

就是×运算符重载,代码如代码段9所看到的。

om = im*scale;

代码段 9. 使用OpenCV的原有实现訪问矩阵元素

四、实验測试

1、測试代码

为了測试方便,将前面的方法统一写到一个c++源文件test.cpp中。其内容如代码段10所看到的。

/*************************************************************************
> File Name: test.cpp
> Author: aban
> Mail: sawpara@126.com
> Created Time: 2014年06月13日 星期五 18时47分19秒
************************************************************************/ #include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std; #if defined(_WIN32) && defined(_MSC_VER)
#include <windows.h>
double abtic() {
__int64 freq;
__int64 clock;
QueryPerformanceFrequency( (LARGE_INTEGER *)&freq );
QueryPerformanceCounter( (LARGE_INTEGER *)&clock );
return (double)clock/freq*1000*1000;
}
#else
#include <time.h>
#include <sys/time.h>
double abtic() {
double result = 0.0;
struct timeval tv;
gettimeofday( &tv, NULL );
result = tv.tv_sec*1000*1000 + tv.tv_usec;
return result;
}
#endif /* _WIN32 */ #define ISSHOW 0 int main(int argc, char** argv)
{
double tRecorder(0.0);
Mat im = imread("./bigim.tif");
Mat om;
om.create(im.rows, im.cols, CV_8UC3); #if ISSHOW
imshow("orignal Image", im);
waitKey();
#endif float scale = 150.0f/255.0f; // 1. using at()
tRecorder = abtic();
Vec3b pix;
for (int r = 0; r < im.rows; r++)
{
for (int c = 0; c < im.cols; c++)
{
pix = im.at<Vec3b>(r,c);
pix = pix*scale;
om.at<Vec3b>(r,c) = pix;
}
}
cout << (abtic() - tRecorder) << " using at<>()" << endl;
#if ISSHOW
imshow("Scaled Image: using at<>()", om);
waitKey();
#endif // 2. using ptr
tRecorder = abtic();
Vec3b *ppix_im(NULL);
Vec3b *ppix_om(NULL);
for (int r = 0; r < im.rows; r++)
{
ppix_im = im.ptr<Vec3b>(r);
ppix_om = om.ptr<Vec3b>(r);
for (int c = 0; c < im.cols; c++)
{
ppix_om[c] = ppix_im[c]*scale;
}
}
cout << (abtic() - tRecorder) << " using ptr<>() " << endl;
#if ISSHOW
imshow("Scaled Image: using ptr<>()", om);
waitKey();
#endif // 3. using iterator
tRecorder = abtic();
MatIterator_<Vec3b> it_im, itEnd_im;
MatIterator_<Vec3b> it_om;
it_im = im.begin<Vec3b>();
itEnd_im = im.end<Vec3b>();
it_om = om.begin<Vec3b>();
for (; it_im != itEnd_im; it_im++, it_om++)
{
*it_om = (*it_im)*scale;
}
cout << (abtic() - tRecorder) << " using iterator " << endl;
#if ISSHOW
imshow("Scaled Image: using iterator", om);
waitKey();
#endif // 4. using Mat_
tRecorder = abtic();
Mat_<Vec3b> im_, om_;
im_ = im;
om_ = om;
for (int r = 0; r < im.rows; r++)
{
for (int c = 0; c < im.cols; c++)
{
om_(r,c) = im_(r,c) * scale;
}
}
cout << (abtic() - tRecorder) << " using Mat_ " << endl;
#if ISSHOW
imshow("Scaled Image: using Mat_", om);
waitKey();
#endif // 5. using *
tRecorder = abtic();
om = im*scale;
cout << (abtic() - tRecorder) << " using * " << endl;
#if ISSHOW
imshow("Scaled Image: using *", om);
waitKey();
#endif return 0;
}

代码段10. 測试代码

假设你想使用第一部分提到的Makefile,你须要将代码段10保存成test.cpp。或者保存成你希望的某个名字,可是同一时候应该改动Makfile中的全部“test.cpp”。

在正确运行之前。将代码段10中的第40行代码改成你的图片名称。

2、实验平台

CPU:Intel(R) Pentium(R) CPU G840 @ 2.80GHz

G++:4.8.2

OpenCV : 2.4.9

3、实验结果

编译选项使用-O3时。当中一次运行结果:

489570 using at<>()
467315 using ptr<>()
468603 using iterator
469041 using Mat_
621367 using *

编译选项使用-O0 -g时,当中一次运行结果:

2.48216e+06 using at<>()
2.15397e+06 using ptr<>()
3.80784e+06 using iterator
2.38941e+06 using Mat_
621099 using *

4、实验分析

从上面的结果能够看出,使用×时,在两种模式下,计算速度差点儿相同,这实际是由于我们的程序调用的OpenCV的库函数,而这个库函数调用的是同一个。

假设你的产品要求运行速度,从-O3条件下的输出结果能够看出,ptr这样的方式速度略微快一点。可是他们的区别并不大,所以应该再考虑代码的复杂度。

代码复杂度用代码量(代码行数、列数)、使用变量的个数、使用变量个类型掌握难度(比方指针可能难一点)等因素来度量。

最小的就是使用×了(最后一个方法)。尽管他的复杂度较小。实际仅仅有一行代码,可是对于实际的应用,你要想调用OpenCV已经实现的功能。首先要确定OpenCV里已经实现了这个功能。

其次。我觉得复杂度较小的是方法一,由于它实际上能够不借用pix变量。完毕前述算法,使用变量数较少。代码量也不多。

Mat_和ptr这两种方式的复杂度差点儿相同,假设使用指针是一种略微难一点的方式的话。那么Mat_的复杂度能够觉得略微小一点。

一般觉得迭代器是C++里面比較高级的特性。也是学习C++最靠后的技术,再加上它使用了指针,假设指针算是比較难掌握的技术的话,使用迭代器这样的方式复杂度能够说是最复杂的了。

有些情况下,须要考虑安全性,比方防止越界訪问。假设你不想考虑过多边界的问题,使用迭代器或许是一种不错的选择!

五、总结

选择哪种元素訪问方式。应该依据自己的实际应用环境,详细分析作出决定。

主要考虑三个因素:性能、代码复杂度、安全性,依据自己的程序类型,选择。

版权声明:本文博主原创文章,博客,未经同意不得转载。

OpenCV:Mat元素访问方法、演出、代码的复杂性和安全性分析的更多相关文章

  1. OpenCV:Mat元素访问方法、性能、代码复杂度以及安全性分析

    欢迎转载,尊重原创,所以转载请注明出处: http://blog.csdn.net/bendanban/article/details/30527785 本文讲述了OpenCV中几种访问矩阵元素的方法 ...

  2. jquery iframe父子框架中的元素访问方法

    在web开发中,经常会用到iframe,难免会碰到需要在父窗口中使用iframe中的元素.或者在iframe框架中使用父窗口的元素 js 在父窗口中获取iframe中的元素 1. 格式:window. ...

  3. OpenCV不同类型Mat的at方法访问元素时该如何确定模板函数的typename(转)

    自从OpenCV推出了Mat后越来越像是Matlab了,使用起来方便了很多,但是,在用at方法访问Mat时,如何选用合适的typename类型来访问相应的Mat元素是个头疼的问题. 比如: int H ...

  4. 访问 HTML中元素的方法

    http://www.w3school.com.cn/jsref/index.asp   1.document.getElementbyId("id1"),Html中,名称是id1 ...

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

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

  6. OpenCv Mat操作总结

    Author:: Maddock Date: 2015-03-23 16:33:49 转载请注明出处:http://blog.csdn.net/adong76/article/details/4053 ...

  7. C++ Opencv Mat类型使用的几个注意事项及自写函数实现Laplace图像锐化

    为了提升自己对Opencv中Mat数据类型的熟悉和掌握程度,自己尝试着写了一下Laplace图像锐化函数,一路坎坷,踩坑不断.现将代码分享如下: #include <opencv2/opencv ...

  8. OPENCV mat类

    OpenCV参考手册之Mat类详解 目标 我们有多种方法可以获得从现实世界的数字图像:数码相机.扫描仪.计算机体层摄影或磁共振成像就是其中的几种.在每种情况下我们(人类)看到了什么是图像.但是,转换图 ...

  9. opencv Mat 像素操作

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

随机推荐

  1. birdnest是什么意思_birdnest在线翻译_英语_读音_用法_例句_海词词典

    birdnest是什么意思_birdnest在线翻译_英语_读音_用法_例句_海词词典 birdnest

  2. 解决IE11无法下载文件的问题

    [问题描写叙述] 单击IE底部下载工具栏没反应,点击"另存为"也没反应 [解决方法] 打开IE11,依次打开菜单:Internet 选项 -> 高级 -> 重置,重置完 ...

  3. SE 2014年5月28日

    R1模拟总部,R2 与R3模拟分部 如图配置 (1)网络中目前只有两站点, R1 和R2 .同时R2为动态获取IP地址一方,要求使用要求使用 GRE over IPSec VPN 野蛮模式,保证R1和 ...

  4. 利用try-catch判断变量是已声明未声明还是未赋值

    原文 利用try-catch判断变量是已声明未声明还是未赋值 这篇文章主要介绍了利用try-catch判断变量是已声明未赋值还是未声明,需要的朋友可以参考下 目的是如果一个变量是已声明未赋值,就可以直 ...

  5. Learning Cocos2d-x for WP8(1)——创建首个项目

    原文:Learning Cocos2d-x for WP8(1)--创建首个项目 Cocos2d-x for WP8开发语言是C++,系列文章将参考兄弟篇Learning Cocos2d-x for ...

  6. hdu1874畅通工程续 (dijkstra)

    Problem Description 某省自从实行了很多年的畅通工程计划后,终于修建了很多路.不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行 ...

  7. POJ 2942 Knights of the Round Table - from lanshui_Yang

    Description Being a knight is a very attractive career: searching for the Holy Grail, saving damsels ...

  8. Windows phone 8 学习笔记(1) 触控输入

    原文:Windows phone 8 学习笔记(1) 触控输入 Windows phone 8 的应用 与一般的Pc应用在输入方式上最大的不同就是:Windows phone 8主要依靠触控操作.因此 ...

  9. 小技巧,把execl.exe转换成dll

    小技巧 把execl.exe转换成dll1.把excel.exe复制到CProgram FilesMicrosoft Visual Studio .NET 2003SDKv1.1Bin夹中,和TlbI ...

  10. Windows Phone开发(13):如何规范用户的输入行为

    原文:Windows Phone开发(13):如何规范用户的输入行为 很多时候,我们对用户的操作或输入做一定程度的限制,以避免发生不必要的异常或错误,因此,对一些特殊的类型,进行输入限制是很有必要的. ...