0

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

在此处输入图像描述

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

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

4

1 回答 1

2

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

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

去噪

添加一个预通滤波器,用于检测小于 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生成平滑轮廓而不是硬边界截断。

优化性能

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

于 2017-11-03T14:40:58.347 回答