【问题标题】:PSNR values differ in matlab implementation and pythonPSNR 值在 matlab 实现和 python 中不同
【发布时间】:2017-12-10 04:45:28
【问题描述】:

我已经实现了一个 python 代码来计算 YCrCb 通道中 Y 通道的 PSNR 值。 我得到的 PSNR 值约为 35.7dB(对于一对图像)

import cv2, main
import sys

i1 = cv2.imread(sys.argv[1])
i2 = cv2.imread(sys.argv[2])

i1= cv2.cvtColor(i1, cv2.COLOR_BGR2YCrCb)
i2= cv2.cvtColor(i2, cv2.COLOR_BGR2YCrCb)

print(main.psnr(i1[:,:,0], i2[:,:,0]))

在main psnr中定义为:

def psnr(target, ref):
    import cv2
    target_data = numpy.array(target, dtype=numpy.float64)
    ref_data = numpy.array(ref,dtype=numpy.float64)

    diff = ref_data - target_data
    print(diff.shape)
    diff = diff.flatten('C')

    rmse = math.sqrt(numpy.mean(diff ** 2.))

    return 20 * math.log10(255 / rmse)

我在 matlab 中获得了一个在线实现(来自我所指的论文) 我得到的 PSNR 值约为 37.06dB(对于同一对图像)

function psnr=compute_psnr(im1,im2)
if size(im1, 3) == 3,
    im1 = rgb2ycbcr(im1);
    im1 = im1(:, :, 1);
end

if size(im2, 3) == 3,
    im2 = rgb2ycbcr(im2);
    im2 = im2(:, :, 1);
end

imdff = double(im1) - double(im2);
imdff = imdff(:);

rmse = sqrt(mean(imdff.^2));
psnr = 20*log10(255/rmse)

这个错误可能是由于 numpy 引入的错误还是 numpy 似乎可以达到的准确度?

【问题讨论】:

  • 用各种小测试数据运行这两个函数,看看是否有差异。如果是,则调试。例如。 psnr([1], [2])psnr([1, 2], [4, 3]) 或类似的东西。

标签: matlab opencv numpy octave mse


【解决方案1】:

您的两个转换函数似乎产生了截然不同的结果:

Python 输出:

八度输出:

这解释了差异。

Octave 确实提到有几个 YCbCr 标准:

 The formula used for the conversion is dependent on two constants,
 KB and KR which can be specified individually, or according to
 existing standards:

 "601" (default)
      According to the ITU-R BT.601 (formerly CCIR 601) standard.
      Its values of KB and KR are 0.114 and 0.299 respectively.
 "709" (default)
      According to the ITU-R BT.709 standard.  Its values of KB and
      KR are 0.0722 and 0.2116 respectively.

也许 python 版本使用不同的标准? (或者可能是 BGR 与 RGB 的问题?)。无论如何,这就是差异所在,这似乎不是 numpy 精度的问题(当使用相同的输入单独测试这些函数时,它们会产生相同的结果)。

编辑:

根据这些:

python(或者更确切地说,opencv 库)似乎正在输出“模拟”(未缩放)版本,而 matlab / octave 正在输出“数字”(缩放)版本。

已确认:

# Python
RGB = numpy.concatenate(
  ( numpy.array([[[0], [255], [255], [0],   [0],   [0],   [255]]], dtype=numpy.uint8),
    numpy.array([[[0], [0],   [255], [255], [255], [0],   [255]]], dtype=numpy.uint8),
    numpy.array([[[0], [0],   [0],   [0],   [255], [255], [255]]], dtype=numpy.uint8)),
  axis=2)

RGB2Y = cv2.cvtColor(RGB, cv2.COLOR_BGR2YCrCb)
print(RGB2Y)
[[[  0 128 128]
  [ 29 107 255]
  [179   0 171]
  [150  21  43]
  [226 149   1]
  [ 76 255  85]
  [255 128 128]]]
% Octave
pkg load image;
RGB = uint8 (cat (3, [0, 255, 255, 0,   0,   0,   255], ...
                     [0, 0,   255, 255, 255, 0,   255], ...
                     [0, 0,   0,   0,   255, 255, 255]));
RGB2Y = rgb2ycbcr(RGB)
RGB2Y =
 ans(:,:,1) =
   16   81  210  145  170   41  235
 ans(:,:,2) =
   128   90   16   54  166  240  128
 ans(:,:,3) =
   128  240  146   34   16  110  128

因此,如果是为了实现一致性,我会使用上面维基百科页面中提到的从模拟到数字的转换公式来缩放 python 结果,即:

如果是“哪个版本最适合计算 PSNR”的问题,我不知道,但从我在上面的链接中阅读的内容来看,我的钱将用于 matlab / octave实施。

【讨论】:

  • 试过了。问题是 RMSE 本身就是一个 float64。所以它会计算一个浮点数。
  • 我已经确认 opencv 采用 BGR 值(来自他们的示例代码)。也改变了这一点;但结果是一样的。我想将我的 psnr 值(来自 python 代码和标准图像的输出)与在 matlab/octave 中实现的论文中提供的另一组结果进行比较。有什么办法可以解决这个问题,就是写图像文件,然后使用八度来计算psnr?感谢您注意到它。
  • 好吧,就像我说的,“psnr 计算”位在 python 和 octave 中都很好,问题似乎在图像转换阶段之前。但是,是的,如果您想尝试将内容从 python 卸载到 octave,您可以尝试使用oct2py python 模块。我已经更新了答案,提供了有关转换不同原因的更多信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-11
  • 2020-11-29
  • 1970-01-01
  • 1970-01-01
  • 2017-10-01
  • 2014-09-02
  • 1970-01-01
相关资源
最近更新 更多