1

I am writing pgm using opencv using python as follows...

   cv.SaveImage("a.pgm",np.array(image.astype(np.uint16)))

So, I am casting my data to be unsigned 16 bits. The prob is that the maximum value of the gray level is set to 65535 while the pgm is written, my data has a maximum value of 1103.

What i guess is that when we are saving the pgms in opencv the value is calculated by the datatype and set to max, not based on the actual data.

Could someoone help in telling that how to do it so that the correct value of the max gray level is written.

Thanks a lot.

Shan
  • 18,563
  • 39
  • 97
  • 132

2 Answers2

0

You just need to multiply your image by a conversion factor before you save. In your case the factor will be 65535 / 1103. You can use ConvertScale to do this, it lets you multiple an array by a scalar. Like this:

cv.ConvertScale(im, im, scale=65535 / 1103.0)
fraxel
  • 34,470
  • 11
  • 98
  • 102
  • Hi, Fraxel, the prob is that I am not sure at the moment, because , I dont want to change the actual contents of the image... After convert scale when I read the file, do I get the same values or does it need to be scaled again? – Shan May 15 '12 at 13:54
  • @Shan - Why don't you keep the original, and make a scaled copy too, that way you have both. I guess it all depends on what you are trying to do, and what the data/image is for. – fraxel May 15 '12 at 14:03
  • Well, the thing is, the content should remain original, no scaled version. The only prob is that when setting the maximum value opencv looks at the data type regardless of the contents, so to be clear the original contents with original highest value must be written. – Shan May 15 '12 at 14:09
0

This is somewhat hacky, use at your own risk. I would prefer if OpenCV could solve this natively. The default implementation causes all kinds of trouble if you don't completely fill your 16-bit range (low contrast in Irfanview etc.).

def write_pgm_realmax(path, img):
    maxval = img.max()
    cv2.imwrite(path, img)
    with open(path, 'rb') as fid:
        s = fid.read()
    # the 1 makes sure we replace only the first occurrence.
    s = s.replace(b'\n65535\n', b"\n" + str(maxval) + "\n", 1)
    with open(path, 'wb') as fid:
        fid.write(s)

The code is probably not super-robust nor extremely performant, but it is a place to start. It saves the pgm with OpenCV, then opens the file again an replaces the first single-line string "65535" (the maximum possible uint16 value) by the actual maximum value.

Cerno
  • 751
  • 4
  • 14