2

我找到了用 C++ 编写的 OpenCV 中 PSNR 的实现,但是我在 JavaCV 中实现它时遇到了麻烦。

http://docs.opencv.org/doc/tutorials/highgui/video-input-psnr-ssim/video-input-psnr-ssim.html#image-similarity-psnr-and-ssim

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;
 }
}

例如:

  • 什么是垫型?它与 JavaCV 中的 MatVector 相同吗?
  • 如何为 MatVector 做 absdiff?
  • 我找不到标量类型。
  • 如何求和(s1)?

谢谢并恭祝安康,

杰森

4

2 回答 2

1

在这种情况下,Mat 是图像中的 RGB 值数组。在这种情况下,标量是 3 个数字的列表。

absdiff(I1, I2, s1) 是说您从具有彩色/灰度/rgba 通道等的第一张图像(I1) 中取出一个像素,然后从图像 2(I2) 中的像素中减去它,取绝对值差异,然后将其作为第一个元素存储在您分配的 Matrix/Array(s1) 中。如果你有一个 rgb 图像,你会得到绝对差异 |R1-R2|,|G1-G2|,|B1-B2| 并存储这 3 个值,其中 1 来自图像 1,2 来自图像 2,对所有像素都这样做。

sum(s1) 是什么意思,在 s1 中存储两个图像的颜色差异,将所有红色值相加,将所有蓝色值相加,并将所有绿色值相加,并返回 3 个数字的列表表示每种颜色的总和。

只需将 RGB 替换为 YMK 或您可能正在使用的任何其他东西。

有关包括 Matrix 和 Scalar 在内的基本类型的更多信息,请参见此处的 opencv 文档:http: //opencv.willowgarage.com/documentation/cpp/basic_structures.html,并且可以在此文件和目录附近找到一些代码:https: //github.com/Itseez/opencv/blob/master/modules/core/include/opencv2/core/types_c.h

“Mat 类表示一个 2D 数值数组,可以充当矩阵(进一步称为矩阵)、图像、光流图等。它与 OpenCV 早期版本的 CvMat 类型非常相似,也类似于 CvMat ,矩阵可以是多通道的,但它也完全支持 ROI 机制,就像 IplImage 一样。”

于 2013-06-02T21:00:13.810 回答
0

我遇到了同样的问题,并使用 JavaCV 将上面的代码翻译成 Java。这是我的代码:

private static double getPSNR(CvMat I1, CvMat I2) {     
    CvMat s1 = CvMat.create(I1.rows(), I1.cols(), I1.depth(), I1.nChannels()); //create matrix with same size as I1
    cvAbsDiff(I1, I2, s1); // |I1 - I2|

    CvMat s1_squared = cvCreateMat(s1.rows(), s1.cols(), CV_32FC3); //convert mat to 32bit and 3 channels
    cvMul(s1, s1, s1_squared, 1); // |I1 - I2| ^2

    CvScalar scalar = cvSum(s1_squared); // sum elements per channel
    double sse = scalar.getVal(0) + scalar.getVal(1) + scalar.getVal(2); // sum channels

    double mse = sse / (double) (s1.channels() * s1.total());
    double psnr = 10.0 * Math.log10((255*255) / mse);

    return psnr;
}
于 2013-10-10T08:15:32.443 回答