|
33 | 33 |
|
34 | 34 | # map interpolation strings to module constants
|
35 | 35 | _interpd_ = {
|
| 36 | + 'antialiased': None, # this will use nearest or Hanning if downsampled |
36 | 37 | 'none': _image.NEAREST, # fall back to nearest when not supported
|
37 | 38 | 'nearest': _image.NEAREST,
|
38 | 39 | 'bilinear': _image.BILINEAR,
|
@@ -168,11 +169,28 @@ def _resample(
|
168 | 169 | allocating the output array and fetching the relevant properties from the
|
169 | 170 | Image object *image_obj*.
|
170 | 171 | """
|
| 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 | + disppixels = int(transform.transform([data.shape[1], 0])[0]) |
| 184 | + if (disppixels < 3 * data.shape[1] and disppixels != data.shape[1]): |
| 185 | + interpolation = 'hanning' |
| 186 | + else: |
| 187 | + interpolation = 'nearest' |
| 188 | + |
171 | 189 | out = np.zeros(out_shape + data.shape[2:], data.dtype) # 2D->2D, 3D->3D.
|
172 | 190 | if resample is None:
|
173 | 191 | resample = image_obj.get_resample()
|
174 | 192 | _image.resample(data, out, transform,
|
175 |
| - _interpd_[image_obj.get_interpolation()], |
| 193 | + _interpd_[interpolation], |
176 | 194 | resample,
|
177 | 195 | alpha,
|
178 | 196 | image_obj.get_filternorm(),
|
@@ -354,6 +372,20 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
|
354 | 372 | out_height = int(out_height_base)
|
355 | 373 | out_shape = (out_height, out_width)
|
356 | 374 |
|
| 375 | + # decide if we are going to do anti-aliasing or not on the image |
| 376 | + interpolation = self.get_interpolation() |
| 377 | + if interpolation == 'antialiased': |
| 378 | + # default |
| 379 | + interpolation = 'nearest' |
| 380 | + # do antialiasing.... |
| 381 | + # compare the number of displayed pixels to the number of |
| 382 | + # the data pixels. |
| 383 | + samplerate = t.transform([A.shape[1], 0])[0] / A.shape[1] |
| 384 | + if (samplerate < 3 and |
| 385 | + np.abs(int(samplerate) - (samplerate)) > 0.0001): |
| 386 | + # do anti-aliasing |
| 387 | + interpolation = 'hanning' |
| 388 | + |
357 | 389 | if not unsampled:
|
358 | 390 | if not (A.ndim == 2 or A.ndim == 3 and A.shape[-1] in (3, 4)):
|
359 | 391 | raise ValueError(f"Invalid shape {A.shape} for image data")
|
@@ -432,7 +464,6 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0,
|
432 | 464 | A_scaled += 0.1
|
433 | 465 | # resample the input data to the correct resolution and shape
|
434 | 466 | A_resampled = _resample(self, A_scaled, out_shape, t)
|
435 |
| - |
436 | 467 | # done with A_scaled now, remove from namespace to be sure!
|
437 | 468 | del A_scaled
|
438 | 469 | # un-scale the resampled data to approximately the
|
@@ -708,9 +739,9 @@ def set_interpolation(self, s):
|
708 | 739 |
|
709 | 740 | Parameters
|
710 | 741 | ----------
|
711 |
| - s : {'nearest', 'bilinear', 'bicubic', 'spline16', 'spline36', \ |
712 |
| -'hanning', 'hamming', 'hermite', 'kaiser', 'quadric', 'catrom', 'gaussian', \ |
713 |
| -'bessel', 'mitchell', 'sinc', 'lanczos', 'none'} |
| 742 | + s : {'antialiased', 'nearest', 'bilinear', 'bicubic', 'spline16', |
| 743 | +'spline36', 'hanning', 'hamming', 'hermite', 'kaiser', 'quadric', 'catrom', \ |
| 744 | +'gaussian', 'bessel', 'mitchell', 'sinc', 'lanczos', 'none'} |
714 | 745 |
|
715 | 746 | """
|
716 | 747 | if s is None:
|
|
0 commit comments