Another attempt on the smartblur idea. After some experiments I found out about the so called “bilateral filtering” which is similar to gaussian blur but also calculates the weights based on the color distance. This way the blurring becomes weaker with the color difference of the pixels in question. It’s really nice for smoothing color transitions (debanding) or hiding dither (denoise). A problem though is that the kernel can’t be separated like with gaussian blur since the weights depend on the central pixel.
I tried my best though to make it as performant as possible. All operations are done with float4 to make usage of vector and matrix operations. Still the complexity is quadratic in kernel radius r, so at higher resolutions and with big r it’s probably gonna be slow. Anyway… there are 3 parameters you can adjust:
Radius - determines the radius r of the kernel (diamater = 2*ceil®+1)
Color Threshold - it’s not a hard threshold but a sigma value for an exponential function which maps the color difference to weights
Central Weight - the central pixel has the standard weight of 1. but you can increase it with this parameter to give the picture some of it’s texture and details back. this parameter is scaled relatively in the total sum of weights.
you can use it on the original resolution (higher impact) or on top of other shaders. set the scale factor to 1.0, filtering option depends on your shader combination
the code should be pretty easy to understand (except maybe for the choice of some constants, don’t mind them =D). I could keep the for loops in, since it seems that the cg compiler is automatically unrolling them if the number of iterations is static. would be nice though if others would have a look at it to see if there still possibilites to optimize.
anyway, here is the shader: http://pastebin.com/N38YXJCb
wikipedia articel for this method: https://en.wikipedia.org/wiki/Bilateral_filtering
imgur gallery with example shots: https://imgur.com/a/kshC6