Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bilateral filter algorithm

I'm trying to implement a simple bilateral filter in javascript. This is what I've come up with so far:

// For each pixel
for (var y = kernelSize; y < height-kernelSize; y++) {
    for (var x = kernelSize; x < width-kernelSize; x++) {
        var pixel = (y*width + x)*4;
        var sumWeight = 0;
        outputData[pixel] = 0;
        outputData[pixel+1] = 0;
        outputData[pixel+2] = 0;
        outputData[pixel+3] = inputData[pixel+3];

        // For each neighbouring pixel
        for(var i=-kernelSize; i<=kernelSize; i++) {
            for(var j=-kernelSize; j<=kernelSize; j++) {
                var kernel = ((y+i)*width+x+j)*4;
                var dist = Math.sqrt(i*i+j*j);
                var colourDist = Math.sqrt((inputData[kernel]-inputData[pixel])*(inputData[kernel]-inputData[pixel])+
                        (inputData[kernel+1]-inputData[pixel+1])*(inputData[kernel+1]-inputData[pixel+1])+
                        (inputData[kernel+2]-inputData[pixel+2])*(inputData[kernel+2]-inputData[pixel+2]));
                var curWeight = 1/(Math.exp(dist*dist/72)*Math.exp(colourDist*colourDist*8));
                sumWeight += curWeight;
                outputData[pixel] += curWeight*inputData[pixel];
                outputData[pixel+1] += curWeight*inputData[pixel+1];
                outputData[pixel+2] += curWeight*inputData[pixel+2];
            }
        }

        outputData[pixel] /= sumWeight;
        outputData[pixel+1] /= sumWeight;
        outputData[pixel+2] /= sumWeight;
    }
}

inputData is from a html5 canvas object and is in the form of rgba. My images are either coming up with no changes or with patches of black around edges depending on how i change this formula:

var curWeight = 1/(Math.exp(dist*dist/72)*Math.exp(colourDist*colourDist*8));

Unfortunately I'm still new to html/javascript and image vision algorithms and my search have come up with no answers. My guess is there is something wrong with the way curWeight is calculated. What am I doing wrong here? Should I have converted the input image to CIElab/hsv first?

like image 845
Skul Avatar asked Feb 16 '26 08:02

Skul


2 Answers

I'm no Javasript expert: Are the RGB values 0..255? If so, Math.exp(colourDist*colourDist*8) will yield extremely large values - you'll probably want to scale colourDist to the range [0..1].

BTW: Why do you calculate the sqrt of dist and colourDist if you only need the squared distance afterwards?

like image 123
Niki Avatar answered Feb 17 '26 22:02

Niki


First of all, your images turn out black/weird in the edges because you don't filter the edges. A short look at your code would show that you begin at (kernelSize,kernelSize) and finish at (width-kernelSize,height-kernelSize) - this means that you only filter a smaller rectangle inside the image where your have a margin of kernelSize on each side which is unfilterred. Without knowing your javscript/html5, I would assume that your outputData array is initialized with zero's (which means black) and then not touching them would leave them black. See my link the comment to your post for code that does handle the edges.

Other than that, follow @nikie's answer - your probably want to make sure the color distance is clamped to the range of [0,1] - youo can do this by adding the line colourDist = colourDist / (MAX_COMP * Math,sqrt(3)) (directly after the first line to calculate it). where MAX_COMP is the maximal value a color component in the image can have (usually 255)

like image 33
Barak Itkin Avatar answered Feb 17 '26 22:02

Barak Itkin