为什么在Matlab和OpenCV中图像值不同?

时间:2018-09-19 22:23:30

标签: image matlab opencv image-processing

我有原始图片:

enter image description here

然后我阅读它,创建一个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<unsigned int>(r, c)给出

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

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

imwrite(lenablurgray1, 'lenablur.png');

然后在OpenCV中阅读它:

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

然后img.at<double>(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

1 个答案:

答案 0 :(得分:6)

要了解您所看到的差异,您需要了解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<double>()读取它们,则每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。)