Fix severe boundary artifacts in Box filter caused by floating-point precision#255
Fix severe boundary artifacts in Box filter caused by floating-point precision#255DavidDiao wants to merge 1 commit into
Conversation
|
I understand the problem somehow..., but don't understand your fix. Looks non-symmetric. TBH, the box filter is shitty, and it's really worth trashing it instead of fixing. Could you explain the details of the fix and why the problem will not happen at a different scale ratio? |
|
Sorry for the delay and the long post. I wanted to reorganize my thoughts properly, so I used an AI to help structure and translate this explanation for better clarity. 1. The
|
|
If you have no objection, I would keep this open for an uncertain time. Just because the reading is interesting :) . Lack of time to dive into every detail.
I suspect, here can be divergence in terminology pica/src/mm_resize/resize_filter_info.ts Line 16 in ce6a3b6
|
|
I have no objection to keeping this PR open. |
|
Ah, you are right, 0.5 in both directions gives 1.0 in total. Shame on me :) |
Description
This PR fixes a severe accuracy bug specifically affecting the Box filter during downsampling.
Users migrating from or comparing outputs with
PIL/Pillowmight notice that at certain downsampling ratios (e.g.,1000px -> 288px),picaproduces periodic visual glitches.The Root Cause
Unlike continuous filters (Lanczos, Bicubic) which gracefully decay to
0.0at their window edges, the Box filter is a discrete step function. It relies on a hard cliff: a pixel is either fully included (weight1.0) or completely excluded (weight0.0).When calculating the normalized distance of a boundary pixel to the center
diff = (pxl + 0.5) - center:0.5or-0.5.-0.49999999999999994.Math.abs(x) < 0.5evaluates this astrue.As a result, an out-of-bounds pixel that should have been discarded (weight
0.0) incorrectly receives a full weight of1.0. This accidentally widens the averaging window by 1 extra pixel for certain periodic target pixels, drastically changing the denominator and introducing a neighboring color, causing the massive deviation.The Fix
This PR implements a mathematically robust boundary extraction specifically to defend against floating-point jitter at exactly
±0.5for the Box filter. By offsetting theMath.floorbounds by+0.5(a standard technique used in PIL's C implementation), we physically exclude the floating-point-corrupted pixels from entering the accumulation loop.Impact
0.0atx = support, floating-point boundary jitter does not impact their sum.