imshow without resampling

Hi,
I found this old thread discussing the possibility of placing un-resampled images in PS, PDF and SVG. It was questioned weather there were any potential users for such a feature to justify the effort. If it makes a difference, here is one user who very much welcome it.
I need to overlay plotting onto images without the degradation cause by resampling. Is this possible? Currently I use interpolation='nearest' and a high DPI setting for savefig, but this is not ideal.
Thanks for any help,
Geoff

Re: imshow without resampling
by Jouni K. Seppänen Apr 05, 2009; 03:13am
Eric Firing <efiring@...83...> writes:

> I'm not sure who the SVG expert is, and I presume the attached message
> applies to pdf as well as ps. I'm bringing it to your attention
> because it is suggesting what would seem to be significant
> improvements in some backends by taking better advantage of their
> native image support. I know nothing about this; would either of you
> (or anyone else) like to comment?

Thanks for forwarding this Eric - yes, it applies to pdf.

> From: Thomas Robitaille <thomas.robitaille@...83...>

> I am using matplotlib to create postscript and SVG files. I am
> currently using imshow to show the contents of an array, but this
> means that when saving vector graphics files, matplotlib resamples the
> image/array onto a finer grid. [...] Postscript and SVG (as languages)
> both allow a bitmap of an arbitrary resolution to be scaled,
> translated, and rotated without resampling.

This is complicated by the wide variety of interpolation methods offered
by imshow:

         Acceptable values are *None*, 'nearest', 'bilinear',
           'bicubic', 'spline16', 'spline36', 'hanning', 'hamming',
           'hermite', 'kaiser', 'quadric', 'catrom', 'gaussian',
           'bessel', 'mitchell', 'sinc', 'lanczos',

where None means to use the matplotlibrc value, and I think the default
is bicubic. The 'nearest' case is what you get by simply scaling the
original bitmap, so in that case all vector backends could probably
support skipping the interpolation step. The other interpolation methods
could be programmed in Postscript, but that doesn't help with other
backends - though perhaps PDF shadings (gradient fills) could be hacked
to do this. I don't know anything about SVG.

I wonder how the API between the backend and the image object should
look like. Currently the AxesImage object does essentially

         im = self.make_image(renderer.get_image_magnification())
         renderer.draw_image(round(l), round(b), im, self.axes.bbox.frozen(),
                             clippath, affine)

and then the backend does things like

         h, w = im.get_size_out()
         [...]
         h,w,s = im.as_rgba_str()
         rgba.shape = (h, w, 4)
         rgb = rgba[:,:,:3]
         a = rgba[:,:,3:]

Instead, I suppose AxesImage needs to first query the renderer if it
supports the interpolation being used, and if so, call a new renderer
method, say draw_interpolated_image(im). Or perhaps it could just call
the new method, and its implementation in RendererBase would fall back
to interpolating the image and calling the old draw_image. Vector
backends could override it to be smarter when possible.

A possibly related thought: the pdf backend could render some kinds of
image files by passing through the encoded image data from the original
file, so when e.g. image_demo3.py does

         lena = Image.open('../data/lena.jpg')
         im = imshow(lena, origin='lower')

the pdf backend could try to read the JPEG file directly, and only
decode it into a bitmap if it happens to be a wrong subtype of JPEG. For
someone who's using big image files, this would decrease both rendering
time and output size, but I don't know if there are any actual users and
if the benefit is large enough to justify the added complexity - but if
we modify the API anyway to support non-resampling imshow, it might be
good to keep that use-case in mind.

···

--
Jouni K. Seppänen
http://www.iki.fi/jks

Hi there,

Finally with lot of try I've finally managed to make blitting of a cmap
working.
I've also patched QT4agg backend, to make a redraw immediately.
(replaced self.draw by self.repaint)
In my current project I was able to stream a 655KB network stream, do
demodulation of an IQ stream and display the spectrogram in real time (4096
pixel per 1024) with matplotlib and QT4 backend, thx to the patch + blitting
example attached.

Without patch, the refrech was veeery long. (waiting for QT loop to execute
code wen it wanted.)
And do NOT always work. If you've got a powerfull pc you've got chance to
see only white background...
(or simply the loop timer to 0, you will see that without patch blit does
not work).

Only tested under windows currently, 'cause my project is on windows
currently...

There is one bug in the example, that I didn't manage to correct yet.
Depending on screen resolution, the color of the cmap blitted area can be
kind of alpha'ed. (that is look like a little bit transparent...) , Any idea
on the root of this issue?

By the way to make the example work I needed to do this:
        self.ax2.draw_artist(self.line2)
        self.blit(self.ax2.bbox)
        self.restore_region(self.background2)

that is blit before restore... don't understand why yet.

Any comment welcomed.

Is there any chance, after review, to find a way to include this in main
trunk?
What do think about this?

Cheers,
Laurent

backend_qt4agg.py (4.69 KB)

animation_blit_qt4_v7.py (3.91 KB)

I'm not able to comment on the other questions you raised, but the
change to backend_qt4agg.py improved the behavior of the existing qt4
blit example (without your changes the axes labels were not drawn on
my machine), so I checked the change into the trunk. Thank you!

Darren

···

On Mon, Nov 30, 2009 at 7:01 PM, Laurent Dufrechou <laurent.dufrechou@...287...> wrote:

Hi there,

Finally with lot of try I've finally managed to make blitting of a cmap
working.
I've also patched QT4agg backend, to make a redraw immediately.
(replaced self.draw by self.repaint)
In my current project I was able to stream a 655KB network stream, do
demodulation of an IQ stream and display the spectrogram in real time (4096
pixel per 1024) with matplotlib and QT4 backend, thx to the patch + blitting
example attached.

Without patch, the refrech was veeery long. (waiting for QT loop to execute
code wen it wanted.)
And do NOT always work. If you've got a powerfull pc you've got chance to
see only white background...
(or simply the loop timer to 0, you will see that without patch blit does
not work).

Only tested under windows currently, 'cause my project is on windows
currently...

There is one bug in the example, that I didn't manage to correct yet.
Depending on screen resolution, the color of the cmap blitted area can be
kind of alpha'ed. (that is look like a little bit transparent...) , Any idea
on the root of this issue?

By the way to make the example work I needed to do this:
self.ax2.draw_artist(self.line2)
self.blit(self.ax2.bbox)
self.restore_region(self.background2)

that is blit before restore... don't understand why yet.

Any comment welcomed.

Is there any chance, after review, to find a way to include this in main
trunk?
What do think about this?