我正在尝试在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吗?
答案 0 :(得分:2)
我不是Javasript专家:RGB值是0..255吗?如果是这样,Math.exp(colourDist*colourDist*8)
将产生非常大的值 - 您可能希望将colourDist缩放到范围[0..1]。
BTW:如果你之后只需要平方距离,为什么要计算sqrt
和dist
的{{1}}?
答案 1 :(得分:1)
首先,您的图像在边缘变黑或变怪,因为您不会过滤边缘。仔细看看你的代码会显示你从(kernelSize,kernelSize)开始并在(width-kernelSize,height-kernelSize)结束 - 这意味着你只在图像中过滤了一个较小的矩形,你的内核边缘为kernelSize每一方都没有过滤。在不知道你的javscript / html5的情况下,我会假设你的outputData数组初始化为零(这意味着黑色),然后不触摸它们会让它们变黑。有关处理边缘的代码,请参阅我的链接评论到您的帖子。
除此之外,请按照@ nikie的回答 - 你可能想确保颜色距离被限制在[0,1]的范围内 - 你可以通过添加行colourDist = colourDist / (MAX_COMP * Math,sqrt(3))
来实现这一点(直接在第一行来计算它)。其中MAX_COMP
是图像中颜色分量可以具有的最大值(通常为255)
答案 2 :(得分:0)
我在代码中发现了错误。问题是我将每个像素添加到自身而不是周围的邻居。我将保留更正的代码,以防任何人需要双边滤波算法。
outputData[pixel] += curWeight*inputData[kernel];
outputData[pixel+1] += curWeight*inputData[kernel+1];
outputData[pixel+2] += curWeight*inputData[kernel+2];