您的位置:首页 > 运维架构

opencv 矩阵元素不同获取方式及其效率对比

2016-04-15 14:38 459 查看
opencv 矩阵数据Mat元素获取有四种方式: 直接获取、模板方式、行指针方式、元素地址方式。 测试发现在O3优化方式下直接获取和元素地址访问这两中方式效率最高, 其效率为模板和行指针方式的两倍。 在没有优化的方式下符合一般常识,元素地址访问和行指针方式效率最高。

测试代码如下:

#include <string>
#include <iostream>
#include <time.h>
using namespace cv;
using namespace std;
#include "CwTimer.hpp"
int main( int argc, const char** argv )
{

//矩阵总共获取次数
uint32_t num = 10000;
Mat m(100, 100, CV_64F, Scalar(0));
//定义矩阵模板
Mat_<double> m_ = m;
uint32_t h = m.rows, w = m.cols;
//直接获取方式
CwTimer tm0("direct");
for(int i = 0; i < num; i++)
{
tm0.Start();
for(int p = 0; p < h; p++)
{
for(int q = 0; q < w; q++)
{
m.at<float>(p, q) = 13;
double tm = m.at<double>(p, q);
}
}
tm0.Stop();
}
tm0.Report();

//模板获取方式
CwTimer tm3("template");
for(int i = 0; i < num; i++)
{
tm3.Start();
for(int p = 0; p < h; p++)
{
for(int q = 0; q < w; q++)
{
m_(p, q) = 13;
double tm = m_(p, q);
}
}
tm3.Stop();
}
tm3.Report();
//行指针获取方式
CwTimer tm1("row_ptr");
for(int i = 0; i < num; i++)
{
tm1.Start();
for(int p = 0; p < h; p++)
{
double * pm = m.ptr<double>(p);
for(int q = 0; q < w; q++)
{
pm[q] = 13;
double tm = pm[q];
}
}
tm1.Stop();
}
tm1.Report();
//元素地址获取方式
CwTimer tm2("address");
for(int i = 0; i < num; i++)
{
tm2.Start();
double * pdata = (double*)m.data;
for(int p = 0; p < h * w; p++)
{
pdata[p] = 13;
double tm = pdata[p];
}
tm2.Stop();
}
tm2.Report();
return 1;
}


代码中CwTimer 是一个时间类,可以方便测试程序运行时间, 该类是从网络中获取, 作者为 程明明。 其实现如下。

#pragma once

#pragma warning(disable:4512)
class CwTimer
{
public:
CwTimer(string t = "Timer"):title(t) { is_started = false; start_clock = 0; cumulative_clock = 0; n_starts = 0; }

~CwTimer(){	if (is_started) printf("CwTimer '%s' is started and is being destroyed.\n", title.c_str());	}

inline void Start();
inline void Stop();
inline void Reset();

inline bool Report();
inline bool StopAndReport() { Stop(); return Report(); }
inline float TimeInSeconds();

inline float AvgTime(){assert(is_started == false); return TimeInSeconds()/n_starts;}

private:
string title;

bool is_started;
clock_t start_clock;
clock_t cumulative_clock;
unsigned int n_starts;
};

/************************************************************************/
/*                       Implementations                                */
/************************************************************************/

void CwTimer::Start()
{
if (is_started){
printf("CwTimer '%s' is already started. Nothing done.\n", title.c_str());
start_clock = clock();
return;
}

is_started = true;
n_starts++;
start_clock = clock();
}

void CwTimer::Stop()
{
if (!is_started){
printf("CwTimer '%s' is started. Nothing done\n", title.c_str());
return;
}

cumulative_clock += clock() - start_clock;
is_started = false;
}

void CwTimer::Reset()
{
if (is_started)	{
printf("CwTimer '%s'is started during reset request.\n Only reset cumulative time.\n", title.c_str());
return;
}
cumulative_clock = 0;
}

bool CwTimer::Report()
{
if (is_started){
printf("CwTimer '%s' is started.\n Cannot provide a time report.", title.c_str());
return false;
}

float timeUsed = TimeInSeconds();
printf("[%s] CumuTime: %4gs, #run: %2d, AvgTime: %4gs\n", title.c_str(), timeUsed, n_starts, timeUsed/n_starts);
return true;
}

float CwTimer::TimeInSeconds()
{
if (is_started){
printf("CwTimer '%s' is started. Nothing done\n", title.c_str());
return 0;
}
return float(cumulative_clock) / CLOCKS_PER_SEC;
}


利用O3优化:

g++ test.cpp -O3 -o test `pkg-config --cflags --libs opencv`程序运行结果如下, 发现直接获取元素和地址访问速度基本一样,但是模板获取和行指针的方式效率只有其他两种的一般。这个和一般性常识不符,一般认为按照行指针获取的效率会和元素地址获取方式持平。



不利用优化:

g++ test.cpp -g -o test `pkg-config --cflags --libs opencv`

得出结果如下:



可以看出此时的性能符合一般常识。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息