如何使用OpenCV显示PGM图像

5

我正在尝试使用OpenCV(2.4.0) for C++加载和显示.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:

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

问题在于打开窗口时显示的图像比使用IrfanView打开文件时更暗。此外,如果我尝试将此图像写入另一个文件,就像这样:
Mat imgWrite;
imgWrite = image;
imwrite("newImage.pgm", imgWrite)

我将获得一个不同于原始文件内容的文件,并且IrfanView将像我的函数显示imshow一样显示它。
是否有一个不同的imread标志用于.PGM文件,以便我可以获取原始文件以进行显示和保存?
编辑:图像pgm文件 编辑2:注意到:IrfanView将图像归一化为最大像素值255。为了使用OpenCV清晰地查看图像,加载到Mat中时也应该对图像进行归一化。这是否可以直接使用OpenCV函数实现,而无需迭代像素并修改其值?

1
也许Irfanview正在自动规范化,即对您的图像进行对比度拉伸,而OpenCV则没有...也许尝试在Irfanview中保存一个经过规范化、对比度拉伸的图像,并将其加载到OpenCV中,或者在显示之前在OpenCV中拉伸一个暗色图像。 - Mark Setchell
1
也许你可以在这里找到答案(点击 COMPATIBILITY 查看):http://netpbm.sourceforge.net/doc/pgm.html。你能给出你的PGM文件链接吗? - sturkmen
我已经添加了照片的链接! - John Smith
该链接指向一个PNG文件。 - Mark Setchell
现在试试,我上传文件的网站已经改变了。 - John Smith
1个回答

2
问题不在于数据的加载方式,而在于它们的显示方式。
您的图像是CV_16UC1类型,imshow和imwrite都将原始范围[0, 65535]的值标准化为范围[0, 255]以适应CV_8U类型的范围。
由于您的PGM图像的最大值为4096:
P2        
1176 640  // width height
4096      // max_value 

应该将范围从[0, 65535]规范化为[0, 4096]

您可以使用以下方法实现:

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文件来检索它。

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


我想支持这个答案。我刚刚使用opencv将一个16位的pgm转换成了一个16位的tif(只需调用imread(..., -1), imwrite(...))。在使用两个不同的工具(IrfanView和Beyond Compare图像查看器)打开两个图像后,两者之间显示出了差异。但是当我使用opencv重新打开这两个图像时,像素值是相同的。你必须考虑到很多图像处理工具不支持16位图像。因此,数据是正确的,但可视化可能不正确。 - Cerno

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接