【问题标题】:Why image values are different in Matlab and OpenCV?为什么 Matlab 和 OpenCV 中的图像值不同?
【发布时间】:2019-02-24 03:58:39
【问题描述】:

我有一张原图:

然后我阅读它,创建一个 PSF,并在 Matlab 中对其进行模糊处理:

lenawords1=imread('lenawords.bmp');
%create PSF
sigma=6;
PSFgauss=fspecial('gaussian', 8*sigma+1, sigma);

%blur it
lenablur1=imfilter(lenawords1, PSFgauss, 'conv');
lenablurgray1=mat2gray(lenablur1);
PSFgaussgray = mat2gray(PSFgauss);

我保存了模糊的图像:

imwrite(lenablurgray1, 'lenablur.bmp');

当我在其中显示一些值时,我得到

disp(lenablurgray1(91:93, 71:75))

0.5556    0.5778    0.6000    0.6222    0.6444
0.6000    0.6444    0.6667    0.6889    0.6889
0.6444    0.6889    0.7111    0.7333    0.7333

然后我在 OpenCV 中打开该模糊图像并在相同的索引处显示其值:

Mat img = imread("lenablur.bmp");

for (int r = 91; r < 94; r++) {
    for (int c = 71; c < 76; c++) {
        cout << img.at<double>(r, c) << " ";
    }
    cout << endl;
}
cout << endl;

我得到的结果与上面的值不匹配:

0 0 0 0 0
0 0 0 0 0
0 0 0 0 0

这是为什么?

编辑img.at&lt;unsigned int&gt;(r, c)

1903260029 1533437542 ...
2004318088 ...
....

如果我将模糊图像保存为 png 文件:

imwrite(lenablurgray1, 'lenablur.png');

然后当我在 OpenCV 中阅读时:

Mat img = imread("lenablur.png");
img.convertTo(img, CV_64F);

然后img.at&lt;double&gt;(r, c) 给出

17 11 11 11 6
17 11 11 11 6
17 11 11 11 11

仍然与 Matlab 中的值不匹配

EDIT2:我现在看到内核的值是错误的。在 Matlab 中,我得到了

imwrite(PSFgaussgray, 'PSFgauss.bmp');
disp(PSFgaussgray(7:9, 7:9)*256)

.0316 .0513 .0812
.0513 ...
...

而在 OpenCV 中:

Mat kernel = imread("PSFgauss.bmp");
cvtColor(kernel, kernel, cv::COLOR_BGR2GRAY);
kernel.convertTo(kernel, CV_64F);

for (int r = 6; r < 9 ; r++) {
    for (int c = 6; c < 9; c++) {
        cout << kernel.at<double>(r, c) << " ";
    }
    cout << endl;
}
cout << endl;

我得到的结果与上面的值不匹配:

0 0 0
0 0 0
0 0 0

【问题讨论】:

  • 如果您在图像中读取为unsigned char,则不能执行img.at&lt;double&gt;(r, c)(BMP 始终是 8 位无符号整数)。
  • 那我该怎么办?
  • 类型必须与img 对象中存储的数据类型相匹配。请参阅文档:docs.opencv.org/trunk/d3/d63/…
  • 是的,我知道。我在 EDIT 中尝试了一些更改,但这些都不起作用
  • 还有一个更改:MATLAB 索引从 1 开始,OpenCV 的索引从 0 开始。您需要调整您使用的索引。

标签: image matlab opencv image-processing


【解决方案1】:

要了解您看到的差异,您需要了解 MATLAB 如何将图像保存到 BMP 或 PNG 文件,以及 OpenCV 如何读取它。

MATLAB 假设,如果图像的类型是 double,在这种情况下,它的强度范围是 [0,1]。也就是说,不期望低于 0 和高于 1 的像素值。此类图像在保存到文件时会乘以 255 并转换为 8 位整数(范围为 [0,255])。

因此,如果

>> disp(lenablurgray1(91:93, 71:75))
0.5556    0.5778    0.6000    0.6222    0.6444
0.6000    0.6444    0.6667    0.6889    0.6889
0.6444    0.6889    0.7111    0.7333    0.7333

保存的是

>> uint8( lenablurgray1(91:93, 71:75) * 255 )

142   147   153   159   164
153   164   170   176   176
164   176   181   187   187

接下来,OpenCV 会将此文件读取为 RGB(或者更确切地说是 BGR,OpenCV 的尴尬颜色顺序)和 8 位无符号整数 (CV_8U)。要显示这些数据,请提取其中一个颜色通道,或使用

转换为灰度值
cvtColor(img, img, cv::COLOR_BGR2GRAY);

然后,读取 8 位无符号值

img.at<uchar>(r, c)

如果你用img.at&lt;double&gt;()读取它们,8个连续像素组将被视为一个像素值(double有8个字节)。

接下来,请记住 MATLAB 的索引从 1 开始,而 OpenCV 的索引从 0 开始。所以您的循环应该如下所示:

for (int r = 90; r < 93; r++) {     // matches MATLAB's 91:93 indexing
    for (int c = 70; c < 75; c++) { // matches MATLAB's 71:75 indexing
        cout << (int)img.at<uchar>(r, c) << " ";
    }
    cout << '\n';
}
cout << '\n';

最后,对于您的内核,请注意,当它乘以 255 时,它的值仍然远小于统一值:.0316 .0513 .0812。这些值将作为 0 写入 BMP 或 PNG 文件。如果要保存这些值,则需要对内核进行缩放,使其最大值为 1:

PSFgauss = PSFgauss / max(PSFgauss(:));
imwrite(PSFgauss, 'PSFgauss.bmp');

(注意这个内核已经是灰度图了,不需要在上面使用mat2gray。)

【讨论】:

  • 感谢您的澄清。但是,正如我在 EDIT3 中提到的,我现在注意到,当我在 Matlab 中使用 imfilter 和在 OpenCV 中使用 filter2D 时,值不匹配。 filter2D 的值似乎是错误的。这是为什么呢?
  • @user5739619:拜托,拜托,不要把这个问题变成一个移动的目标。请将此最新编辑作为新问题发布,您可以链接此问题以供参考。我很乐意回答。请包含一个 MCVE,目前尚不清楚您将什么用作 filter2D 的输入。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-13
  • 1970-01-01
  • 1970-01-01
  • 2017-11-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多