OpenGL GLSL-Sobel Edge Detection Filter


9

이 주제 와 관련하여 GLSL에서 Sobel Edge Detection 필터를 성공적으로 구현했습니다 . 필터의 조각 쉐이더 코드는 다음과 같습니다.

#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 에지 감지 필터가있는 큐브

그림을 확대하면 Sobel에서 생성 한 "노이즈"가 많다는 것을 알 수 있습니다. 파란색 / 흰색 그라디언트로 인해 장면 전체에 회색 가로 줄무늬가 있습니다. 또한, 라이트 콘은 큐브에서 원치 않는 패턴을 생성합니다. 큐브 왼쪽의 검은 색 가장자리도 큐브 왼쪽의 밝은 원뿔로 인해 희미 해집니다.

따라서이 기사 를 읽고 이미지를 먼저 그레이 스케일하고 가우시안 블러 필터를 사용하여 가장자리를보다 분명하게 만들어야한다고 언급했습니다. 기사의 맨 아래에는 더 나은 결과를 생성하는 것처럼 보이는 가장자리 감지 필터도 있습니다.

이제 두 가지 질문이 있습니다.

  1. 최상의 가장자리 감지 결과를 얻을 수 있도록 다음 단계가 정확합니까?

    • 그레이 스케일
    • 가우스 흐림
    • 소벨 / 캐니 에지 감지
  2. 그렇다면 원본 이미지를 처리 ​​된 이미지와 어떻게 병합합니까? 즉, 위에서 언급 한 단계를 처리 한 후 흰색 가장자리가 완전히 검은 색이거나 그 반대의 이미지가 나타납니다. 원본 이미지 / 텍스처에 가장자리를 어떻게 배치합니까?

당신의 도움을 주셔서 감사합니다!


어떤 식 으로든 OpenGL의 edge 플래그 를 사용하여 원하는 결과를 얻을 수 있는지 궁금합니다 . 선 모드에있을 때 edge 플래그가 켜져있는 정점 사이의 모서리 만 그려지는 것처럼 보입니다. 여기 에 설명이 있습니다 . (내가 직접 사용하지 않았거나 예제를 게시 할 것입니다.)
user1118321

답변:


9
  1. 최고의 결과 는 사용 사례에 따라 크게 다릅니다. 또한 달성하고자하는 효과에 따라 다릅니다. Sobel은 에지 감지 필터 일뿐입니다. 에지는 입력 신호에 따라 달라지며 입력 신호를 선택하십시오.

    여기서는 컬러 이미지를 입력으로 사용하고 필터는 파란색 그라디언트에서 희미한 가장자리를 올바르게 감지하고 큐브의 가장자리는 배경색과 너무 가까운 위치에서 중단됩니다.

    귀하의 프로그램이 큐브를 그릴 책임이 있다고 가정하므로 Sobel 필터에 공급할 수있는 다른 정보에 액세스 할 수 있습니다. 예를 들어, 깊이와 법선은 가장자리 감지에 적합한 후보입니다. 조명 전의 알베도를 사용할 수 있습니다. 다른 입력으로 테스트하고 결과에 따라 사용할 입력을 결정하십시오.

  2. 가장자리 정보를 결합하는 방법에 대한 질문에 대해서는 필터링을 제안합니다. 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).

이 주제에 대한 자세한 내용은 "Multi Render Target" (MRT)을 참조하십시오.


좋은 정보입니다. Julien에게 감사합니다. 질문 하나 더 : 프래그먼트 셰이더에서 깊이 또는 노멀 정보를 어떻게 사용할 수 있습니까? 나는 여전히 GLSL을 처음 사용하므로 Sobel 알고리즘에 값을 포함시키는 방법을 모릅니다.
enne87

2
렌더링 패스에 대한 프레임 버퍼를 만들 때 둘 이상의 텍스처를 첨부 할 수 있습니다. 깊이 텍스처를 첨부하면 깊이에 자동으로 사용됩니다. "멀티 렌더 타겟"(MRT)이라는 기능인 별도의 컬러 텍스처 ( opengl.org/sdk/docs/man/html/glDrawBuffers.xhtml 참조 )를 추가합니다.
Julien Guertault 2016 년

@ enne87 : 기꺼이 도와 드리겠습니다. :)
Julien Guertault 2016 년

@trichoplax : 제안 해 주셔서 감사합니다. 끝난.
Julien Guertault 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.