Why do Octave and MATLAB both automatically shift the gray values in this image?
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.