【问题标题】:Implementing a Sobel filter with SVG filters使用 SVG 过滤器实现 Sobel 过滤器
【发布时间】:2016-01-30 21:15:19
【问题描述】:

乍一看,我认为这很简单。谷歌发现this有以下代码,但它不是真正的sobel过滤器。

<filter id="edge">
<feColorMatrix type="luminanceToAlpha" />
<feConvolveMatrix order="3" kernelMatrix="-1 -2 -1 0 0 0 1 2 1" />
<feConvolveMatrix order="3" kernelMatrix="-1 -2 -1 0 0 0 1 2 1" />
</filter>

按照wikipedia page,我需要一种方法来查找两个feConvolveMatrix 结果之间的距离。我可以通过合成来平方和添加它们,但似乎没有任何方法可以获得平方根运算符。有可能吗?

我在下面添加了我当前的解决方案,但它与参考不完全匹配。

【问题讨论】:

    标签: svg svg-filters


    【解决方案1】:

    那个示例代码是错误的。这是使用卷积的传统 Sobel。它分离出通道并将它们转换为 alpha,运行边缘检测,将它们重新着色回 RGB 并将通道重新添加到一起。为了获得准确的参考结果,他们似乎添加了阈值 - 您可以使用 feComponentTransfer 来做到这一点。

    <svg width="600px" height="800px" >
    
    <defs>
    <filter id="sobel" x="0%" y="0%" width="100%" height="100%">
        <!-- convert source image to luminance map-->
        <feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 
                                             0 0 0 0 1 
                                             0 0 0 0 1 
                                             1 0 0 0 0" result="RChan" />
      
          <feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 
                                             0 0 0 0 1 
                                             0 0 0 0 1 
                                             0 1 0 0 0" result="GChan" />
      
      
          <feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 
                                             0 0 0 0 1 
                                             0 0 0 0 1 
                                             0 0 1 0 0" result="BChan" />
      
        <!-- sobel edge detection-->
    
      
        <feConvolveMatrix in="RChan" order="3" kernelMatrix="-1 -2 -1  
                                                   0 0 0  
                                                   1 2 1 "
                     
                       result="Rhor" />
      
        <feConvolveMatrix in="RChan" order="3" kernelMatrix="-1 0 1  
                                                                     -2 0 2 
                                                                     -1 0 1"  result="Rver"  />
      
       <feComposite operator="arithmetic" k2="1" k3="1" in="Rhor" in2="Rver" />
       <feColorMatrix type="matrix" values="0 0 0 1 0
                                        0 0 0 0 0 
                                        0 0 0 0 0 
                                        0 0 0 0 1" result="rededge"/>
    
      
       <feConvolveMatrix in="GChan" order="3" kernelMatrix="-1 -2 -1  
                                                   0 0 0  
                                                   1 2 1"
                       result="Ghor" />
      
        <feConvolveMatrix in="GChan" order="3" kernelMatrix="-1 0 1 
                                                             -2 0 2 
                                                             -1 0 1"  result="Gver"  />
      
       <feComposite operator="arithmetic" k2="1" k3="1" in="Ghor" in2="Gver" />
       <feColorMatrix type="matrix" values="0 0 0 0 0
                                        0 0 0 1 0 
                                        0 0 0 0 0 
                                        0 0 0 0 1" result="greenedge"/>
      
    
       <feConvolveMatrix in="BChan" order="3" kernelMatrix="-1 -2 -1  
                                                   0 0 0  
                                                   1 2 1 " result="Bhor" />
      
        <feConvolveMatrix in="BChan" order="3" kernelMatrix="-1 0 1  
                                                                     -2 0 2 
                                                                     -1 0 1"  result="Bver"  />
      
       <feComposite operator="arithmetic" k2="1" k3="1" in="Bhor" in2="Bver"/>
       <feColorMatrix type="matrix" values="0 0 0 0 0
                                        0 0 0 0 0 
                                        0 0 0 1 0 
                                        0 0 0 0 1" result="blueedge"/>
    
      <feComposite operator="arithmetic" in="blueedge" in2="rededge" k2="1" k3="1"/>
      <feComposite operator="arithmetic" in2="greenedge" k2="1" k3="1" result="finaledges"/>
      
      <feFlood flood-color="black" result="black"/>
      <feComposite operator="over" in="finaledges"/>
      </filter>
      
      </defs>
    
    <image width="400" height="300" preserveAspectRatio="xMinYMin meet" xlink:href="http://www.roborealm.com/help/Sobel_src.jpg"/>
      
      <image filter="url(#sobel)" y="400" width="400" height="300" xlink:href="http://www.roborealm.com/help/Sobel_src.jpg"/>
      
    </svg>

    【讨论】:

      【解决方案2】:

      feDiffuseLighting 实际上计算了一个 sobel 滤波器来生成一个法线。我将以下内容放在一起,将 RGB 提取为三个白色图像,每个图像以 R、G 和 B 作为高度图的 alpha。然后使用位于图像上方的定向光提取法线的z 分量(即1 - sqrt(dx^2 + dy^2))。最后将其反转(仅获得sqrt(dx^2 + dy^2))并将所有三个通道合并。

      我不太确定color-interpolation-filters="sRGB" 图像非常暗,因此我设置了surfaceScale="8.0" 以提供更高的增量变化。它仍然看起来不太像参考,但它很接近。此外,无论出于何种原因,过滤器都会向外扩展以覆盖 HTML 的其他部分(编辑: 参见 this)。

      来自this page的测试图像:

      .sobelme {
        -webkit-filter: url('#sobel');
        -moz-filter: url('#sobel');
        -ms-filter: url('#sobel');
        -o-filter: url('#sobel');
        filter: url('#sobel');
      }
      <img class="sobelme" src="http://i.stack.imgur.com/sld5Y.png" />
      <img src="http://i.stack.imgur.com/wq077.png" />
      
      <svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="0">
        <filter id="sobel" color-interpolation-filters="sRGB">
          <feColorMatrix type="matrix" in="SourceGraphic" result="RA" values="0 0 0 0 1
                0 0 0 0 1
                0 0 0 0 1
                1 0 0 0 0"></feColorMatrix>
          <feColorMatrix type="matrix" in="SourceGraphic" result="GA" values="0 0 0 0 1
                0 0 0 0 1
                0 0 0 0 1
                0 1 0 0 0"></feColorMatrix>
          <feColorMatrix type="matrix" in="SourceGraphic" result="BA" values="0 0 0 0 1
                0 0 0 0 1
                0 0 0 0 1
                0 0 1 0 0"></feColorMatrix>
          <feDiffuseLighting in="RA" result="R" surfaceScale="8.0">
            <feDistantLight elevation="90"></feDistantLight>
          </feDiffuseLighting>
          <feDiffuseLighting in="GA" result="G" surfaceScale="8.0">
            <feDistantLight elevation="90"></feDistantLight>
          </feDiffuseLighting>
          <feDiffuseLighting in="BA" result="B" surfaceScale="8.0">
            <feDistantLight elevation="90"></feDistantLight>
          </feDiffuseLighting>
          <feColorMatrix type="matrix" in="R" result="RS" values="-1 0 0 0 1
                0 0 0 0 0
                0 0 0 0 0
                0 0 0 0 1"></feColorMatrix>
          <feColorMatrix type="matrix" in="G" result="GS" values="0 0 0 0 0
                0 -1 0 0 1
                0 0 0 0 0
                0 0 0 0 1"></feColorMatrix>
          <feColorMatrix type="matrix" in="B" result="BS" values="0 0 0 0 0
                0 0 0 0 0
                0 0 -1 0 1
                0 0 0 0 1"></feColorMatrix>
          <feComposite in="RS" in2="GS" result="RSGS" operator="arithmetic" k1="0" k2="1" k3="1" k4="0"></feComposite>
          <feComposite in="RSGS" in2="BS" operator="arithmetic" k1="0" k2="1" k3="1" k4="0"></feComposite>
        </filter>
      </svg>

      更新:

      测试图像是一个近似值,它忽略了水平和垂直增量之间的距离,只是简单地将它们相加。使用上述feDiffuseLighting 进行正态计算的 Sobel 滤波器是归一化的,这就是为什么需要按 8 缩放的原因。与@MichaelMullany's answer 类似,只需将水平和垂直增量的绝对值相加,无需sqrt(),即可实现如下。一个优点是不会发生过滤器在边界之外的恼人扩展。 color-interpolation-filters 是必需的,否则会应用伽马,产生奇怪的结果。它仍然与测试图像不太匹配,但更接近和更简单。

      .sobelme {
        -webkit-filter: url('#sobel');
        -moz-filter: url('#sobel');
        -ms-filter: url('#sobel');
        -o-filter: url('#sobel');
        filter: url('#sobel');
      }
      <img class="sobelme" src="http://i.stack.imgur.com/sld5Y.png" />
      <img src="http://i.stack.imgur.com/wq077.png" />
      
      <svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="0">
        <filter id="sobel" color-interpolation-filters="sRGB">
          <feConvolveMatrix in="SourceGraphic" order="3" preserveAlpha="true" kernelMatrix="-1 -2 -1
      0 0 0
      1 2 1 " result="VP" />
          <feConvolveMatrix in="SourceGraphic" order="3" preserveAlpha="true" kernelMatrix="1 2 1
      0 0 0
      -1 -2 -1 " result="VN" />
          <feConvolveMatrix in="SourceGraphic" order="3" preserveAlpha="true" kernelMatrix="-1 0 1
      -2 0 2
      -1 0 1 " result="HP" />
          <feConvolveMatrix in="SourceGraphic" order="3" preserveAlpha="true" kernelMatrix="1 0 -1
      2 0 -2
      1 0 -1 " result="HN" />
          <feComposite operator="arithmetic" in="VN" in2="VP" k2="1" k3="1" result="V" />
          <feComposite operator="arithmetic" in="HN" in2="HP" k2="1" k3="1" result="H" />
          <!-- <feComposite operator="arithmetic" in="V" in2="H" k2="1" k3="1" /> -->
          <feBlend mode="lighten" in="H" in2="V" />
        </filter>
      </svg>

      【讨论】:

        猜你喜欢
        • 2019-03-27
        • 1970-01-01
        • 1970-01-01
        • 2014-11-22
        • 2021-03-15
        • 2017-06-20
        • 1970-01-01
        • 2019-03-11
        • 2014-11-04
        相关资源
        最近更新 更多