我一直在尝试使用现有SVG过滤器工具箱中的一组有限基元复制双边滤镜效果(边缘保留,颜色范围感知)。我尝试了很多方法。我迄今为止最成功的是三部分操作,它进行Sobel边缘检测,扩展Sobel边缘,通过合成操作提取与这些边缘对应的像素,高斯模糊源图像,然后将原始边缘像素复合回顶部。模糊的图像。结果保留边缘,但不能识别颜色范围。
<filter id="surfaceBlur" color-interpolation-filters="sRGB">
<!-- convert source image to luminance map-->
<feColorMatrix type="luminanceToAlpha" />
<!-- sober edge detection-->
<feConvolveMatrix order="3" kernelMatrix="-1 -2 -1
0 0 0
1 2 1 "
preserveAlpha="true"
/>
<feConvolveMatrix order="3" kernelMatrix="-1 0 1
-2 0 2
-1 0 1 "
preserveAlpha="true"
/>
<!-- dilate the edges to produce a wider mask-->
<feMorphology operator="dilate" radius="1"
result="mask"/>
<!-- extract just the detail from the source graphic using the dilated edges -->
<feComposite operator="in" in="SourceGraphic" in2="mask" result="detail" />
<!-- blur the source image -->
<feGaussianBlur stdDeviation="3" in="SourceGraphic" result="backblur"/>
<!-- slap the detail back on top of the blur! -->
<feComposite operator="over" in="detail" in2="backblur"/>
你可以看到原始的,高斯布鲁尔,这个过滤器,右下角是真正的双边滤波器:
http://codepen.io/mullany/details/Dbyxt
正如你所看到的,这并不是一个糟糕的结果,但它并不是非常接近双边滤波器。此方法也仅适用于灰度图像,因为它使用亮度差异来查找边缘 - 因此不会检测到相似亮度的颜色之间的边缘。
所以问题在于是否存在边缘保留颜色范围感知滤波器的算法变体(引导边缘视图,双边等) - 可以使用SVG中可用的有限基元构建 - 对于那些不熟悉SVG的人来说是:
只有RGB色彩空间可用。多次迭代很好,可以构造这些操作的任何有向图。
更新
我使用feBlend成功创建了一个中值滤波器,使其在冒泡排序中变亮并变暗为Max和Min运算符(感谢cs.stackexchange.com的帮助)。然而,这是低效的:http://codepen.io/mullany/pen/dmbvz,并且缺乏双边滤波器的颜色范围感知。
答案 0 :(得分:4)
我应该通过说我没有任何图形经验来证明这一点,但从数学的角度来看,我认为这可以效仿the equation that defines the bilateral filter:
根据您的图片I
,使用颜色矩阵生成一个图像Intensity
,该图像保存单个通道中每个像素的强度,例如R.通道G和B归零
对于双边滤波器窗口中的每个非中心像素,构造一个卷积矩阵,该矩阵取特定像素和中心像素之间的差异。例如,对于3x3窗口,您有矩阵
0 0 0 -1 0 0 0-1 0 0 0-1 0 0 0 0 0 0 0 0 0 0 0 0
-1 1 0 0 1 0 0 1 0 0 1 0 0 1-1 0 1 0 0 1 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-1 0-1 0 -1 0 0
您可以根据需要缩放1
和-1
,以模拟双边滤镜的空间内核。
将每个卷积矩阵应用于Intensity
地图,获得(在3x3示例中)8个图像,这些图像表示中心像素与其邻居之间的强度变化。
对于8个图像中的每一个,使用模拟双边滤波器的范围内核的表格将原始组件转移应用于R。
使用其他颜色矩阵将G和B通道设置为与所有8个图像中的R通道匹配。
在8和原始图像的每一个上使用乘法运算符,得到8个新图像,代表双边滤波器总和中的8个项。
使用Porter-Duff运算符叠加8个图像,有效地取双边滤波器中的8个项的总和。这将为您提供最终图像。
答案 1 :(得分:2)
答案 2 :(得分:1)
以下文档解释了如何使用不同像素强度级别的空间滤波器插值来实现双边滤波器的恒定时间近似(仅限插值+高斯滤波器):
<杨庆雄,Kar-Han Tan和Narendra Ahuja,实时O(1)双边过滤, IEEE计算机视觉和模式识别会议(CVPR)2009]这里存在一个java实现:https://code.google.com/p/kanzi/source/browse/java/src/kanzi/filter/FastBilateralFilter.java
要查看过滤器的结果:
java -cp kanzi.jar kanzi.test.TestEffects -filter=FastBilateral -file=...
原始C代码和其他好东西可在http://www.cs.cityu.edu.hk/~qiyang
获得答案 3 :(得分:0)
以下是使用纯图像处理的方法: -
使用反锐化遮罩(它基本上锐化边缘)。
可以通过将原始图像的拉普拉斯添加到原始图像来完成。
在锐化的图像上使用模糊。
背后的概念是,由于模糊会降低边缘的强度,因此我们会增加所有锐边的强度,然后应用模糊来消除效果。
注意: - 我不知道SVG屏蔽
答案 4 :(得分:0)
虽然答案已被接受并且赏金得到奖励,但我想尝试anisotropic diffusion algorithm。它在像素强度上应用扩散定律来平滑图像中的纹理。防止在边缘上发生扩散,因此它保留图像中的边缘。
我对SVG不太熟悉,只是在Matlab上用灰度图像编写了一个非常简单的代码。但我认为它在SVG中是可行的,因为只需要基本的差异操作(在所有4个方向中像素i+1
和i
之间的差异)和功率/添加操作。
代码:
diff = I; % original image
lambda = 0.25;
niter = 10;
Co = 20;
for i = 1:niter % iterations
% Construct diffl which is the same as diff but
% has an extra padding of zeros around it.
diffl = zeros(rows+2, cols+2);
diffl(2:rows+1, 2:cols+1) = diff;
% North, South, East and West differences
deltaN = diffl(1:rows,2:cols+1) - diff;
deltaS = diffl(3:rows+2,2:cols+1) - diff;
deltaE = diffl(2:rows+1,3:cols+2) - diff;
deltaW = diffl(2:rows+1,1:cols) - diff;
cN = 1./(1 + (deltaN/Co).^2);
cS = 1./(1 + (deltaS/Co).^2);
cE = 1./(1 + (deltaE/Co).^2);
cW = 1./(1 + (deltaW/Co).^2);
diff = diff + lambda*(cN.*deltaN + cS.*deltaS + cE.*deltaE + cW.*deltaW);
end
我获得的结果图像:
希望它有所帮助。感谢