Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5924668

Browse files
committed
ENH: anti-alias down-sampled images
1 parent 9e7a235 commit 5924668

File tree

7 files changed

+149
-62
lines changed

7 files changed

+149
-62
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Default interpolation for `image` is new "antialiased" option
2+
-------------------------------------------------------------
3+
4+
Images displayed in Matplotlib previously used nearest-neighbor
5+
interpolation, leading to aliasing effects for non-integer upscaling, and
6+
single dots being lost.
7+
8+
New default for :rc:`image.interpolation` is the new option "antialiased".
9+
`imshow(A, interpolation='antialiased')` will apply a Hanning filter when
10+
resampling the data in A for display (or saving to file) *if* the upsample
11+
rate is less than a factor of three, and not an integer; downsampled data is
12+
always smoothed at resampling.
13+
14+
To get the old behavior, set :rc:`interpolation` to the old default "nearest"
15+
(or speciful the ``interpolation`` kwarg of `.Axes.imshow`)
16+
17+
To always get the anti-aliasing behavior, no matter what the up/down sample
18+
rate, set :rc:`interpolation` to "hanning" (or one of the other filters
19+
available.
20+
21+
Note that the "hanning" filter was chosen because it has only a modest
22+
performance penalty. Anti-aliasing can be improved with other filters.

lib/matplotlib/axes/_axes.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5482,17 +5482,25 @@ def imshow(self, X, cmap=None, norm=None, aspect=None,
54825482
The interpolation method used. If *None*
54835483
:rc:`image.interpolation` is used, which defaults to 'nearest'.
54845484
5485-
Supported values are 'none', 'nearest', 'bilinear', 'bicubic',
5486-
'spline16', 'spline36', 'hanning', 'hamming', 'hermite', 'kaiser',
5487-
'quadric', 'catrom', 'gaussian', 'bessel', 'mitchell', 'sinc',
5488-
'lanczos'.
5485+
Supported values are 'none', 'antialiased', 'nearest', 'bilinear',
5486+
'bicubic', 'spline16', 'spline36', 'hanning', 'hamming', 'hermite',
5487+
'kaiser', 'quadric', 'catrom', 'gaussian', 'bessel', 'mitchell',
5488+
'sinc', 'lanczos'.
54895489
54905490
If *interpolation* is 'none', then no interpolation is performed
54915491
on the Agg, ps, pdf and svg backends. Other backends will fall back
54925492
to 'nearest'. Note that most SVG renders perform interpolation at
54935493
rendering and that the default interpolation method they implement
54945494
may differ.
54955495
5496+
If *interpolation* is the default 'antialiased', then 'nearest'
5497+
interpolation is used if the image is upsampled by more than a
5498+
factor of three (i.e. the number of display pixels is at least three
5499+
times the size of the data array). If the upsampling rate is
5500+
smaller than 3, or the image is downsampled, then 'hanning'
5501+
interpolation is used to act as an anti-aliasing filter, unless the
5502+
image happens to be upsampled by exactly a factor of two or one.
5503+
54965504
See
54975505
:doc:`/gallery/images_contours_and_fields/interpolation_methods`
54985506
for an overview of the supported interpolation methods.

lib/matplotlib/image.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
# map interpolation strings to module constants
3535
_interpd_ = {
36+
'antialiased': None, # this will use nearest or Hanning if downsampled
3637
'none': _image.NEAREST, # fall back to nearest when not supported
3738
'nearest': _image.NEAREST,
3839
'bilinear': _image.BILINEAR,
@@ -168,11 +169,34 @@ def _resample(
168169
allocating the output array and fetching the relevant properties from the
169170
Image object *image_obj*.
170171
"""
172+
173+
# decide if we need to apply anti-aliasing if the data is upsampled:
174+
# compare the number of displayed pixels to the number of
175+
# the data pixels.
176+
interpolation = image_obj.get_interpolation()
177+
if interpolation == 'antialiased':
178+
# don't antialias if upsampling by an integer number or
179+
# if zooming in more than a factor of 3
180+
# do antialiasing....
181+
# compare the number of displayed pixels of the image to the number of
182+
# the data pixels.
183+
disppixelsX = int(transform.transform([data.shape[1], 0])[0])
184+
disppixelsY = int(transform.transform([data.shape[0], 0])[0])
185+
if ((disppixelsX < 3 * data.shape[1] and
186+
disppixelsX != data.shape[1] and
187+
disppixelsX != 2 * data.shape[1]) or
188+
(disppixelsY < 3 * data.shape[0] and
189+
disppixelsY != data.shape[0] and
190+
disppixelsY != 2 * data.shape[0])):
191+
interpolation = 'hanning'
192+
else:
193+
interpolation = 'nearest'
194+
171195
out = np.zeros(out_shape + data.shape[2:], data.dtype) # 2D->2D, 3D->3D.
172196
if resample is None:
173197
resample = image_obj.get_resample()
174198
_image.resample(data, out, transform,
175-
_interpd_[image_obj.get_interpolation()],
199+
_interpd_[interpolation],
176200
resample,
177201
alpha,
178202
image_obj.get_filternorm(),
@@ -432,7 +456,6 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
432456
A_scaled += 0.1
433457
# resample the input data to the correct resolution and shape
434458
A_resampled = _resample(self, A_scaled, out_shape, t)
435-
436459
# done with A_scaled now, remove from namespace to be sure!
437460
del A_scaled
438461
# un-scale the resampled data to approximately the
@@ -708,9 +731,9 @@ def set_interpolation(self, s):
708731
709732
Parameters
710733
----------
711-
s : {'nearest', 'bilinear', 'bicubic', 'spline16', 'spline36', \
712-
'hanning', 'hamming', 'hermite', 'kaiser', 'quadric', 'catrom', 'gaussian', \
713-
'bessel', 'mitchell', 'sinc', 'lanczos', 'none'}
734+
s : {'antialiased', 'nearest', 'bilinear', 'bicubic', 'spline16',
735+
'spline36', 'hanning', 'hamming', 'hermite', 'kaiser', 'quadric', 'catrom', \
736+
'gaussian', 'bessel', 'mitchell', 'sinc', 'lanczos', 'none'}
714737
715738
"""
716739
if s is None:

lib/matplotlib/rcsetup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1100,7 +1100,7 @@ def _validate_linestyle(ls):
11001100
'mathtext.fallback_to_cm': [True, validate_bool],
11011101

11021102
'image.aspect': ['equal', validate_aspect], # equal, auto, a number
1103-
'image.interpolation': ['nearest', validate_string],
1103+
'image.interpolation': ['antialiased', validate_string],
11041104
'image.cmap': ['viridis', validate_string], # gray, jet, etc.
11051105
'image.lut': [256, validate_int], # lookup table
11061106
'image.origin': ['upper',

0 commit comments

Comments
 (0)