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

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`

得出结果如下:


可以看出此时的性能符合一般常识。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值