Dear developers,
matplotlib offers high quality interpolation filters which give
excellent results if you scale up an image. However, for downscaling an
image the results are worse. Depending on the precise scaling fine
details (e.g., thin horizontal lines, single pixel points) disappear and
aliasing effects are visible. After studying the source and the docs for
Agg I figured out how to improve this. Agg provides all possibilities,
just use them.
I attached a patch against the current svn version that adds a
'resample' argument to imshow. Additionally, this patch supports a
'image.resample' entry in the rc file. Setting this to false (default),
the behaviour is unchanged.
I also attached a simple test script (test_imshow.py) to show the
difference between image display with and without resampling. To see the
difference it might be necessary to zoom out.
Gregor Thalhammer
Index: src/_image.cpp
===================================================================
--- src/_image.cpp (Revision 5430)
+++ src/_image.cpp (Arbeitskopie)
@@ -426,11 +426,22 @@
case HAMMING: filter.calculate(agg::image_filter_hamming(), norm);
break;
case HERMITE: filter.calculate(agg::image_filter_hermite(), norm);
break;
}
- typedef agg::span_image_filter_rgba_2x2<img_accessor_type,
interpolator_type> span_gen_type;
- typedef agg::renderer_scanline_aa<renderer_base, span_alloc_type,
span_gen_type> renderer_type;
- span_gen_type sg(ia, interpolator, filter);
- renderer_type ri(rb, sa, sg);
- agg::render_scanlines(ras, sl, ri);
+ if (resample)
+ {
+ typedef agg::span_image_resample_rgba_affine<img_accessor_type>
span_gen_type;
+ typedef agg::renderer_scanline_aa<renderer_base, span_alloc_type,
span_gen_type> renderer_type;
+ span_gen_type sg(ia, interpolator, filter);
+ renderer_type ri(rb, sa, sg);
+ agg::render_scanlines(ras, sl, ri);
+ }
+ else
+ {
+ typedef agg::span_image_filter_rgba_2x2<img_accessor_type,
interpolator_type> span_gen_type;
+ typedef agg::renderer_scanline_aa<renderer_base, span_alloc_type,
span_gen_type> renderer_type;
+ span_gen_type sg(ia, interpolator, filter);
+ renderer_type ri(rb, sa, sg);
+ agg::render_scanlines(ras, sl, ri);
+ }
}
break;
case BILINEAR:
@@ -464,11 +475,22 @@
case LANCZOS: filter.calculate(agg::image_filter_lanczos(radius),
norm); break;
case BLACKMAN: filter.calculate(agg::image_filter_blackman(radius),
norm); break;
}
- typedef agg::span_image_filter_rgba<img_accessor_type,
interpolator_type> span_gen_type;
- typedef agg::renderer_scanline_aa<renderer_base, span_alloc_type,
span_gen_type> renderer_type;
- span_gen_type sg(ia, interpolator, filter);
- renderer_type ri(rb, sa, sg);
- agg::render_scanlines(ras, sl, ri);
+ if (resample)
+ {
+ typedef agg::span_image_resample_rgba_affine<img_accessor_type>
span_gen_type;
+ typedef agg::renderer_scanline_aa<renderer_base, span_alloc_type,
span_gen_type> renderer_type;
+ span_gen_type sg(ia, interpolator, filter);
+ renderer_type ri(rb, sa, sg);
+ agg::render_scanlines(ras, sl, ri);
+ }
+ else
+ {
+ typedef agg::span_image_filter_rgba<img_accessor_type,
interpolator_type> span_gen_type;
+ typedef agg::renderer_scanline_aa<renderer_base, span_alloc_type,
span_gen_type> renderer_type;
+ span_gen_type sg(ia, interpolator, filter);
+ renderer_type ri(rb, sa, sg);
+ agg::render_scanlines(ras, sl, ri);
+ }
}
break;
@@ -530,6 +552,20 @@
}
+char Image::get_resample__doc__[] =
+"get_resample()\n"
+"\n"
+"Get the resample flag."
+;
+
+Py::Object
+Image::get_resample(const Py::Tuple& args) {
+ _VERBOSE("Image::get_resample");
+
+ args.verify_length(0);
+ return Py::Int((int)resample);
+}
+
char Image::get_size_out__doc__[] =
"numrows, numcols = get_size()\n"
"\n"
@@ -593,6 +629,21 @@
}
+char Image::set_resample__doc__[] =
+"set_resample(boolean)\n"
+"\n"
+"Set the resample flag."
+;
+
+Py::Object
+Image::set_resample(const Py::Tuple& args) {
+ _VERBOSE("Image::set_resample");
+ args.verify_length(1);
+ int flag = Py::Int(args[0]);
+ resample = (bool)flag;
+ return Py::Object();
+}
+
static void write_png_data(png_structp png_ptr, png_bytep data, png_size_t
length) {
PyObject* py_file_obj = (PyObject*)png_get_io_ptr(png_ptr);
PyObject* write_method = PyObject_GetAttrString(py_file_obj, "write");
@@ -752,12 +803,14 @@
add_varargs_method( "buffer_rgba", &Image::buffer_rgba,
Image::buffer_rgba__doc__);
add_varargs_method( "get_aspect", &Image::get_aspect,
Image::get_aspect__doc__);
add_varargs_method( "get_interpolation", &Image::get_interpolation,
Image::get_interpolation__doc__);
+ add_varargs_method( "get_resample", &Image::get_resample,
Image::get_resample__doc__);
add_varargs_method( "get_size", &Image::get_size, Image::get_size__doc__);
add_varargs_method( "get_size_out", &Image::get_size_out,
Image::get_size_out__doc__);
add_varargs_method( "reset_matrix", &Image::reset_matrix,
Image::reset_matrix__doc__);
add_varargs_method( "get_matrix", &Image::get_matrix,
Image::get_matrix__doc__);
add_keyword_method( "resize", &Image::resize, Image::resize__doc__);
add_varargs_method( "set_interpolation", &Image::set_interpolation,
Image::set_interpolation__doc__);
+ add_varargs_method( "set_resample", &Image::set_resample,
Image::set_resample__doc__);
add_varargs_method( "set_aspect", &Image::set_aspect,
Image::set_aspect__doc__);
add_varargs_method( "write_png", &Image::write_png, Image::write_png__doc__);
add_varargs_method( "set_bg", &Image::set_bg, Image::set_bg__doc__);
Index: src/_image.h
===================================================================
--- src/_image.h (Revision 5430)
+++ src/_image.h (Arbeitskopie)
@@ -42,6 +42,8 @@
Py::Object set_bg(const Py::Tuple& args);
Py::Object flipud_out(const Py::Tuple& args);
Py::Object flipud_in(const Py::Tuple& args);
+ Py::Object set_resample(const Py::Tuple& args);
+ Py::Object get_resample(const Py::Tuple& args);
std::pair<agg::int8u*, bool> _get_output_buffer();
@@ -78,6 +80,7 @@
unsigned interpolation, aspect;
agg::rgba bg;
+ bool resample;
private:
Py::Dict __dict__;
agg::trans_affine srcMatrix, imageMatrix;
@@ -101,6 +104,8 @@
static char set_bg__doc__[];
static char flipud_out__doc__[];
static char flipud_in__doc__[];
+ static char get_resample__doc__[];
+ static char set_resample__doc__[];
};
Index: lib/matplotlib/axes.py
===================================================================
--- lib/matplotlib/axes.py (Revision 5430)
+++ lib/matplotlib/axes.py (Arbeitskopie)
@@ -4974,7 +4974,7 @@
def imshow(self, X, cmap=None, norm=None, aspect=None,
interpolation=None, alpha=1.0, vmin=None, vmax=None,
origin=None, extent=None, shape=None, filternorm=1,
- filterrad=4.0, imlim=None, **kwargs):
+ filterrad=4.0, imlim=None, resample=None, **kwargs):
"""
call signature::
@@ -5061,7 +5061,7 @@
self.set_aspect(aspect)
im = mimage.AxesImage(self, cmap, norm, interpolation, origin, extent,
filternorm=filternorm,
- filterrad=filterrad, **kwargs)
+ filterrad=filterrad, resample=resample, **kwargs)
im.set_data(X)
im.set_alpha(alpha)
Index: lib/matplotlib/image.py
===================================================================
--- lib/matplotlib/image.py (Revision 5430)
+++ lib/matplotlib/image.py (Arbeitskopie)
@@ -57,6 +57,7 @@
extent=None,
filternorm=1,
filterrad=4.0,
+ resample = False,
**kwargs
):
@@ -86,6 +87,7 @@
self.set_interpolation(interpolation)
+ self.set_resample(resample)
self.axes = ax
@@ -200,6 +202,7 @@
im.set_interpolation(self._interpd[self._interpolation])
+ im.set_resample(self._resample)
# the viewport translation
tx = (xmin-self.axes.viewLim.x0)/dxintv * numcols
@@ -325,6 +328,13 @@
raise ValueError('Illegal interpolation string')
self._interpolation = s
+ def set_resample(self, v):
+ if v is None: v = rcParams['image.resample']
+ self._resample = v
+
+ def get_interpolation(self):
+ return self._resample
+
def get_extent(self):
'get the image extent: left, right, bottom, top'
if self._extent is not None:
Index: lib/matplotlib/rcsetup.py
===================================================================
--- lib/matplotlib/rcsetup.py (Revision 5430)
+++ lib/matplotlib/rcsetup.py (Arbeitskopie)
@@ -379,6 +379,7 @@
'image.cmap' : ['jet', str], # one of gray, jet, etc
'image.lut' : [256, validate_int], # lookup table
'image.origin' : ['upper', str], # lookup table
+ 'image.resample' : [False, validate_bool],
'contour.negative_linestyle' : ['dashed',
validate_negative_linestyle_legacy],
from pylab import *
import numpy
im = numpy.zeros((200, 200))
im[range(0,100,4)] = 1.0
im[range(100,200,5), 100] = 1.0
subplot(121)
imshow(im, resample=False, interpolation = 'bicubic')
gray()
subplot(122)
imshow(im, resample=True, interpolation = 'bicubic' )
gray()
#show()
-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php
_______________________________________________
Matplotlib-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel