7

I need to analyze a part of an image, selected as a submatrix, in a tif file. I would like to have the image in raw format, with no frills (scaling, axis, labels and so on)... How could I do that?

This is the code I am using now:

 submatrix = im[x_min:x_max, y_min:y_max]
 plt.imshow(submatrix)
 plt.savefig("subplot_%03i_%03i.tif" % (index, peak_number), format = "tif")
Janne Karila
  • 24,266
  • 6
  • 53
  • 94
albus_c
  • 6,292
  • 14
  • 36
  • 77
  • I suppose `plt` is `matplotlib.pyplot`. – Janne Karila Oct 30 '13 at 07:56
  • 1
    There might be something helpful over [here](http://stackoverflow.com/questions/8218608/scipy-savefig-without-frames-axes-only-content) – Matthew Wesly Oct 30 '13 at 08:00
  • possible duplicate of [Matplotlib plots: removing axis, legends and white spaces](http://stackoverflow.com/questions/9295026/matplotlib-plots-removing-axis-legends-and-white-spaces) – Janne Karila Oct 30 '13 at 08:02
  • Thanks Matthew, that worked. Does someone have an idea on why there are many more pixels than expected? I would like to have one pixel per value, in the range [x_min:x_max, y_min:y_max] – albus_c Oct 30 '13 at 11:06

1 Answers1

9

First off, if you're just wanting to store the raw values or a grayscale representation of the raw values, it's easiest to just use PIL for this.

For example, this will generate a 10x10 grayscale tif file:

import numpy as np
import Image

data = np.random.randint(0, 255, (10,10)).astype(np.uint8)
im = Image.fromarray(data)
im.save('test.tif')

As far as your question about why the matplotlib version has more pixels, it's because you implictly told it to. Matplotlib figures have a size (in inches) and a dpi (by default, 80 on-screen and 100 when saved). Also, by default imshow will interpolate the values in your array, and even if you set interpolation to nearest, the saved image will still be the size you specified for the figure.

If you want to use matplotlib to save the figure at one-value-to-one-pixel (for example, to allow easy use of colormaps), do something similar to this:

import numpy as np
import matplotlib.pyplot as plt

dpi = 80 # Arbitrary. The number of pixels in the image will always be identical
data = np.random.random((10, 10))

height, width = np.array(data.shape, dtype=float) / dpi

fig = plt.figure(figsize=(width, height), dpi=dpi)
ax = fig.add_axes([0, 0, 1, 1])
ax.axis('off')

ax.imshow(data, interpolation='none')
fig.savefig('test.tif', dpi=dpi)
Joe Kington
  • 275,208
  • 71
  • 604
  • 463
  • I made the changes suggested by Joe and I got the following error: "ValueError: too many values to unpack" for height, width = np.array(data.shape, dtype=float) / dpi. What should I change? – albus_c Nov 01 '13 at 09:39
  • @albus_c - It sounds like you have a 3d array? What does `data.shape` look like? If it's a 3D array, you'd want to do something like `height, width, nbands = ...`. – Joe Kington Nov 01 '13 at 14:28
  • @albus_c - Also, if you're dealing with a multiband image, just save it to a tif directly using `Image` (a.k.a. "PIL"). I was assuming that you wanted to color a single-band image according to a colormap (which can be done with PIL as well, by the way, but it's more difficult to build the colormap). – Joe Kington Nov 01 '13 at 14:30
  • Thanks for the tips! I am happy with the colour images I got now (I need them just to check that I am considering the right regions) – albus_c Nov 03 '13 at 11:10
  • 1
    With PILLOW (which is intended to replace PIL), the package is installed with `pip install PILLOW` and imported with `from PIL import Image`. You need to convert images into a 0-255 range uint8 format (as in the example) and flatten single-channel images to two dimensions. The rest goes as the PIL example here. – Josiah Yoder Aug 28 '19 at 20:40