Algorithm 如何使用一组有限的基本操作创建边缘保持模糊(类似于双边过滤器)
我一直在尝试使用SVG过滤器现有工具箱中有限的原语集复制双边过滤器效果(边缘保持、颜色范围感知)。我试过很多方法。到目前为止,我最成功的操作是三部分操作,即进行Sobel边缘检测、放大Sobel边缘、通过合成操作提取与这些边缘对应的像素、高斯模糊源图像,然后在模糊图像的顶部合成原始边缘像素。结果将保留边,但不知道颜色范围Algorithm 如何使用一组有限的基本操作创建边缘保持模糊(类似于双边过滤器),algorithm,image-processing,svg,Algorithm,Image Processing,Svg,我一直在尝试使用SVG过滤器现有工具箱中有限的原语集复制双边过滤器效果(边缘保持、颜色范围感知)。我试过很多方法。到目前为止,我最成功的操作是三部分操作,即进行Sobel边缘检测、放大Sobel边缘、通过合成操作提取与这些边缘对应的像素、高斯模糊源图像,然后在模糊图像的顶部合成原始边缘像素。结果将保留边,但不知道颜色范围 <filter id="surfaceBlur" color-interpolation-filters="sRGB"> <!-- conve
<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"/>
您可以看到原始的gaussianBlur,此过滤器和右下角的真实双边过滤器:
正如你所看到的,这不是一个可怕的结果,但它不是非常接近双边过滤器。此方法也仅适用于灰度图像,因为它使用亮度差异来查找边缘,因此不会检测到亮度相似的颜色之间的边缘
因此,问题在于是否存在一种边缘保留颜色范围感知过滤器(引导边缘视图、双边等)的算法变体,该过滤器可以使用SVG中可用的有限原语构建,对于不熟悉SVG的人来说,该过滤器包括:
- 高斯模糊
- 卷积(任何内核大小)
- 侵蚀/扩张
- 颜色矩阵
- 所有波特·达夫合成作业
- 基本混合操作(倍增、屏幕、增亮、变暗)
- 组件传输原语,允许颜色通道通过表格查找进行转换(以及将地板/天花板转换为特定值)
我成功地创建了一个中值滤波器,使用feBlend-lighted和darken作为冒泡排序中的Max和Min操作符(感谢cs.stackexchange.com的帮助)。然而,这是低效的:,并且缺乏双边过滤器的颜色范围意识。我应该说我在图形方面没有任何经验来证明这一点,但从数学角度来看,我认为这将有助于模拟:
- 给定图像
,使用颜色矩阵生成图像I
,该图像将每个像素的强度保持在单个通道中,例如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
s和1
s,以模拟双边过滤器的空间内核-1
- 将每个卷积矩阵应用于
贴图,获得(在3x3示例中)8幅图像,表示中心像素与其相邻像素之间的强度变化强度
- 对于8个图像中的每个图像,使用模拟双边过滤器范围内核的表将组件传输应用到R
- 使用另一个颜色矩阵设置G和B通道,以匹配所有8幅图像中的R通道
- 对8和原始图像中的每一个使用乘法运算符,以获得8个新图像,它们表示双边滤波器和中的8个项
- 使用波特-达夫算子叠加8幅图像,有效地在双边滤波器中获取8项的总和。这将为您提供最终图像
以下是一种使用纯图像处理的方法:
注意:-我不知道SVG掩蔽以下文档说明了如何使用不同像素强度级别的空间滤波器插值实现双边滤波器的恒定时间近似(仅限插值+高斯滤波器): [杨庆雄、陈家汉和阿胡贾,实时O(1)双边滤波, IEEE计算机视觉和模式识别会议(CVPR)2009] 这里有一个java实现: 要查看过滤器的结果,请执行以下操作:
java-cp-kanzi.jar-kanzi.test.TestEffects-filter=fastbreal-file=…
原始的C代码和其他好东西可以在上找到,尽管答案已经被接受并获得了赏金,但我想尝试一下。它将像素强度上的扩散定律应用于平滑图像中的纹理。防止跨边扩散,因此可以保留图像中的边。 我不是很熟悉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
我获得的结果图像:
希望能有帮助。谢谢Hi-Andy刚刚对第5步(“使用另一个颜色矩阵…”)做了一个快速的澄清,你的意思是重复我们刚才用G和B对R通道所做的步骤吗?或者重复这些步骤,或者只是将R通道复制到G和B通道上。现在想想,我不完全清楚两个像素相乘是如何工作的。它只是多重的吗