[cookbook笔记三] colorReduce函数运行效率测试方法

原创 2014年05月15日 16:15:02
一个很有用的测试图像处理运行耗时的方法为
double duration;
duration = static_cast<double>(cv::getTickCount());
colorReduce(image); // the function to be tested
duration = static_cast<double>(cv::getTickCount())-duration;
duration /= cv::getTickFrequency(); // the elapsed time in s

其中duration结果可以是多次调用函数colorReduce后的平均值,注意到函数getTickFrequency()是将tick转换成秒,而不是毫秒!

那么接下来就测试一下几种函数实现同意功能的不同运行耗时:

测试函数:

double duration = static_cast<double>(getTickCount());
	for (int i=0 ; i<10 ; i++){
		colorReduce2(img,64);
	}
	duration = static_cast<double>(getTickCount())-duration ;
	duration *=1000;//转换成ms
	duration /=(getTickFrequency()*10);
	cout<<"共耗时 : "<<duration<<" ms"<<endl;

函数一:

void colorReduce1(Mat &image , int factor)//行指针扫描方式,据官方文档说是最快的方式
{
	int colLength = image.cols*image.channels();
	for(int i=0; i<image.rows ; i++){
		uchar *data = image.ptr<uchar>(i);//得到每一行的起始地址
		for(int j=0; j< colLength; j++){
			data[j] = data[j]/factor * factor + factor/2;
		}
	}
}

实际运行效果(取10次的平均值):



函数二:

void colorReduce2(Mat &image ,int factor)//连续时直接扫描
{
	int nCols,nRows;
	if(image.isContinuous()){
		nCols = image.total() * image.elemSize();
		nRows = 1;
		uchar *data = image.ptr<uchar>(0);//第一行指针
		for(int i=0 ; i<nCols ; i++){
			data[i] = 255;
		}
	}
}

实际运行效果(取10次的平均值):



函数三:

void colorReduce3(Mat &image , int factor)//迭代器方式
{
	Mat_<Vec3b> cImage = image;
	Mat_<Vec3b>::iterator it = cImage.begin();
	Mat_<Vec3b>::iterator itEnd = cImage.end();
	for(; it!=itEnd ; it++){
		(*it)[0] = (*it)[0]/factor *factor + factor/2;
		(*it)[1] = (*it)[1]/factor *factor + factor/2;
		(*it)[2] = (*it)[2]/factor *factor + factor/2;
	}
}
实际运行效果(取10次的平均值):


函数四:

void colorReduce4(Mat &image , int factor)//at方式---注意内外层循环的嵌套方式 ,由于图片是按行存储,因此下面的方式应该会很慢---真的么?
{
	for(int ncols=0 ; ncols <image.cols ; ncols++){
		for(int nrows=0 ; nrows<image.rows ; nrows++){
			image.at<Vec3b>(nrows , ncols)[0] = image.at<Vec3b>(nrows , ncols)[0]/factor * factor + factor/2;
			image.at<Vec3b>(nrows , ncols)[1] = image.at<Vec3b>(nrows , ncols)[1]/factor * factor + factor/2;
			image.at<Vec3b>(nrows , ncols)[2] = image.at<Vec3b>(nrows , ncols)[2]/factor * factor + factor/2;
		}
	}
}

实际运行效果(取10次的平均值):



函数五:

void colorReduce5(Mat &image , int factor)
{
	for(int nrows=0 ; nrows <image.rows ; nrows++){//at方式---注意内外层循环的嵌套方式 ,由于图片是按行存储,因此下面的方式应该会比上面的快一些--真的么?
		for(int ncols=0 ; ncols<image.cols ; ncols++){
			image.at<Vec3b>(nrows , ncols)[0] = image.at<Vec3b>(nrows , ncols)[0]/factor * factor + factor/2;
			image.at<Vec3b>(nrows , ncols)[1] = image.at<Vec3b>(nrows , ncols)[1]/factor * factor + factor/2;
			image.at<Vec3b>(nrows , ncols)[2] = image.at<Vec3b>(nrows , ncols)[2]/factor * factor + factor/2;
		}
	}
}

实际运行效果(取10次的平均值):



函数六:

void colorReduce6(Mat &image , int factor)
{
	if(image.isContinuous()){
		image.reshape(1,image.cols*image.rows);//并不改变存储方式
	}
	int nrow = image.rows;
	int ncol = image.cols * image.channels();
	for(int i=0; i<nrow; i++){
		uchar* data = image.ptr<uchar>(i);
		for(int j=0; j<ncol; j++){
			data[j] = data[j]/factor*factor +factor/2;
		}
	}
}
实际运行效果(取10次的平均值):



注意:注意到许多运行效率的问题都有能来自于程序编写所致,

例如:

将int nc= image.cols * image.channels(); 

for (int i=0; i<nc; i++) {}

换成for (int i=0; i<image.cols * image.channels(); i++) {}

这样你需要多次重复计算一行的元素个数,会带来巨大的运行消耗,而这个消耗是可以避免的!


结论:1.关于迭代器访问方式:迭代器访问方式的主要作用是简化访问步骤---smart enough to skip the gaps,且可以与STL兼容(可以用到如sort等算法中去),所以运行效率稍低是可以接受的。

           2.关于at访问方式效率最低,这种方式往往用于随机访问某一位置像素点的值,一般不用于扫描整个图像!

   3.注意函数4和5,很显然其实没有这回事儿,因为在内存中,不存在磁头移动的问题,因此上一次随机存取的位置对这一次没有影响!都是要计算起始地址加偏移量。因此俩函数效率差不多!

   4.关于for循环:循环次数少但循环内语句多点  >  一个长循环

   这样我们可以得到最快的改进版函数:

void colorReduce7(Mat &image , int factor)
{
	int nCols,nRows;
	if(image.isContinuous()){
		nRows = 1;
		uchar *data = image.ptr<uchar>(0);//第一行指针
		for(int i=0 ; i<image.cols ; i++){
			data[i] = data[i]/factor * factor + factor/2;
			data[i++] = data[i++]/factor * factor + factor/2;
			data[i++] = data[i++]/factor * factor + factor/2;
		}
	}
}
注意到这里总是假定image是连续的,一个更完善的方案是如下方案:

void colorReduce8(Mat &image , int factor)
{
	int nRows=image.rows;
	int nCols=image.cols;

	if(image.isContinuous()){
		nCols = image.cols * image.rows;
		nRows = 1;
	}
	for(int i=0 ; i<nRows ; i++){
		uchar *data = image.ptr<uchar>(i);//第一行指针
		for(int j=0 ; j<nCols ; j++)
		{
			*data++ = *data/factor * factor + factor/2;
			*data++ = *data/factor * factor + factor/2;
			*data++ = *data/factor * factor + factor/2;
		}
	}
}

扩展:使用多线程技术也是一个加快嵌套的for循环运行效率的方法!在此可以参考目前比较常用的OpenMP和Intel Threading Building Blocks (TBB)这俩API。OpenMp直接在VS中开启的方法就是打开工程属性页面,找到 C++/语言 这一栏,其中有一个OpenMP支持,打开就能使用了!


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

我的OpenCV学习笔记(二):操作每个像素

首先推荐一本书:《OpenCV 2 Computer Vision Application Programming Cookbook》网上可以下载到这本书的英文版,貌似没有翻译的。这本书的特点是里面的...

opencv学习(5)图像像素的访问、颜色通道的分离和融合

代码都是源于毛星云的《opencv3.0编程入门》1、计时函数 getTickCount()和getTickFrequency()函数; getTickCount()函数返回CPU自某个事件...

我的OpenCV学习笔记(三):利用操作像素完成简单的图像处理:加入椒盐噪声、图像翻转、改变对比度、图像锐化

在第二讲中,我介绍了如何操作每个像素,这次利用操作像素完成简单的图像处理操作。 首先从给图像加入椒盐噪声开始,椒盐噪声其实就是使图像的一些随机的像素为黑色(255)或者白色(0): #includ...

OpenCV参考手册之Mat类详解(三)

Mat::eye 返回一个恒等指定大小和类型矩阵。 C++: static MatExpr Mat::eye(int rows, int cols, inttype) C++: static MatE...

opencv 人脸识别 (二)训练和识别

上一篇中我们对训练数据做了一些预处理,检测出人脸并保存在\pic\color\x文件夹下(x=1,2,3,...类别号),本文做训练和识别。为了识别,首先将人脸训练数据 转为灰度、对齐、归一化,再放入...

OpenCV学习笔记(十八)——图像的各种变换(cvtColor*+)imgproc

imgproc是OpenCV一个比较复杂的lib,我是分开介绍的,之前介绍过了滤波器、直方图、结构分析和形状描述三节,这次介绍一下图像的变换,OpenCV对于图像的变换又可分为几何变换和其他的变换,我...

OPENCV3.0 函数学习2——cvtColor

1 .cvtColor cvtColor 是Opencv里的颜色空间转换函数,可以实现RGB颜色向HSV,HSI等颜色空间的转换,也可以转换为灰度图像。 函数参数说明  void cvtColo...

双目相机标定以及立体测距原理及OpenCV实现

单目相机标定的目标是获取相机的内参和外参,内参(1/dx,1/dy,Cx,Cy,f)表征了相机的内部结构参数,外参是相机的旋转矩阵R和平移向量t。内参中dx和dy是相机单个感光单元芯片的长度和宽度,是...
  • dcrmg
  • dcrmg
  • 2016-10-31 22:59
  • 8739

CSDN 2007软件技术英雄大会

来到CSDN也有近两年的时间了,一开始,只是灌水、看贴、学习,逐渐开始参与讨论,体会到交流的重要性,慢慢开始活跃在C/C++版块。不想居然收到CSDN邀请,有幸参加CSDN 2007软件技术英雄大会。...

opencv imencode和imdecode使用,用于网络传输图片

这是C++版本的。程序首先读入一个图片。然后encode,之后把encode后的内容写入文件(实际应用可以发送到网络)。第二步,从文件读取encode的内容。然后解码decode。转换为mat格式,显...
  • tt_ren
  • tt_ren
  • 2016-11-19 10:09
  • 6276
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)