8

I need to visualize a 2D numpy array. I am using pyplot for this.

Here's the code:

import cv2 as cv
import numpy as np
from matplotlib import pyplot

img = pyplot.imshow( radiance_val )
#radiance_val is a 2D numpy array of size = ( 512, 512 ) 
#filled with np.float32 values

pyplot.show()

I am getting the output as expected.

Now my question is, is there any way of converting "img" in the above code from pyplot type to numpy type. I need this so that I can load the visualization as opencv image and perform further processing on it. I am using python 2.7, 32 bit.


EDIT 1: after Thorsten Kranz's solution

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
import PIL
from cStringIO import StringIO

frame1 = plt.gca()
frame1.axes.get_xaxis().set_visible(False)
frame1.axes.get_yaxis().set_visible(False)
plt.imshow(np.random.random((10,10)))

buffer_ = StringIO()
plt.savefig( buffer_, format = "png", bbox_inches = 'tight', pad_inches = 0 )
buffer_.seek(0)

image = PIL.Image.open( buffer_ )

ar = np.asarray(image)
cv.imshow( 'a', ar )
cv.waitKey(0)
cv.destroyAllWindows()

Here I am getting a runtime error from MS VC++ runtime library after the program terminates. My better guess is that it is because of the open "buffer_". But I am getting the required output.


EDIT 2: closing the buffer using

buffer_.close()

did not solve the runtime error

vvvvv
  • 25,404
  • 19
  • 49
  • 81
Yash
  • 689
  • 4
  • 11
  • 26
  • I added buffer_.close() as mentioned by Thorsten Kranz but the runtime error occurs. – Yash Feb 14 '13 at 09:42

4 Answers4

11

Unless you really need the marker ticks and such,

im._rgba_cache

gives you direct access to the MxNx4 numpy array that is the color mapped data.

If you just want the color mapped data, you can by pass imshow entirely and directly color-map the data your self (see guide for picking your color map)

my_cm = maplotlib.cm.get_cmap('Reds')
normed_data = (data - np.min(data)) / (np.max(data) - np.min(data))
mapped_data = my_cm(normed_data)

which will give you back a MxNx4 array mapped between 0 and 1,

mapped_datau8 = (255 * my_cm(normed_data)).astype('uint8')

or

mapped_data = my_cm(normed_data, bytes=True)

will convert it to unsigned ints.

matplotlib includes a range of normalization code, see here.

get_cmap doc and colormap gallery

edit: fixed oversight pointed out at https://stackoverflow.com/a/14880947/380231

Community
  • 1
  • 1
tacaswell
  • 84,579
  • 22
  • 210
  • 199
  • Wow, your solution preserves the original image dimensions which was my next question. thank you very much. And I am not getting any runtime error too. – Yash Feb 14 '13 at 15:52
  • By the way, its `my_cm = matplotlib.cm.get_cmap('jet')`. And is there any specific purpose for passing `'jet'` in `'my_cm = matplotlib.cm.get_cmap('jet')'` ? I ask because I am getting same output without passing. – Yash Feb 14 '13 at 15:56
  • 1
    if you want to use a different color map ex, `get_cmap('jet_r')` you can call them by name. You get the same thing because if you do not pass an argument it returns the default (which unless you have changed it is `'jet'`). – tacaswell Feb 14 '13 at 16:05
  • `my_cm( data )` is not producing correct map for `numpy.float` data type. Its working fine for `numpy.int` data type. – Yash Feb 14 '13 at 16:51
  • @Yash You should open a new question with that issue. – tacaswell Feb 14 '13 at 17:01
  • 2
    Trying to directly access the numpy array using `im._rgba_cache` throws `AttributeError: 'AxesImage' object has no attribute '_rgba_cache'`. What's that `im` in our first snippet? – FaCoffee Feb 22 '17 at 14:31
  • @FaCoffee Did you ever figure it out? – tejasvi88 Jul 20 '20 at 09:31
  • 1
    As mentioned by @FaCoffee, what is `im` in `im._rgba_cache` in the first line of the answer? – Anirban Chakraborty May 17 '21 at 01:45
5

Ar you sure you want to convert the return value of the method or the whole plot?

For the latter, you should try:

  • Save the plot to a StringIO-buffer image using savefig
  • Load the image from this buffer, using PIL or opencv
  • Convert it to a numpy array

See sample below:

import numpy as np
import matplotlib.pyplot as plt
import PIL
from cStringIO import StringIO

plt.imshow(np.random.random((20,20)))
buffer_ = StringIO()
plt.savefig(buffer_, format = "png")
buffer_.seek(0)
image = PIL.Image.open(buffer_)
ar = np.asarray(image)
buffer_.close()

Look into savefig-*args and **kwargs for more options, e.g., dpi, background color, transparency, padding etc.

If you jsut want the color coded image, without axes, labels, etc., I'd still do the same, just use

plt.subplots_adjust(0,0,1,1)

to extend the axes over the whole figure. Take care of the aspect of you plot, otherwise mpl might shrink your axes again.

Thorsten Kranz
  • 12,492
  • 2
  • 39
  • 56
  • Awesome this worked for me. Thank you very much. I exactly wanted what your solution is providing. I have a problem though. I put the script into a file and executed it. After the program terminates, I get a run-time error from Microsoft VC++ runtime library ( this application has asked the runtime to terminate it in an unusual way ). I have edited my post to include the code. Can you please tell me how to correct it. My better guess is the open "buffer_". But there is no option to close open file in PIL. – Yash Feb 14 '13 at 09:26
  • 1
    buffer_ is a StringIO object, nothing related to PIL. You can release all used resources by calling `buffer_.close()`. Though I'm not sure if this will solve your problem. Nevertheless, before we search on, try this. – Thorsten Kranz Feb 14 '13 at 09:30
  • I included buffer_.close() to no effect. I still am getting a runtime error, same as mentioned before, in my previous comment. Please find the full code in my post. I have edited it after your solution. – Yash Feb 14 '13 at 09:41
  • 1
    You could try to replace `from cStringIO import StringIO` with `from StringIO import StringIO`. This might be a little bit slower (irrelevant here) but reduces dependencies to compiled C code. – Thorsten Kranz Feb 14 '13 at 10:36
  • I must add that no error is being raised if i type in line by line into python IDLE...... . Error occurs only when i put the code into .py file and run it. – Yash Feb 14 '13 at 11:16
  • 1
    Does it also occur if you don't use matplotlib and only put `np.random.random((20,20))` into `cv.imshow`? Maybe setting another mpl backend can help, e.g. `import matplotlib; matplotlib.use("Agg")` at the beginnig of your script. – Thorsten Kranz Feb 14 '13 at 11:26
  • cv.imshow works only with 'uint8' data type which is unlike the data type returned by np.random.random((20,20)). And I tried setting another mpl backend as you suggested. The runtime error still persists but I am getting the correct putput. I think its some kind of bug. I will post it on [bugs.python.org](http://bugs.python.org) – Yash Feb 14 '13 at 13:56
0

Updated answer inspired from @Thorsten Kranz

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import io
plt.imshow(np.random.random((20,20)))
with io.BytesIO() as buffer:
    plt.savefig(buffer, format = "png")
    buffer.seek(0)
    image = Image.open(buffer)
    ar = np.asarray(image)
print(ar.shape)
Talha Anwar
  • 2,699
  • 4
  • 23
  • 62
0

here I found a much more sample to convert an array to rgba, I wanted to convert the spectrogram to rgb images with the magma cmap, and here's what I did;

import matplotlib.cm as cm
sm = cm.ScalarMappable(cmap='magma')
sm.set_clim(spect.min(), spect.max())
im = sm.to_rgba(spect)

plt.imshow(im)
plt.title(im.shape)

enter image description here

Walid Bousseta
  • 1,329
  • 2
  • 18
  • 33