Fixed inaccurate image placement and even more resampling bugs#31021
Fixed inaccurate image placement and even more resampling bugs#31021QuLogic merged 9 commits intomatplotlib:mainfrom
Conversation
59e9389 to
8b0224e
Compare
|
Does this replace #30175? |
|
Yes, so I'll close #30175 |
3b36edb to
af951be
Compare
1f49307 to
a3764d8
Compare
To elaborate, the issue at hand is that the Agg resampler uses an integer-based interpolator for affine resampling (see some details in #30184 (comment)). The resulting inaccuracies can be obvious when using nearest-neighbor interpolation. This PR replaces that interpolator with a floating-point-based interpolator, and qualitatively there is no discernable performance hit. As a nice benefit of this change, the solution described in #30184 (comment) – falling back to nonaffine resampling under extreme zooms – is no longer necessary to preserve the alignment of pixel edges. To be safe performance-wise, affine resampling under non-nearest-neighbor interpolation continues to use the integer-based interpolator. Unlike with nearest-neighbor interpolation, it's very difficult to tell if there are slight inaccuracies with the interpolator. This can be revisited in the future. |
a3764d8 to
a9da7a6
Compare
104077d to
e919599
Compare
e919599 to
b413c6c
Compare
f5088a9 to
7472d60
Compare
a034951 to
50b6ed3
Compare
This comment was marked as outdated.
This comment was marked as outdated.
c752389 to
6fdf13e
Compare
55b7d02 to
8c50a53
Compare
tacaswell
left a comment
There was a problem hiding this comment.
modulo fixing the c++ style issue.
QuLogic
left a comment
There was a problem hiding this comment.
Some minor nits, but also a small ask: please add a bit more context to the commit messages; it is helpful to find out the why of a change without having to search out the PR. Maybe not the entirety of the test images you have here, but at least more than the single-line messages.
992b375 to
72dc4aa
Compare
Sure, I've added a bunch of sentences to the commit messages |
|
I'd like to keep the individual commits, so please squash the fixups into the originals. I assume that a lot of the commits affect test images repeatedly, so it's probably fine to keep those updates in a single separate commit. |
The code now specifies the resampling with the foreknowledge that the resampled image will be placed at the nearest display pixel. This fixes situations where the rendered image can appear to be shifted by up to one display pixel.
The built-in Agg interpolator for determining the nearest-neighbor pixels under an affine transform uses integer-based math, but that results in slight inaccuracies that can become visible at even a minor level of magnification. A custom interpolator that uses floating-point-based math is now used instead.
For nearest-neighbor interpolation, the code no longer applies any antialiasing of edges under an affine transform for more accurate edges and no longer shows data beyond the image bounds under a non-affine transform.
Calculations now take into account that rendering will be to the nearest display pixel.
Premultiplied image data is passed to the Agg resampler so that the interpolation is handled correctly. This code now tells Agg that the image is premultiplied so that the antialiasing of edges is handled correctly.
This fixes a subtle issue where a resampled pixel falling exactly between two input pixels would normally round half up, but would also be rendered with rounding half up, resulting in the resampled pixel having the wrong value. The code now functionally rounds half down, which cancels out the effect of rendering rounding half up in these situations, and otherwise makes no difference.
…olation This fixes a visual issue where there can appear to be a slight gap between an image and the axes spines even when it is supposed to fill the axes. The code now expands the rendering edges to fill the axes without degrading the placement accuracy within the image.
|
Sure, I've squashed the commits down to nine commits |
due to upstream changes at matplotlib/matplotlib#31021




PR summary
This PR now fixes a bunch of bugs:
AxesImage,PcolorImage, andNonUniformImageOriginal post:
This PR fixes a bug with how images are resampled for drawing when they are positioned at a fractional pixel (which is nearly always the case). The existing code resamples the image to the (mostly) correct width/height in display pixels, but essentially assumes that the beginning edge of the display array is aligned with the beginning edge of the image array. This resampled image is then placed at the nearest display pixel, which combined with above, means that the drawn image can be up to a pixel off from the optimal location.
The "mostly" above is because the above bug means that the drawn image can leave a gap to the axes at the end edge of the drawn image, so there's additional, discomforting code to slightly enlarge the resampled image to cover up that gap. This additional code runs only for affine transformations, so you can see the gap when using a nonaffine transformation.
Before this PR:
This PR fixes the resampling logic so that it anticipates the rounding that will be used in the later drawing and defines the transform appropriately with the rounding baked in. That way, each display pixel has been resampled exactly correctly to match the eventual drawing. Furthermore, this means there are should no longer any gaps at the end edge of the drawn image, so there no longer needs to be an enlarging step.
The resampling code for nonaffine transforms has already been scrubbed extensively (#30054 and #30184), so drawing using a nonaffine transform now gives optimal results with this PR.
Unfortunately, while drawing using an affine transform is also broadly improved, there are still cases where the results are not optimal due to inaccuracies in the image-resampling code for affine transforms. See #30184 (comment) for some details. I'm mulling over whether to greatly expand the solution described in #30184 (comment), that is, taking the switching to the nonaffine-transform code path for extreme zooms (>128x) and extending it down to minor zooms (>~5x).Update: I've made changes to how the Agg resampler handles affine transforms when using nearest-neighbor interpolation, and now drawing using an affine transform also gives optimal results.
After this PR:
Generating script:
Fixes #31009
PR checklist