Opencv3.2中的Opencl使用过程中遇到的困惑

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lifei092/article/details/79571628
我的开发环境为:VS2015 + OPencv3.2
首先opencl是一个GPU加速技术,因此需要确认机器的显卡是否支持opencl,通过“TechPowerUp GPU-Z” 这款软件可以看出,如图中红色标注位置,本机是支持opencl技术的。

OK,下面通过opencv自带的光流算法进行opencl的实验验证,确认其是否真的能够加快算法运算速度,代码如下:
#include <iostream>
#include "opencv2/opencv.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/ml/ml.hpp"
#include "opencv2/core/ocl.hpp"
#include <opencv2/core/core.hpp>
#include <omp.h> 
#include <deque>
#include "windows.h"
#include <time.h> /*用到了time函数,所以要有这个头文件*/

using namespace std;
using namespace cv;

#define HAVE_OPENCL 

#ifdef _DEBUG
#pragma comment(lib,"opencv_world320d.lib")
#else
#pragma comment(lib,"opencv_world320.lib")
#endif

LARGE_INTEGER m_liPerfFreq;
LARGE_INTEGER m_liPerfStart;
LARGE_INTEGER liPerfNow;
double dfTim;    //时间记录

//记录开始时间
void getStartTime()
{
	QueryPerformanceFrequency(&m_liPerfFreq);
	QueryPerformanceCounter(&m_liPerfStart);
}

//记录结束时间并计算时间间隔
void getEndTime()
{
	QueryPerformanceCounter(&liPerfNow);
	dfTim = (((liPerfNow.QuadPart - m_liPerfStart.QuadPart) * 1000.0f) / m_liPerfFreq.QuadPart);
}

// 按照面积大小从大到小排序
bool biggerSort(vector<cv::Point> v1, vector<cv::Point> v2)
{
	return cv::contourArea(v1) > cv::contourArea(v2);
}


int main(int argc, const char** argv)
{
	char* VideoFile1 = "E://PictureVideoDatabase//ObjectTrackingVideo//Test//th//st_flux1.mp4";

	UMat frame1;           // 从视频中取出一帧
	UMat FrameDetect;      // 学生场景的检测区域
	UMat Flow;
	UMat gn, gc;
	UMat FramePre;
	int frameNum = 0;
	double pyrScale = 0.6; //一个构造图像金字塔的参数,一般就认为是0.5最好了,也就是将图像缩小一半。
	int	Levels = 3; // 依然是与金字塔有关参数,常设值1.
	int	Winsize = 20; // 相当于一个均值滤波的作用,窗口大小决定了其噪声的抑制能力什么的。
	int Iterations = 3; // 在每层金字塔上的迭代次数。
	int polyN = 5; // 点与附近领域点之间的联系作用,一般为5, 7等等即可。
	double polySigma = 1.2; // 像素点的一个平滑水平,一般1 - 1.5即可。
	int Flags = 0; // 一个标记,决定计算方法,0表示均值滤波,1表示高斯滤波

	VideoCapture capture1(VideoFile1);              // 打开视频文件
	int scale1 = 4;									// 视频处理的缩放比例

	ocl::setUseOpenCL(true);

	if (capture1.isOpened() == false)  // 视频不存在,就返回
		return 0;

	for (;;)
	{
		capture1 >> frame1;
		if (frame1.empty())
			break;
		frameNum++;
		resize(frame1, FrameDetect, Size(frame1.cols / scale1, frame1.rows / scale1));

		//getStartTime();   //获取开始时间
		if (!FramePre.empty())
		{
			getStartTime();   //获取开始时间
			cvtColor(FramePre, gc, CV_RGB2GRAY);
			cvtColor(FrameDetect, gn, CV_RGB2GRAY);
			calcOpticalFlowFarneback(gc, gn, Flow, pyrScale, Levels, Winsize, Iterations, polyN, polySigma, Flags);
			getEndTime();   //得到执行时间
			cout << "with OPencl -- The time is(ms): "<< dfTim << endl;
		}
		FrameDetect.copyTo(FramePre); // 当前帧保存到FramePre中,用于计算下一帧的光流图
	}

	return 0;
}

代码中ocl::setUseOpenCL(true);函数非常重要,它决定了是否使用opencl技术,当参数为true时表示使用opencl技术;当参数为false时表示不使用opencl;除此之外,Mat类型需改为UMat类型。

首先设置opencl不使用,即ocl::setUseOpenCL(false);记录光流法耗时,如下图
其次设置opencl使用,即ocl::setUseOpenCL(true);记录光流法耗时,如下图

从以上两图可以看出,使用opencl技术比不使用Opencl的耗时还要多一倍的耗时,这让我十分困惑,参阅了http://blog.csdn.net/kaychangeek/article/details/78857535 这篇博客,认为opencl技术在某些场合是不太适用的,当对于单幅图像进行大量循环计算时,使用opencl是合适的;而对于类似于视频帧不停读取视频的场景中则不太适合;原因是opencl是使用GPU进行计算的,而在进行计算之前需要将内存数据拷贝到显存中,这个过程是是个隐式的初始化,是较为耗时的。

于是我将光流法重复计算了10次、50次再进行计时,发现结果一样,使用opencl技术比不使用Opencl的耗时还要多一倍的耗时,我猜测是否是因为GPU没有真正运行,于是打开“TechPowerUp GPU-Z” 软件,对GPU运行性能进行检测;
不使用opencl技术的情况下,GPU检测如下图所示:

使用opencl技术的情况下,GPU检测如下图所示:


从上面两图可以看出,GPU是真实运行了,于是我陷入的深深的沉思了,这个opencl貌似没有传说中的那么牛啊。
展开阅读全文

没有更多推荐了,返回首页