How to display PGM image using OpenCV

John Smith picture John Smith · Nov 20, 2015 · Viewed 7.8k times · Source

I'm trying to load and display a .PGM image using OpenCV(2.4.0) for C++.

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

I'm calling open like this:

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

The problem is that the image shown when the window is opened is darker than if I'm opening the file with IrfanView. Also if I'm trying to write this image to another file like this:

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

I will get a different file content than the original one and IrfanView will display this as my function displays with imshow.

Is there a different flag in imread for .PGM files such that I can get the original file to be displayed and saved ?

EDIT: Image pgm file

EDIT 2 : Remarked that: IrfanView normalizes the image to a maximum pixel value of 255 . In order to see the image clearly using OpenCV I should normalize the image also when loading in Mat. Is this possible directly with OpenCV functions without iterating through pixels and modifying their values ?

Answer

Miki picture Miki · Nov 22, 2015

The problem is not in the way data are loaded, but in the way they are displayed.

Your image is a CV_16UC1, and both imshow and imwrite normalize the values from original range [0, 65535] to the range [0, 255] to fit the range of the type CV_8U.

Since your PGM image has max_value of 4096:

P2        
1176 640  // width height
4096      // max_value 

it should be normalized from range [0, 4096] instead of [0, 65535]. You can do this with:

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

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

Please note that the values range in your image doesn't correspond to [0, 4096], but:

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

// minv = 198
// maxv = 2414

So the straightforward normalization in [0,255] like:

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

won't work, as it will produce an image brighter than it should be.


This means that to properly show your image you need to know the max_value (here 4096). If it changes every time, you can retrieve it parsing the .pgm file.

Again, it's just a problem with visualization. Data are correct.