基于opencv的gpu与cpu对比程序,代码来自opencv的文档中

简介:   原文链接: http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/gpu/gpu-basics-similarity/gpu-basics-similarity.html   代码中有错误,关于GpuMat OpenCV代码中没有对其进行操作符运算的重载,所有编译的时候有错误。

 

原文链接:

http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/gpu/gpu-basics-similarity/gpu-basics-similarity.html

 

代码中有错误,关于GpuMat OpenCV代码中没有对其进行操作符运算的重载,所有编译的时候有错误。对于GpuMat的运算只能调用相关函数才行,后面我嫌麻烦就没有重写

 

 

 

<span style="font-size:18px;">// PSNR.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include <iostream>                   // Console I/O
#include <sstream>                    // String to number conversion

#include <opencv2/core/core.hpp>      // Basic OpenCV structures
#include <opencv2/imgproc/imgproc.hpp>// Image processing methods for the CPU
#include <opencv2/highgui/highgui.hpp>// Read images
#include <opencv2/gpu/gpu.hpp>        // GPU structures and methods

using namespace std;
using namespace cv;

double getPSNR(const Mat& I1, const Mat& I2);      // CPU versions
Scalar getMSSIM( const Mat& I1, const Mat& I2);

double getPSNR_GPU(const Mat& I1, const Mat& I2);  // Basic GPU versions
Scalar getMSSIM_GPU( const Mat& I1, const Mat& I2);

struct BufferPSNR                                     // Optimized GPU versions
{   // Data allocations are very expensive on GPU. Use a buffer to solve: allocate once reuse later.
	gpu::GpuMat gI1, gI2, gs, t1,t2;

	gpu::GpuMat buf;
};
double getPSNR_GPU_optimized(const Mat& I1, const Mat& I2, BufferPSNR& b);

struct BufferMSSIM                                     // Optimized GPU versions
{   // Data allocations are very expensive on GPU. Use a buffer to solve: allocate once reuse later.
	gpu::GpuMat gI1, gI2, gs, t1,t2;

	gpu::GpuMat I1_2, I2_2, I1_I2;
	vector<gpu::GpuMat> vI1, vI2;

	gpu::GpuMat mu1, mu2; 
	gpu::GpuMat mu1_2, mu2_2, mu1_mu2; 

	gpu::GpuMat sigma1_2, sigma2_2, sigma12; 
	gpu::GpuMat t3; 

	gpu::GpuMat ssim_map;

	gpu::GpuMat buf;
};
Scalar getMSSIM_GPU_optimized( const Mat& i1, const Mat& i2, BufferMSSIM& b);

void help()
{
	cout
		<< "\n--------------------------------------------------------------------------" << endl
		<< "This program shows how to port your CPU code to GPU or write that from scratch." << endl
		<< "You can see the performance improvement for the similarity check methods (PSNR and SSIM)."  << endl
		<< "Usage:"                                                               << endl
		<< "./gpu-basics-similarity referenceImage comparedImage numberOfTimesToRunTest(like 10)." << endl
		<< "--------------------------------------------------------------------------"   << endl
		<< endl;
}

int main(int argc, char *argv[])
{
	help(); 
	Mat I1 = imread("swan1.jpg",1);           // Read the two images
	Mat I2 = imread("swan2.jpg",1);

	if (!I1.data || !I2.data)           // Check for success
	{
		cout << "Couldn't read the image";
		return 0;
	}

	BufferPSNR bufferPSNR;
	BufferMSSIM bufferMSSIM;

	int TIMES; 
	stringstream sstr("500"); 
	sstr >> TIMES;
	double time, result;

	//------------------------------- PSNR CPU ----------------------------------------------------
	time = (double)getTickCount();    

	for (int i = 0; i < TIMES; ++i)
		result = getPSNR(I1,I2);

	time = 1000*((double)getTickCount() - time)/getTickFrequency();
	time /= TIMES;

	cout << "Time of PSNR CPU (averaged for " << TIMES << " runs): " << time << " milliseconds."
		<< " With result of: " <<  result << endl; 

	//------------------------------- PSNR GPU ----------------------------------------------------
	time = (double)getTickCount();    

	for (int i = 0; i < TIMES; ++i)
		result = getPSNR_GPU(I1,I2);

	time = 1000*((double)getTickCount() - time)/getTickFrequency();
	time /= TIMES;

	cout << "Time of PSNR GPU (averaged for " << TIMES << " runs): " << time << " milliseconds."
		<< " With result of: " <<  result << endl; 
/*
	//------------------------------- PSNR GPU Optimized--------------------------------------------
	time = (double)getTickCount();                                  // Initial call
	result = getPSNR_GPU_optimized(I1, I2, bufferPSNR);
	time = 1000*((double)getTickCount() - time)/getTickFrequency();
	cout << "Initial call GPU optimized:              " << time  <<" milliseconds."
		<< " With result of: " << result << endl;

	time = (double)getTickCount();    
	for (int i = 0; i < TIMES; ++i)
		result = getPSNR_GPU_optimized(I1, I2, bufferPSNR);

	time = 1000*((double)getTickCount() - time)/getTickFrequency();
	time /= TIMES;

	cout << "Time of PSNR GPU OPTIMIZED ( / " << TIMES << " runs): " << time 
		<< " milliseconds." << " With result of: " <<  result << endl << endl; 


	//------------------------------- SSIM CPU -----------------------------------------------------
	Scalar x;
	time = (double)getTickCount();    

	for (int i = 0; i < TIMES; ++i)
		x = getMSSIM(I1,I2);

	time = 1000*((double)getTickCount() - time)/getTickFrequency();
	time /= TIMES;

	cout << "Time of MSSIM CPU (averaged for " << TIMES << " runs): " << time << " milliseconds."
		<< " With result of B" << x.val[0] << " G" << x.val[1] << " R" << x.val[2] << endl; 

	//------------------------------- SSIM GPU -----------------------------------------------------
	time = (double)getTickCount();    

	for (int i = 0; i < TIMES; ++i)
		x = getMSSIM_GPU(I1,I2);

	time = 1000*((double)getTickCount() - time)/getTickFrequency();
	time /= TIMES;

	cout << "Time of MSSIM GPU (averaged for " << TIMES << " runs): " << time << " milliseconds."
		<< " With result of B" << x.val[0] << " G" << x.val[1] << " R" << x.val[2] << endl; 

	//------------------------------- SSIM GPU Optimized--------------------------------------------
	time = (double)getTickCount();    
	x = getMSSIM_GPU_optimized(I1,I2, bufferMSSIM);
	time = 1000*((double)getTickCount() - time)/getTickFrequency();
	cout << "Time of MSSIM GPU Initial Call            " << time << " milliseconds."
		<< " With result of B" << x.val[0] << " G" << x.val[1] << " R" << x.val[2] << endl; 

	time = (double)getTickCount();    

	for (int i = 0; i < TIMES; ++i)
		x = getMSSIM_GPU_optimized(I1,I2, bufferMSSIM);

	time = 1000*((double)getTickCount() - time)/getTickFrequency();
	time /= TIMES;

	cout << "Time of MSSIM GPU OPTIMIZED ( / " << TIMES << " runs): " << time << " milliseconds."
		<< " With result of B" << x.val[0] << " G" << x.val[1] << " R" << x.val[2] << endl << endl; 
	return 0;
	*/
	getchar();
}


double getPSNR(const Mat& I1, const Mat& I2)
{
	Mat s1; 
	absdiff(I1, I2, s1);       // |I1 - I2|
	s1.convertTo(s1, CV_32F);  // cannot make a square on 8 bits
	s1 = s1.mul(s1);           // |I1 - I2|^2

	Scalar s = sum(s1);         // sum elements per channel

	double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels

	if( sse <= 1e-10) // for small values return zero
		return 0;
	else
	{
		double  mse =sse /(double)(I1.channels() * I1.total());
		double psnr = 10.0*log10((255*255)/mse);
		return psnr;
	}
}



double getPSNR_GPU_optimized(const Mat& I1, const Mat& I2, BufferPSNR& b)
{    
	b.gI1.upload(I1);
	b.gI2.upload(I2);

	b.gI1.convertTo(b.t1, CV_32F);
	b.gI2.convertTo(b.t2, CV_32F);

	gpu::absdiff(b.t1.reshape(1), b.t2.reshape(1), b.gs);
	gpu::multiply(b.gs, b.gs, b.gs);

	double sse = gpu::sum(b.gs, b.buf)[0];

	if( sse <= 1e-10) // for small values return zero
		return 0;
	else
	{
		double mse = sse /(double)(I1.channels() * I1.total());
		double psnr = 10.0*log10((255*255)/mse);
		return psnr;
	}
}

double getPSNR_GPU(const Mat& I1, const Mat& I2)
{
	gpu::GpuMat gI1, gI2, gs, t1,t2; 

	gI1.upload(I1);
	gI2.upload(I2);

	gI1.convertTo(t1, CV_32F);
	gI2.convertTo(t2, CV_32F);

	gpu::absdiff(t1.reshape(1), t2.reshape(1), gs); 
	gpu::multiply(gs, gs, gs);

	Scalar s = gpu::sum(gs);
	double sse = s.val[0] + s.val[1] + s.val[2];

	if( sse <= 1e-10) // for small values return zero
		return 0;
	else
	{
		double  mse =sse /(double)(gI1.channels() * I1.total());
		double psnr = 10.0*log10((255*255)/mse);
		return psnr;
	}
}

Scalar getMSSIM( const Mat& i1, const Mat& i2)
{ 
	const double C1 = 6.5025, C2 = 58.5225;
	/***************************** INITS **********************************/
	int d     = CV_32F;

	Mat I1, I2; 
	i1.convertTo(I1, d);           // cannot calculate on one byte large values
	i2.convertTo(I2, d); 

	Mat I2_2   = I2.mul(I2);        // I2^2
	Mat I1_2   = I1.mul(I1);        // I1^2
	Mat I1_I2  = I1.mul(I2);        // I1 * I2

	/*************************** END INITS **********************************/

	Mat mu1, mu2;   // PRELIMINARY COMPUTING
	GaussianBlur(I1, mu1, Size(11, 11), 1.5);
	GaussianBlur(I2, mu2, Size(11, 11), 1.5);

	Mat mu1_2   =   mu1.mul(mu1);    
	Mat mu2_2   =   mu2.mul(mu2); 
	Mat mu1_mu2 =   mu1.mul(mu2);

	Mat sigma1_2, sigma2_2, sigma12; 

	GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);
	sigma1_2 -= mu1_2;

	GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);
	sigma2_2 -= mu2_2;

	GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);
	sigma12 -= mu1_mu2;

	///////////////////////////////// FORMULA ////////////////////////////////
	Mat t1, t2, t3; 

	t1 = 2 * mu1_mu2 + C1; 
	t2 = 2 * sigma12 + C2; 
	t3 = t1.mul(t2);              // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))

	t1 = mu1_2 + mu2_2 + C1; 
	t2 = sigma1_2 + sigma2_2 + C2;     
	t1 = t1.mul(t2);               // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2))

	Mat ssim_map;
	divide(t3, t1, ssim_map);      // ssim_map =  t3./t1;

	Scalar mssim = mean( ssim_map ); // mssim = average of ssim map
	return mssim; 
}

Scalar getMSSIM_GPU( const Mat& i1, const Mat& i2)
{ 
	const float C1 = 6.5025f, C2 = 58.5225f;
	/***************************** INITS **********************************/
	gpu::GpuMat gI1, gI2, gs1, t1,t2; 

	gI1.upload(i1);
	gI2.upload(i2);

	gI1.convertTo(t1, CV_MAKE_TYPE(CV_32F, gI1.channels()));
	gI2.convertTo(t2, CV_MAKE_TYPE(CV_32F, gI2.channels()));

	vector<gpu::GpuMat> vI1, vI2; 
	gpu::split(t1, vI1);
	gpu::split(t2, vI2);
	Scalar mssim;

	for( int i = 0; i < gI1.channels(); ++i )
	{
		gpu::GpuMat I2_2, I1_2, I1_I2; 

		gpu::multiply(vI2[i], vI2[i], I2_2);        // I2^2
		gpu::multiply(vI1[i], vI1[i], I1_2);        // I1^2
		gpu::multiply(vI1[i], vI2[i], I1_I2);       // I1 * I2

		/*************************** END INITS **********************************/
		gpu::GpuMat mu1, mu2;   // PRELIMINARY COMPUTING
		gpu::GaussianBlur(vI1[i], mu1, Size(11, 11), 1.5);
		gpu::GaussianBlur(vI2[i], mu2, Size(11, 11), 1.5);

		gpu::GpuMat mu1_2, mu2_2, mu1_mu2; 
		gpu::multiply(mu1, mu1, mu1_2);   
		gpu::multiply(mu2, mu2, mu2_2);   
		gpu::multiply(mu1, mu2, mu1_mu2);   

		gpu::GpuMat sigma1_2, sigma2_2, sigma12; 

		gpu::GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);
		//sigma1_2 = sigma1_2 - mu1_2;
		gpu::subtract(sigma1_2,mu1_2,sigma1_2);

		gpu::GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);
		//sigma2_2 = sigma2_2 - mu2_2;

		gpu::GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);
		(Mat)sigma12 =(Mat)sigma12 - (Mat)mu1_mu2;
		//sigma12 = sigma12 - mu1_mu2

		///////////////////////////////// FORMULA ////////////////////////////////
		gpu::GpuMat t1, t2, t3; 

// 		t1 = 2 * mu1_mu2 + C1; 
// 		t2 = 2 * sigma12 + C2; 
// 		gpu::multiply(t1, t2, t3);     // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))
// 
// 		t1 = mu1_2 + mu2_2 + C1; 
// 		t2 = sigma1_2 + sigma2_2 + C2;     
// 		gpu::multiply(t1, t2, t1);     // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2))

		gpu::GpuMat ssim_map;
		gpu::divide(t3, t1, ssim_map);      // ssim_map =  t3./t1;

		Scalar s = gpu::sum(ssim_map);    
		mssim.val[i] = s.val[0] / (ssim_map.rows * ssim_map.cols);

	}
	return mssim; 
}

Scalar getMSSIM_GPU_optimized( const Mat& i1, const Mat& i2, BufferMSSIM& b)
{ 
	int cn = i1.channels();

	const float C1 = 6.5025f, C2 = 58.5225f;
	/***************************** INITS **********************************/

	b.gI1.upload(i1);
	b.gI2.upload(i2);

	gpu::Stream stream;

	stream.enqueueConvert(b.gI1, b.t1, CV_32F);
	stream.enqueueConvert(b.gI2, b.t2, CV_32F);      

	gpu::split(b.t1, b.vI1, stream);
	gpu::split(b.t2, b.vI2, stream);
	Scalar mssim;

	for( int i = 0; i < b.gI1.channels(); ++i )
	{        
		gpu::multiply(b.vI2[i], b.vI2[i], b.I2_2, stream);        // I2^2
		gpu::multiply(b.vI1[i], b.vI1[i], b.I1_2, stream);        // I1^2
		gpu::multiply(b.vI1[i], b.vI2[i], b.I1_I2, stream);       // I1 * I2

		//gpu::GaussianBlur(b.vI1[i], b.mu1, Size(11, 11), 1.5, 0, BORDER_DEFAULT, -1, stream);
		//gpu::GaussianBlur(b.vI2[i], b.mu2, Size(11, 11), 1.5, 0, BORDER_DEFAULT, -1, stream);

		gpu::multiply(b.mu1, b.mu1, b.mu1_2, stream);   
		gpu::multiply(b.mu2, b.mu2, b.mu2_2, stream);   
		gpu::multiply(b.mu1, b.mu2, b.mu1_mu2, stream);   

		//gpu::GaussianBlur(b.I1_2, b.sigma1_2, Size(11, 11), 1.5, 0, BORDER_DEFAULT, -1, stream);
		//gpu::subtract(b.sigma1_2, b.mu1_2, b.sigma1_2, stream);
		//b.sigma1_2 -= b.mu1_2;  - This would result in an extra data transfer operation

		//gpu::GaussianBlur(b.I2_2, b.sigma2_2, Size(11, 11), 1.5, 0, BORDER_DEFAULT, -1, stream);
		//gpu::subtract(b.sigma2_2, b.mu2_2, b.sigma2_2, stream);
		//b.sigma2_2 -= b.mu2_2;

		//gpu::GaussianBlur(b.I1_I2, b.sigma12, Size(11, 11), 1.5, 0, BORDER_DEFAULT, -1, stream);
		//gpu::subtract(b.sigma12, b.mu1_mu2, b.sigma12, stream);
		//b.sigma12 -= b.mu1_mu2;

		//here too it would be an extra data transfer due to call of operator*(Scalar, Mat)
		gpu::multiply(b.mu1_mu2, 2, b.t1, stream); //b.t1 = 2 * b.mu1_mu2 + C1; 
		//gpu::add(b.t1, C1, b.t1, stream);
		gpu::multiply(b.sigma12, 2, b.t2, stream); //b.t2 = 2 * b.sigma12 + C2; 
		//gpu::add(b.t2, C2, b.t2, stream);     

		gpu::multiply(b.t1, b.t2, b.t3, stream);     // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))

		//gpu::add(b.mu1_2, b.mu2_2, b.t1, stream);
		//gpu::add(b.t1, C1, b.t1, stream);

		//gpu::add(b.sigma1_2, b.sigma2_2, b.t2, stream);
		//gpu::add(b.t2, C2, b.t2, stream);


		gpu::multiply(b.t1, b.t2, b.t1, stream);     // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2))        
		gpu::divide(b.t3, b.t1, b.ssim_map, stream);      // ssim_map =  t3./t1;

		stream.waitForCompletion();

		Scalar s = gpu::sum(b.ssim_map, b.buf);    
		mssim.val[i] = s.val[0] / (b.ssim_map.rows * b.ssim_map.cols);

	}
	return mssim; 
}</span>


 

 

实现效果:

相关实践学习
在云上部署ChatGLM2-6B大模型(GPU版)
ChatGLM2-6B是由智谱AI及清华KEG实验室于2023年6月发布的中英双语对话开源大模型。通过本实验,可以学习如何配置AIGC开发环境,如何部署ChatGLM2-6B大模型。
相关文章
|
弹性计算 人工智能 Serverless
阿里云ACK One:注册集群云上节点池(CPU/GPU)自动弹性伸缩,助力企业业务高效扩展
在当今数字化时代,企业业务的快速增长对IT基础设施提出了更高要求。然而,传统IDC数据中心却在业务存在扩容慢、缩容难等问题。为此,阿里云推出ACK One注册集群架构,通过云上节点池(CPU/GPU)自动弹性伸缩等特性,为企业带来全新突破。
|
6月前
|
人工智能 并行计算 开发者
CUDA重大更新:原生Python可直接编写高性能GPU程序
NVIDIA在2025年GTC大会上宣布CUDA并行计算平台正式支持原生Python编程,消除了Python开发者进入GPU加速领域的技术壁垒。这一突破通过重新设计CUDA开发模型,引入CUDA Core、cuPyNumeric、NVMath Python等核心组件,实现了Python与GPU加速的深度集成。开发者可直接用Python语法进行高性能并行计算,显著降低门槛,扩展CUDA生态,推动人工智能、科学计算等领域创新。此更新标志着CUDA向更包容的语言生态系统转型,未来还将支持Rust、Julia等语言。
472 3
CUDA重大更新:原生Python可直接编写高性能GPU程序
|
存储 运维 Serverless
函数计算产品使用问题之如何解决代码需要多个gpu的问题
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
监控 异构计算
Jetson 学习笔记(八):htop查看CPU占用情况和jtop监控CPU和GPU
在NVIDIA Jetson平台上使用htop和jtop工具来监控CPU、GPU和内存的使用情况,并提供了安装和使用这些工具的具体命令。
1038 0
|
C++
C++ 根据程序运行的时间和cpu频率来计算在另外的cpu上运行所花的时间
C++ 根据程序运行的时间和cpu频率来计算在另外的cpu上运行所花的时间
164 0
|
机器学习/深度学习 人工智能 并行计算
CPU和GPU的区别
【10月更文挑战第14天】
|
机器学习/深度学习 并行计算 算法
GPU加速与代码性能优化:挖掘计算潜力的深度探索
【10月更文挑战第20天】GPU加速与代码性能优化:挖掘计算潜力的深度探索
|
机器学习/深度学习 人工智能 缓存
GPU加速和CPU有什么不同
【10月更文挑战第20天】GPU加速和CPU有什么不同
539 1
|
调度
CPU调度器实现提示:针对特定体系结构代码【ChatGPT】
CPU调度器实现提示:针对特定体系结构代码【ChatGPT】
|
人工智能 自然语言处理 文字识别
MinerU-大语言语料处理神器,CPU/GPU均可跑,开源免费“敲”好用
在7月4日举行的WAIC 2024科学前沿主论坛上,书生·浦语2.5正式发布,面向大模型研发与应用的全链条工具体系同时迎来升级。
MinerU-大语言语料处理神器,CPU/GPU均可跑,开源免费“敲”好用

热门文章

最新文章