如何使用 OpenCV 显示 PGM 图像

How to display PGM image using OpenCV

我正在尝试使用适用于 C++ 的 OpenCV(2.4.0) 加载和显示 .PGM 图像。

void open(char* location, int flag, int windowFlag)
{
    Mat image = imread(location, flag);
    namedWindow("Image window", windowFlag);
    imshow("Image window", image);
    waitKey(0);
}

我是这样打开的:

open("./img_00245_c1.pgm", IMREAD_UNCHANGED, CV_WINDOW_AUTOSIZE);

问题是打开 window 时显示的图像比我用 IrfanView 打开文件时显示的图像暗。 另外,如果我尝试将此图像写入另一个文件,如下所示:

Mat imgWrite;
imgWrite = image;
imwrite("newImage.pgm", imgWrite)

我会得到一个与原始文件内容不同的文件内容,IrfanView 会在我的函数显示时使用 imshow 显示它。

.PGM 文件的 imread 中是否有不同的标志,以便我可以显示和保存原始文件?

编辑: 图片 pgm file

编辑 2 : 指出:IrfanView 将图像标准化为最大像素值 255 。 为了使用 OpenCV 清楚地看到图像,我还应该在加载到 Mat 时对图像进行归一化。这是否可以直接使用 OpenCV 函数而不遍历像素并修改它们的值?

问题不在于数据加载的方式,而在于它们显示的方式。

您的图片是 CV_16UC1imshowimwrite 都将原始范围 [0, 65535] 的值标准化到 [0, 255] 范围以适应CV_8U.

类型的范围

因为您的 PGM 图片有 max_value4096:

P2        
1176 640  // width height
4096      // max_value 

它应该从范围 [0, 4096] 而不是 [0, 65535] 进行标准化。 你可以这样做:

Mat img = imread("path_to_image", IMREAD_UNCHANGED);
img.convertTo(img, CV_8U, 255.0 / 4096.0);

imshow("Image", img);
waitKey();

请注意,您图片中的值范围不对应 [0, 4096],而是:

double minv, maxv;
minMaxLoc(img, &minv, &maxv);

// minv = 198
// maxv = 2414

所以 [0,255] 中的直接标准化就像:

normalize(img, img, 0, 255, NORM_MINMAX);
img.convertTo(img, CV_8U);

不会工作,因为它会生成比应有的更亮的图像。


这意味着要正确地显示您的图像,您需要知道max_value(这里是4096)。如果它每次都改变,您可以通过解析 .pgm 文件来检索它。

同样,这只是 可视化 的问题。数据正确。