Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invert the y-axis of an image without flipping the image upside down

I'm trying to do some image processing with matplotlib. However the y-axis is decreasing bottom up. I want it to be increasing bottom up without flipping the image upside down

I have the following code

import matplotlib.pyplot as plt
import numpy as np
img_path = '/path/to/image.tif'
img = plt.imread(img_path)
plt.imshow(img, cmap = 'gray')

it produces the following image: enter image description here

The images can be obtained there

I tried plt.gca().invert_yaxis() without success

What shall I do

like image 422
ecjb Avatar asked Jul 06 '19 18:07

ecjb


1 Answers

The default behavior of imshow is to put the origin of the coordinate system in the upper left corner. This is different from plotting scientific data, such as two entities x and y against each other, where the origin, i.e. the point corresponding to the coordinate (0,0), is in the lower left corner, with the (positive) x-axis extending to the right and the (positive) y-axis extending towards the top.

The latter is just scientific convention, though one that goes back centuries. Arguably (albeit near impossible to back up with historical evidence), the x-axis is traditionally aligned left-to-right because that's how text is written in many languages, while the y-axis is oriented towards the top as that's how people intuit an increase — much like the elevation of terrain.

For images, on the other hand, the existing convention is rooted in the memory layout of pixel data and the way one might arrange consecutive pixels on the canvas: from left to right on the first line (by the same logic as above), then from the left again on the next line, and so on for all other lines, going from top to bottom. Just like words arranged on a page — in languages written from left to right and, much more universally so, top to bottom.

It is for that reason that the y-axis in your image is oriented the way it is. To have the y-values increase from the bottom up, you could invoke the option origin='lower' so that the input data is interpreted as per the scientific convention. However, you then also need to flip the image's lines upside down so that, when displayed on the screen, the image appears in its intended orientation. That's because what used to be the first line when the image was loaded into memory now corresponds to the last y-coordinate, the one at the top.

Bottom line (pun not unintended), just call imshow like so in the above code:

plt.imshow(np.flipud(img), cmap='gray', origin='lower')

To illustrate further, here is a self-contained example that demonstrates the behavior:

from imageio import imread
image = imread('https://upload.wikimedia.org/wikipedia/commons'
               '/thumb/6/6a/Mona_Lisa.jpg/158px-Mona_Lisa.jpg')

from matplotlib import pyplot
figure = pyplot.figure(tight_layout=True)
(axes1, axes2, axes3) = figure.subplots(nrows=1, ncols=3)

axes1.set_title("origin='upper'")
axes1.imshow(image)

axes2.set_title("origin='lower'")
axes2.imshow(image, origin='lower')

axes3.set_title("'lower' + flipped")
axes3.imshow(image[::-1], origin='lower')

pyplot.show()

The example requires ImageIO to be installed in order to retrieve the sample image. Its output is:

output of demo script

(In the example's code, I used image[::-1] to flip the image, instead of the aforementioned, and equivalent, syntax np.flipud(image). All that does is avoid an explicit import of NumPy (as np), i.e., an extra line of code. Implicitly, NumPy is still doing the work.)

Similar questions:

  • Matplotlib inverted image
  • How to use "extent" in matplotlib.pyplot.imshow
  • How to make imshow read (x,y) coordinates from other Numpy arrays
  • Why does imshow's extent argument flip my images?
  • Matlab image and plot with unexpected flip
like image 178
john-hen Avatar answered Nov 13 '22 09:11

john-hen