GPU上的相似度检测(PNSR 和 SSIM)
GPU上的相似度检测(PNSR 和 SSIM)
学习目标
在 OpenCV的视频输入和相似度测量 教程中我们已经学习了检测两幅图像相似度的两种方法:PSNR和SSIM。正如我们所看到的,执行这些算法需要相当长的计算时间,其中SSIM(结构相似度)的算法代价相当高昂。然而,OpenCV现在支持Nvidia的CUDA加速,如果你有一块支持CUDA的的Nvidia显卡。您可以将算法改为使用GPU计算从而大幅提高效率。
本教程将提供一个很好的示例来演示如何让OpenCV来使用GPU这些操作。当然在这之前,你应该了解一下如何操作core,highgui 和imgproc 模块。因此我们的目标是:
- GPU与CPU有什么不同?
- 为PSNR何SSIM编写GPU 代码
- 优化代码以获得最佳性能
源代码
你也可以在OPENCV源库文件夹中 samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity 找到源代码以及一些视频文件或者 从这里下载 。 完整的源码很长(因为其中包含了通过命令行参数进行应用程序和性能测量等无关代码)。因此在这里只出现一部分关键代码。
如果两个输入图像的相似,PSNR 返回一个浮点数在30和50之间,(数值越高,相符程度越高).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
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 |