Blur: should the centre point be part of the average?
Brought to you by:
twm
BlurBuffer and BlurBufferMask in src/u_dzGraphicsUtils.pas average a pixel with its eight neighbours (div 9). The TODO at both asks whether the pixel itself should be left out, which might blur better (the divisor would then be 8).
From the TODO scan in issue 12 of dzlib's ISSUES.md.
Analysis (no code changed yet):
Leaving out the centre would not blur better. The 3x3 average including the centre is the standard box blur. Without the centre each pixel loses its own share and takes only its neighbours, which is a different filter with visible artifacts:
A better blur would go the other way: weight the centre more, e.g. the binomial kernel
which approximates a Gaussian blur without the contrast inversion. It changes how existing blurs look, so it would be a change of behaviour.
A possible problem with
div 9: it rounds down. On uniform areas nothing is lost (9 * 100 div 9 = 100), but at edges and in noise every step loses just under half a brightness level on average.TBitmap_BlurRectandTBitmap_BlurEllipserun the filter twice per pass, so with many passes blurred areas could get noticeably darker. Not measured yet; rounding instead,(Sum + 4) div 9, would avoid it.Measured on two real photos (4096x2304): two faces blurred with
TBitmap_BlurEllipse, two licence plates withTBitmap_BlurRect, plus five variants of the 3x3 step in a test program. A reimplementation of the current code gave bit-identical results to dzlib, so the comparison is fair.div 9rounding downSo the centre question is settled: leaving it out (C) is worse. The real problem is that the intermediate values are bytes: rounding down darkens, rounding to nearest freezes once a gradient is smooth. Keeping more precision (E/F) fixes both; box or binomial makes little difference at this scale.
Also tried: a separable box blur with a radius, three passes with a running sum (nearly Gaussian, sigma ~ sqrt(r(r+1))), using the real neighbouring pixels. At r = 23 it matches E at 800 passes visually, and takes ~100 ms instead of ~2.5 s for the two faces. r = 12 left the front plate partly readable, r >= 20 did not.
Follow-ups filed: the darkening/stalling as [bugs:#26], the radius-based blur as [#26].
Related
Bug Reports:
#26Feature Requests:
#26Closed: the centre stays in the 3x3 average. Leaving it out blurs worse (variant C above). The darkening found while measuring is handled in [bugs:#26], the radius-based blur in [#26].
Related
Bug Reports:
#26Feature Requests:
#26