Take a look at this post in particular. I've experienced similar issues with imread
and with Java's ImageIO
class and for the longest time, I could not find this link as proof that other people have experienced the same thing... until now. Similarly, someone experienced related issues in this post but it isn't quite the same at what you're experiencing.
Essentially, the reason why images loaded in both Java and MATLAB are different is due to enhancement purposes. MATLAB scales the intensities so the image isn't mostly black. Essentially, the maximum intensity in your PGM gets scaled to 255
while the other intensities are linearly scaled to suit the dynamic range of [0,255]
. So for example, if your image had a dynamic range from [0-100]
in your PGM file before loading it in with imread
, this would get scaled to [0-255]
and not be the original scale of [0-100]
. As such, you would have to know the maximum intensity value of the image before you loaded it in (by scanning through the file yourself). That is very easily done by reading the third line of the file. In your case, this would be 156
. Once you find this, you would need to scale every value in your image so that it is rescaled to what it originally was before you read it in.
To confirm that this is the case, take a look at the first pixel in your image, which has intensity 21 in the original PGM file. MATLAB would thus scale the intensities such that:
scaled = round(val*(255/156));
val
would be the input intensity and scaled
is the output intensity. As such, if val = 21
, then scaled
would be:
scaled = round(21*(255/156)) = 34
This matches up with the first pixel when reading it out in MATLAB. Similarly, the sixth pixel in the first row, the original value is 18. MATLAB would scale it such that:
scaled = round(18*(255/156)) = 29
This again matches up with what you see in MATLAB. Starting to see the pattern now? Basically, to undo the scaling, you would need to multiply by the reciprocal of the scaling factor. As such, given that A
is the image you loaded in, you need to do:
A_scaled = uint8(double(A)*(max_value/255));
A_scaled
is the output image and max_value
is the maximum intensity found in your PGM file before you loaded it in with imread
. This undoes the scaling, as MATLAB scales the images from [0-255]
. Note that I need to cast the image to double
first, do the multiplication with the scaling factor as this will most likely produce floating point values, then re-cast back to uint8
. Therefore, to bring it back to [0-max_value]
, you would have to scale in the opposite way.
Specifically in your case, you would need to do:
A_scaled = uint8(double(A)*(156/255));
The disadvantage here is that you need to know what the maximum value is prior to working with your image, which can get annoying. One possibility is to use MATLAB and actually open up the file with file pointers and get the value of the third line yourself. This is also an annoying step, but I have an alternative for you.
Alternative... probably better for you
Alternatively, here are two links to functions written in MATLAB that read and write PGM files without doing that unnecessary scaling, and it'll provide the results that you are expecting (unscaled).
How the read function works is that it opens up the image using file pointers and manually parses in the data and stores the values into a matrix. You probably want to use this function instead of relying on imread
. To save the images, file pointers are again used and the values are written such that the PGM standard is maintained and again, your intensities are unscaled.