OpenGL GLSL - ตัวกรองการตรวจจับขอบ Sobel


9

ในส่วนที่เกี่ยวกับหัวข้อนี้ฉันได้ใช้ตัวกรองการตรวจจับขอบ Sobelใน GLSL เรียบร้อยแล้ว นี่คือรหัสส่วนของตัวกรอง:

#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);
} 

และนี่คือผลลัพธ์ของ cube ที่มีการตรวจจับขอบ Sobel:

Cube พร้อมตัวกรองการตรวจจับขอบ Sobel

หากคุณขยายภาพคุณจะเห็นว่ามี "เสียง" จำนวนมากที่ผลิตโดย Sobel: มีแถบแนวนอนสีเทาทั่วฉากเนื่องจากการไล่ระดับสีฟ้า / ขาว ยิ่งไปกว่านั้นกรวยแสงสร้างรูปแบบที่ไม่พึงประสงค์บนก้อน ขอบสีดำทางด้านซ้ายของลูกบาศก์ดูเหมือนจะจางหายไปเพราะกรวยแสงที่ครึ่งซ้ายของลูกบาศก์

ดังนั้นฉันจึงอ่านบทความนี้ซึ่งระบุว่าควรมีภาพระดับสีเทาก่อนและใช้ตัวกรองเบลอ Gaussian เพื่อทำให้ขอบชัดเจนยิ่งขึ้น ที่ด้านล่างของบทความนอกจากนี้ยังมีตัวกรองการตรวจจับขอบแสนรู้ซึ่งดูเหมือนจะให้ผลลัพธ์ที่ดีกว่า

ตอนนี้ฉันมีสองคำถาม:

  1. ขั้นตอนต่อไปนี้ถูกต้องเพื่อให้ได้ผลลัพธ์การตรวจจับขอบที่ดีที่สุด:

    • โทนสีเทา
    • เกาส์เบลอ
    • การตรวจจับขอบ Sobel / Canny
  2. ถ้าใช่ฉันจะรวมรูปภาพต้นฉบับกับรูปภาพที่ประมวลผลได้อย่างไร ฉันหมายถึงหลังจากดำเนินการตามขั้นตอนข้างต้นแล้วฉันจะได้ภาพที่มีสีดำสนิทขอบสีขาวหรือ verca ฉันจะวางขอบบนรูปภาพ / พื้นผิวต้นฉบับของฉันได้อย่างไร

ขอบคุณสำหรับความช่วยเหลือของคุณ!


ฉันสงสัยว่าคุณอาจได้รับผลลัพธ์ที่คุณต้องการโดยใช้การตั้งค่าสถานะขอบของ OpenGL ในบางวิธี ดูเหมือนว่าจะวาดเฉพาะขอบระหว่างจุดยอดที่มีการตั้งค่าสถานะขอบเมื่ออยู่ในโหมดบรรทัด มีคำอธิบายที่นี่ (ฉันไม่ได้ใช้มันเองหรือฉันจะโพสต์ตัวอย่าง)
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) คุณสามารถเขียนถึงพวกเขาด้วยการประกาศผลการหลาย shaders ส่วนของคุณ (ใช้ในการทำได้ด้วยgl_FragData; ทางใดทางหนึ่งให้ดูglDrawBuffers)

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับหัวข้อค้นหา"Multi Render Target" (MRT)


ข้อมูลที่ดีขอบคุณ Julien อีกหนึ่งคำถาม: ฉันจะใช้ความลึกหรือข้อมูลปกติในส่วนของฉันได้อย่างไร ฉันยังค่อนข้างใหม่กับ GLSL และดังนั้นจึงไม่มีความคิดวิธีรวมค่าในอัลกอริทึม Sobel
enne87

2
เมื่อคุณสร้าง framebuffer สำหรับการแสดงผลของคุณคุณสามารถแนบมากกว่าหนึ่งพื้นผิว หากคุณแนบพื้นผิวความลึกมันจะถูกใช้โดยอัตโนมัติเพื่อความลึก มันคุณแนบพื้นผิวสีอื่นที่คุณสามารถเขียนลงในมันแยกต่างหาก (ดูopengl.org/sdk/docs/man/html/glDrawBuffers.xhtml ) คุณลักษณะที่เรียกว่า "Multi Render Target" (MRT)
Julien Guertault

@ enne87: ยินดีที่จะช่วย :)
Julien Guertault

@trichoplax: ขอบคุณสำหรับคำแนะนำ; เสร็จแล้ว
Julien Guertault
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.