Fixed several accuracy bugs with image resampling#30184
Fixed several accuracy bugs with image resampling#30184QuLogic merged 10 commits intomatplotlib:mainfrom
Conversation
| if(i <= pivot) m_weight_array[pivot - i] = value; | ||
| } | ||
| unsigned end = (diameter() << image_subpixel_shift) - 1; | ||
| m_weight_array[0] = m_weight_array[end]; |
There was a problem hiding this comment.
This line is one of the bugs. 0 and end are different distances from pivot, so the corresponding weights typically should not be the same.
There was a problem hiding this comment.
Please put the new version under a macro guard, as was done in #28122, so that we keep a track of what's the original Agg and what we changed on top of it.
There was a problem hiding this comment.
It turns out that I can't add a preprocessor definition in _image_resample.h a la #28122. There is buggy code in agg_image_filters.cpp that needs to be skipped, but since it is a CPP file rather than a H file, it gets compiled separately with no awareness of _image_resample.h. I have put the preprocessor definition (MPL_FIX_IMAGE_FILTER_LUT_BUGS) here at the top of agg_image_filters.h, which is lower level than would be nice, but at least still makes it clear what is custom code.
There was a problem hiding this comment.
You could also put the define in the corresponding meson.build if you prefer.
There was a problem hiding this comment.
Ah, that's a nicer approach. Done!
You can see such a blip in the example above, but it's easy to overlook. Here's a starker example: an array of two pixels with the same value (0.1) is resampled to an array of ten pixels. Before this PR, two of the pixels in the output array have values slightly greater than 0.1. >>> import numpy as np
>>> from matplotlib.transforms import Affine2D
>>> from matplotlib.image import resample, BILINEAR
>>>
>>> in_data = np.array([[0.1, 0.1]])
>>> in_shape = in_data.shape
>>>
>>> out_shape = (1, 10)
>>>
>>> # Create a simple affine transform for scaling the input array
>>> affine = Affine2D().scale(sx=out_shape[1] / in_shape[1], sy=1)
>>>
>>> affine_data = np.empty(out_shape)
>>> resample(in_data, affine_data, affine, interpolation=BILINEAR)
>>>
>>> print(affine_data)
[[0.1 0.10001221 0.1 0.1 0.1 0.1
0.10001221 0.1 0.1 0.1 ]]After this PR, the output is the expected: >>> print(affine_data)
[[0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1]] |
d2fa1e5 to
7eb18b2
Compare
7eb18b2 to
d9f8bb5
Compare
|
This killed the log-scale images? Also this changed a bunch of image tests, but I can't see any difference by eye. Is it worth just relaxing the tolerance on those tests a bit and at the same time adding new tests for these fixes? |
7eb1cea to
5cbb7bb
Compare
Indeed, I need to track down why.
Yes, the other 17 image tests are mostly subtle differences, but merely relaxing the tolerance doesn't make sense to me. The updated baseline images do represent what the output should be. |
|
Fair enough - however, it would be good if there were some tests devised where it showed a visual effect of these inaccuracies. |
e198af6 to
717a221
Compare
| } | ||
| } | ||
|
|
||
| #ifndef MPL_FIX_IMAGE_FILTER_LUT_BUGS |
There was a problem hiding this comment.
The following code block is removed because it not only has the same bugs as the code in agg_image_filters.h, but also it shouldn't even exist because it modifies the weight array after it has been normalized, thus potentially destroying the normalization.
43b912c to
90bd95f
Compare
|
I fixed the issue with On the other hand, most of the updated images have solely very slight changes in the appearance of text. As @jklymak suggested, it might make more sense in those cases to simply increase the tolerance instead for the comparison instead of updating the baseline image, so let me know if I should do that instead. |
|
Are you sure you have the right set of images? |
|
OK, I see that |
90bd95f to
9fdca21
Compare
35b0fc8 to
48e28b8
Compare
|
I likely won't be able to review properly the changes since Oct. 8 before the holiday break. Sorry about that, this looks like great work. |
greglucas
left a comment
There was a problem hiding this comment.
This looks good to me.
It was decided on the call to merge this into main and then update the text overhaul branch to remove the added tolerances here.
We should merge #30824 first because they both update the bivar cmap image.
48e28b8 to
c19b295
Compare
|
I've updated this PR now that #30824 has been merged |
|
Whew, thanks! |



PR summary
This PR fixes several accuracy bugs with image resampling:
Below are illustrative plots and the generating script for linear resampling of a 2-pixel array. There are fundamental limitations of the accuracy due to the subpixel approach of the agg backend, but the motivation here is for the average behavior to be accurate (i.e., eliminate bias).
Before this PR
After this PR
Script
PR checklist