【问题标题】:Smooth contours detection from texture in GLSLGLSL中纹理的平滑轮廓检测
【发布时间】:2018-04-16 01:25:26
【问题描述】:

我想从如下纹理生成平滑(一致的宽度和连续)轮廓:

我目前运行一个着色器,它进行非常基本的边缘检测并最终得到以下结果:

void main(void) {

  vec2 texCoord = vec2(((vProjectedCoords.x / vProjectedCoords.w) + 1.0 ) / 2.0,
            ((vProjectedCoords.y / vProjectedCoords.w) + 1.0 ) / 2.0 );

  float borderWidth = uWidth; // in px
  float step_u = borderWidth * 1.0 / uCanvasWidth;
  float step_v = borderWidth * 1.0 / uCanvasHeight;

  vec4 centerPixel = texture2D(uTextureFilled, texCoord);
  vec4 rightPixel  = texture2D(uTextureFilled, texCoord + vec2(step_u, 0.0));
  vec4 bottomPixel = texture2D(uTextureFilled, texCoord + vec2(0.0, step_v));
  // now manually compute the derivatives
  float _dFdX = length(rightPixel - centerPixel) / step_u;
  float _dFdY = length(bottomPixel - centerPixel) / step_v;

  gl_FragColor.r = max(max(centerPixel.r, rightPixel.r), bottomPixel.r);
  gl_FragColor.g = max(max(centerPixel.g, rightPixel.g), bottomPixel.g);
  gl_FragColor.b = max(max(centerPixel.b, rightPixel.b), bottomPixel.b);
  gl_FragColor.a = max(_dFdX, _dFdY);

  return;

显然生成的轮廓不干净,但即使应用适当的 sobel 过滤也不能大大提高结果。

我想获得几乎像素完美的轮廓,如果可能的话,最好也忽略来自输入纹理的噪声。

谢谢!

编辑:可能需要添加一些平滑的步骤,例如: https://www.shadertoy.com/view/4ssSRl

【问题讨论】:

    标签: opengl glsl contour smoothing sobel


    【解决方案1】:

    根据您的示例图像,您似乎正在使用具有固定背景颜色的图像。这可以简化工作。我不确定第二张图片与第一张的关系如何。它是结果的放大部分吗?

    如果我理解正确,您所描述的可以通过“出血”纹理来实现。步骤如下:

    去噪

    添加一个 pre-pass 过滤器,用于检测小于 N 个像素的非背景颜色区域并将其从源图像中消除。每个纹素应该:

    1. 对其直接邻居进行采样。如果它们都是背景,则设置为背景颜色并退出。如果 N-1 个邻居是非背景的,则保留该纹素并退出。
    2. 对下一个“环”邻居进行采样并重复该过程,直到满足 N-1 个非背景邻居或达到“步数”阈值。

    可能有这种方法和其他方法的变体可以应用于您的案例来消除噪音。另见https://computergraphics.stackexchange.com/questions/3904/is-it-better-to-blur-the-input-or-output-of-an-edge-detection-shader-for-noise-r

    您从 ShaderToy 引用的平滑步骤直接与不适用于您的用例的程序线方程一起使用。

    轮廓线

    这个想法是生成一个“边缘距离”图,其中包含每个纹素到最近的非背景纹素的距离。应用以下过滤器从源图像生成另一个纹理。对于每个像素:

    1. 如果对应的纹素为非背景,则输出黑色并退出。
    2. 否则,根据所需的边框大小,在适当大小的区域中对输入纹素周围的纹素进行采样。将距离/255 输出到最近的非背景纹素。如果没有找到,则输出白色。

    最后的处理步骤将使用这两种纹理来添加轮廓线。对于每个像素:

    1. 获取(或使用最近纹理过滤采样)相应的“边缘距离”图像纹理。
    2. 如果“边缘距离”== 0,则按原样从源图像中获取并输出相应的纹素。
    3. 如果“边缘距离”== 1.0,则输出背景颜色(或来自源图像的相应纹素)。
    4. 否则,这是一个边界!乘以 255 得到到最近的非背景纹素的距离。如果距离小于所需的边框大小,则输出边框颜色。为获得最佳效果,请使用smoothstep 生成平滑的轮廓,而不是使用硬边框截断。

    优化性能

    整个过程有很多可能的优化区域。其中,计算着色器和共享内存的智能使用可以显着减少内存带宽的使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多