license: GPL v2
The Kuwahara filter is an edge preserving spatial noise reduction filter. It applies spatial smoothing while preserving the edges.
Kuwahara
(clip clip,
int window = 1, bool generalized
= true, int q = 2, bool smooth_chroma
= false, int edge = 0, int threshold
=
70, float edge_brightness = 0.75)
window is the radius of the smoothing filter. For any pixel the square with the lowest standard deviation of its luma samples is selected. Only four surrounding squares of the pixel are considered for its selection (that is the quadrants). The pixel gets the value of the average color channels of that square (for smooth_chroma = true), or it will only average the luma of that square (for smooth_chroma = false). The larger the radius the more smoothing will be applied. The squares have the size (window+1) x (window+1), so window=0 will leave the image unfiltered.
generalized when set to true a generalized filter will be used. When set to true that means that a weighted average of the four squares will be taken (instead of just one square), where a low standard deviation will contribute more. When set to true it preserves the edges in a more accurate way. See section theory for more information.
q is only used when generalized is set to true. For large q you will get the same results as for generalized = false. See section theory for more information.
smooth_chroma when set to true it will average the color channels. When set to false it will only average the luma.
edge can be set to 0, 1 or 2. When set to 0 the smoothing image is returned. When set to 1 the edge mask is returned. When set to 2 the edge mask is drawn on the smoothed image. Note that the edge mask is created using window = 1. When a pixel is surrounded by four edges (meaning the variances of the luma samples of each quadrant are all higher than the threshold) it is not smoothed.
threshold is used to detect the edge. When the variance of the luma samples of the lower right quadrant (for window = 1) of a pixel is higher than threshold than the pixel is detected as being part of an edge. The brightness of the edge can be set using the edge_brightness parameter.
edge_brightness must be between 0 and
255. Setting it to zero will result in a black edge, setting it to 255
wilt result in a white edge (except that pure black will stay black)
and setting it to one will result in original edge.
LoadPlugin("D:\AviSynth\Plugins\Kuwahara\Release\Kuwahara.dll")
c = Imagesource("D:\AviSynth\Plugins\Kuwahara\adriana.jpg", start=0, end=0).BicubicResize(600,450)
c2 = c.Kuwahara(1,true,1,true,2,70).Subtitle("window=1,generalized=true,q=1,smooth_chroma=true,edge=2,threshold=70", size=10)
c3 = c.Kuwahara(1,false,1,false,1,70).Subtitle("edge=1,threshold=70", size=10)
c4 = c.Kuwahara(4,true,1,true,2,70).Subtitle("window=4,generalized=true,q=1,smooth_chroma=true,edge=2,threshold=70", size=10)
v1 = stackhorizontal(c,c2)
v2 = stackhorizontal(c3,c4)
stackvertical(v1,v2)
![]() |
LoadPlugin("D:\AviSynth\Plugins\Kuwahara\Release\Kuwahara.dll")
c = Imagesource("D:\AviSynth\Plugins\Kuwahara\blackhills.jpg", start=0, end=0).BicubicResize(600,450)
c1 = c.Subtitle("original", size=10)
c2 = c.Kuwahara(1,false).Subtitle("window=1,generalized=false", size=10)
c3 = c.Kuwahara(1,true,1,false).Subtitle("window=1,generalized=true,q=1", size=10)
c4 = c.Kuwahara(4,true,1,true).Subtitle("window=4,generalized=true,q=1,smooth_chroma=true", size=10)
v1 = stackhorizontal(c,c4)
v2 = stackhorizontal(c2,c3)
stackvertical(v1,v2)
![]() |
LoadPlugin("D:\AviSynth\Plugins\Kuwahara\Release\Kuwahara.dll")
c = Imagesource("D:\AviSynth\Plugins\Kuwahara\adriana.jpg", start=0, end=0).BicubicResize(600,450)
c5 = c.Kuwahara(1,false,1,true,0,70)
c6 = c.Kuwahara(1,true,1,true,0,70)
c5 = c5.Crop(100,0,-200,-150).Subtitle("window=1,generalized=false,smooth_chroma=true", size=10)
c6 = c6.Crop(100,0,-200,-150).Subtitle("window=1,generalized=true,q=1,smooth_chroma=true", size=10)
stackhorizontal(c5,c6).BicubicResize(1200,600)
![]() |
The region around a pixel (x,y) which will be processed is divided into four quadrants in the following way:
Qi(x,y)={ |
|
generalized = false
For the selection of the quadrant only its luma samples are considered [*].
For all four quadrants, Qi, the mean (average) and the variance of the luma samples is calculated as follows (note that are (window+1)2 samples in every quadrant):
lumaj = redj*srcp[2]+0.587*greenj+0.114*bluej (so the unscaled PC.601 luma is taken)
mean: mi,local = sumj in Qi lumaj / (window+1)2variance: vari,local = sumj in Qi (lumaj - mi,local)2 / (window+1)2
If all four variances are higher than the threshold that means the pixel is surrounded by edges and it won't be processed. (This holds also for the edge of the image itself, so the top, left, bottom and right window number of pixels won't be processed either.) The quadrant with the minimal variance, that is mini vari,local, is selected. Let's say {msel, varsel}.[*] Maybe that's not sufficient in some cases and the chroma should be taken into account too ...
generalized = true
When generalized is set to true, a weighted average of the four quadrants is calculated where smaller variances have more weight, that ismsel = sumi (mi / variq) / sumi (1 / variq) // for smooth_chroma = false
mblue = sumi (mblue,i / variq) / sumi (1 / variq) // for smooth_chroma = true (likewise for green and red)If one of the variances < 0.001 (say vari < 0.001) then msel=mi for smooth_chroma = false, and mblue=mblue,i for smooth_chroma = true (likewise for green and red).
processing the pixel
Finally the color channels of the pixel (x,y) are set as follows:for smooth_chroma = true:
blue = mblue
green = mgreen
red = mred
for smooth_chroma = false:
blue = blue - luma + msel
green = green - luma + msel
red = red - luma + msel
Wikipedia
described the original Kuwahara filter and several variants of it.
The
paper 'Artistic Edge and Corner Enhancing Smoothing' by Papari, Petkov
and Campisi introduces the generalized Kuwahara filter.
v1.1, 12th August 2014
v1.0, 28th June 2014