The Kuwahara filter combines noise reduction (blurring) with edge preservation. This filter is mentioned in chapter 10 of the book, but not implemented. I personally like the effect of this filter and so thought it would be neat to program a shader for it.

The filter starts with a nxn kernel (where n is odd). We then divide the kernel into four subregions {A, B, C, D}

For a 3x3 kernel:

A AB B AC ABCD BD C CD D

For a 5x5 kernel:

A A AB B B A A AB B B AC AC ABCD BD BD C C CD D D C C CD D D

and so on.

For each pixel corresponding to the center point of the kernel, we take the mean value (average) and variance (difference between individual values and the mean) of each subregion. The subregion with the lowest variance will have it's mean value used as the replacement value for the current pixel. With color images, we take the mean of each RGB color channel and the variance will be measured against the luminance which we will calculate with the formula (0.3 R + 0.59 G + 0.11 B)

The effect that this filter has on an image depends on the edges in the original image and the size of the image and kernel. For instance, the rose below has a large kernel of size 27x27 while the polar bear has a kernel of size 9x9. There are several improvements to the Kuwahara filter as shown by Kypriandis.

Code for this example can be found in the Examples section within the "Bonus" tab. The most important part of it is in the 01_kuwahara_filter.fs file, where we calculate the region variance in the lines:

... current_lumination = dot(rgb, vec3(0.3, 0.59, 0.11)); current_lumination /= 255.0; cumulative_lumination += current_lumination; cumulative_lumination2 += (current_lumination*current_lumination); ... //E(X^2) - (E(X))^2 current_variance = cumulative_lumination2 - (cumulative_lumination*cumulative_lumination)/weight;