#version 330 core
in vec2 TexCoords;
out vec4 color;
uniform sampler2D screenTexture;
mat3 sx = mat3(
1.0, 2.0, 1.0,
0.0, 0.0, 0.0,
-1.0, -2.0, -1.0
);
mat3 sy = mat3(
1.0, 0.0, -1.0,
2.0, 0.0, -2.0,
1.0, 0.0, -1.0
);
void main()
{
vec3 diffuse = texture(screenTexture, TexCoords.st).rgb;
mat3 I;
for (int i=0; i<3; i++) {
for (int j=0; j<3; j++) {
vec3 sample = texelFetch(screenTexture, ivec2(gl_FragCoord) + ivec2(i-1,j-1), 0 ).rgb;
I[i][j] = length(sample);
}
}
float gx = dot(sx[0], I[0]) + dot(sx[1], I[1]) + dot(sx[2], I[2]);
float gy = dot(sy[0], I[0]) + dot(sy[1], I[1]) + dot(sy[2], I[2]);
float g = sqrt(pow(gx, 2.0)+pow(gy, 2.0));
color = vec4(diffuse - vec3(g), 1.0);
}
这是具有Sobel边缘检测的多维数据集的结果:
如果放大图片,您会看到Sobel产生很多“噪音”:
由于蓝/白渐变,整个场景中都有灰色的水平条纹。此外,光锥在立方体上产生不需要的图案。由于立方体左半部分的光锥,立方体左侧的黑色边缘也似乎褪色了。高斯模糊滤镜,使边缘更明显。在文章的底部,还有似乎能产生更好结果的canny边缘检测过滤器。
现在我有两个问题:
以下步骤是否正确,以产生最佳的边缘检测结果: />
如果是,如何合并原始图像和处理过的图像?我的意思是,在完成上述步骤后,我得到的图像要么是完全黑的,带有白色边缘,要么是反之。如何将边缘放在原始图像/纹理上?
感谢您的帮助!
#1 楼
最佳结果在很大程度上取决于您的用例。它们还取决于您要实现什么效果。 Sobel只是一个边缘检测过滤器:边缘将取决于输入信号,选择输入信号取决于您。
这里您将彩色图像用作输入,过滤器正确地检测蓝色渐变中的淡淡边缘,而立方体的边缘与背景颜色的颜色太接近时,立方体的边缘会中断。可以输入到Sobel过滤器的其他信息。例如,深度和法线是边缘检测的良好候选者。照明前的反照率就可以适应了。使用不同的输入进行测试,并根据获得的结果决定使用哪些输入。
关于如何结合边缘信息的问题,建议您在使用前先过滤一下
g
。然后,您可以使用它在原始颜色和所需的边缘颜色之间进行插值。例如,您可以尝试以下操作: float g = sqrt(pow(gx, 2.0)+pow(gy, 2.0));
// Try different values and see what happens
g = smoothstep(0.4, 0.6, g);
vec3 edgeColor = vec3(1., 0., 0.2);
color = vec4(mix(diffuse, edgeColor, g), 1.);
附录
要使用深度或法线,您需要将其保存在纹理中如果还没有完成的话。为常规渲染过程创建帧缓冲区时,可以在其上附加各种纹理(请参见
glFramebufferTexture2D
),并向其写入其他信息,而不仅仅是场景的颜色。纹理(带有GL_DEPTH_ATTACHMENT
),它将自动用于深度。如果您附加一个或多个颜色纹理(使用GL_COLOR_ATTACHMENTi
),则可以通过将多个输出声明到片段着色器(以前使用gl_FragData
来完成;这两种方法都请参见glDrawBuffers
)来写入它们。有关该主题的更多信息,请查找“多渲染目标”(MRT)。评论
$ \ begingroup $
好消息,谢谢朱利安。另一个问题:如何在片段着色器中使用深度或常规信息?我对GLSL还是很陌生,因此不知道如何在Sobel算法中包含这些值。
$ \ endgroup $
– enne87
16年6月19日在14:25
$ \ begingroup $
为渲染过程创建帧缓冲区时,可以在其中附加多个纹理。如果附加深度纹理,它将自动用于深度。它附加了另一个可以分别写入其中的颜色纹理(请参见opengl.org/sdk/docs/man/html/glDrawBuffers.xhtml),此功能称为“多渲染目标”(MRT)。
$ \ endgroup $
–朱利安·盖尔特(Julien Guertault)
16年6月20日在0:12
$ \ begingroup $
@ enne87:很乐意提供帮助。 :)
$ \ endgroup $
–朱利安·盖尔特(Julien Guertault)
16年6月21日在2:52
$ \ begingroup $
@trichoplax:感谢您的建议;完成。
$ \ endgroup $
–朱利安·盖尔特(Julien Guertault)
16年6月22日在12:27
评论
我想知道您是否可以通过某种方式利用OpenGL的edge标志来获得所需的结果。在行模式下,看起来仅绘制了带有边标志的顶点之间的边。这里有描述。 (我自己没有使用过,或者我会举一个例子。)