Why do Octave and MATLAB both automatically shift the gray values in this image? Edit: I found this other question that actually addressed a separate but possibly related problem I was experiencing. However, in the below case the image is in uint8 when read into both Octave and MATLAB so it doesn't actually address this specific problem.

I'm going through the Scientist and Engineer's Guide to Digital Signal Processing and experimenting with the image manipulation examples given later in the chapter. But I've run into an odd issue that is grinding my progress to a halt because it makes it impossible to predict what will happen.

I've used Octave from the start, but today downloaded a trial of MATLAB and it does the exact same thing.

Here's an example. I created a test image to experiment with grayscale transforms. Here is the original PNG:



In Octave I run the following code:

&gt;&gt; dots3 = imread('dots_3gray.png');
&gt;&gt; imshow(dots3);


And I get this as the result:



As you can see the values are all shifted -- the image as displayed by Octave (and also MATLAB) has downshifted all the values so the whites are now dark gray and the grays are now black. (ignore the size difference, the second is a screen capture) Both are 100x100 pixel grayscale images. The min value in the matrix as it is read in by Octave is 0 and the max value is 158.

Interestingly, using the eyedropper tool in Paint.NET I checked the range of values in the original PNG and the min value (in the center of a gray dot) is 96 and the max value (in the white field) is 255 -- a difference of 159 which is oddly enough exactly the number of steps in the range of numbers [0, 158] reported in dots3 as read by Octave. So some sort of shifting certainly appears to be going on here.

I can get the image to display with the correct colors by shifting the pixel values by 97, the difference between 255 and 158:

&gt;&gt; imshow(dots3 + 97)


Any idea why this behavior is happening? It makes it extremely difficult for me to experiment with the algorithms because I can't know if a change is caused by the code or by Octave / MATLAB doing this on its own.

Platform is Windows 10. Thanks.
Your image is an indexed image. Meaning it takes integer values that are supposed to be mapped to colours on screen via a particular colourmap.

You can see this if you read your image in as:

[I, M] = imread('dots_3gray.png');


where I becomes your 'indexed' image (which seems to contain indices from 0 to 158), and M is the colormap used to interpret it.

If you look at the documentation of imshow you will see that for indexed images specifically, you can specify which colourmap to use; in this case M to view it as expected:

imshow(I, M)


If you don't want this to be an indexed image, and you'd prefer to convert it to a standard grayscale image (i.e. in the range [0,1]) so that you can process it further, you can perform this conversion using the ind2gray command:

G = ind2gray (I,M); % convert to uint8 grayscale image in the range [0,255]
G = im2double (G);  % convert to double precision image in the range [0,1]




See my answer to a similar question in stackoverflow for more info.