双边滤波算法

发布于 2024-12-05 15:49:08 字数 1820 浏览 0 评论 0原文

我正在尝试用 JavaScript 实现一个简单的双边过滤器。这就是我到目前为止所想到的:

// 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 来自 html5 canvas 对象,并且采用 rgba 的形式。 我的图像要么没有任何变化,要么边缘有黑色斑点,具体取决于我如何更改这个公式:

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

不幸的是,我对 html/javascript 和图像视觉算法仍然很陌生,我的搜索没有找到答案。我的猜测是 curWeight 的计算方式有问题。我在这里做错了什么?我应该先将输入图像转换为 CIElab/hsv 吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

玩世 2024-12-12 15:49:08

我不是 JavaScript 专家:RGB 值是 0..255 吗?如果是这样,Math.exp(colourDist*colourDist*8) 将产生非常大的值 - 您可能希望将 colorDist 缩放到范围 [0..1]。

顺便说一句:如果您之后只需要平方距离,为什么还要计算 distcolourDistsqrt 呢?

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?

不知所踪 2024-12-12 15:49:08

首先,您的图像边缘会变成黑色/奇怪,因为您没有过滤边缘。简短地看一下你的代码会发现你从 (kernelSize,kernelSize) 开始并以 (width-kernelSize,height-kernelSize) 结束 - 这意味着你只过滤图像内一个较小的矩形,其中你有 kernelSize 的边距每一面都是未经过滤的。在不知道你的 javscript/html5 的情况下,我会假设你的 outputData 数组是用零(这意味着黑色)初始化的,然后不接触它们会让它们变成黑色。请参阅我的链接对您的帖子的评论,以获取处理边缘的代码。

除此之外,按照@nikie的答案 - 您可能想确保颜色距离限制在 [0,1] 范围内 - 您可以通过添加行 colourDist = colorDist / (MAX_COMP * Math, sqrt(3)) (直接在第一行之后进行计算)。其中 MAX_COMP 是图像中颜色分量可以具有的最大值(通常为 255)

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)

养猫人 2024-12-12 15:49:08

我发现了代码中的错误。问题是我将每个像素添加到自身而不是其周围的邻居。我将在这里留下更正后的代码,以防有人需要双边过滤算法。

outputData[pixel] += curWeight*inputData[kernel];
outputData[pixel+1] += curWeight*inputData[kernel+1];
outputData[pixel+2] += curWeight*inputData[kernel+2];

I've found the error in the code. The problem was I was adding each pixel to itself instead of its surrounding neighbours. I'll leave the corrected code here in case anyone needs a bilateral filter algorithm.

outputData[pixel] += curWeight*inputData[kernel];
outputData[pixel+1] += curWeight*inputData[kernel+1];
outputData[pixel+2] += curWeight*inputData[kernel+2];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文