วิธีการตรวจหามุมในภาพไบนารีด้วย OpenGL?


13

ฉันมีภาพไบนารีขนาด 160x120 เช่น:

ภาพต้นฉบับ

ฉันต้องการตรวจหามุมของหยดสีขาวเหล่านั้น ก่อนหน้านี้พวกเขาถูกปิดโดยสัณฐานวิทยาทางคณิตศาสตร์ดังนั้นจึงไม่ควรมีมุมด้านใน ในกรณีเฉพาะนี้ฉันต้องการ 16 มุมเช่น:

ตัวอย่างของการตรวจจับมุม

ความพยายามครั้งแรกของฉันคือการใช้ฟังก์ชั่น OpenCV บางอย่างเช่นgoodFeaturesToTrackหรือFASTแต่มันช้ามากเป็นพิเศษ (บวกกับ FAST นั้นไม่เสถียรมาก) ความคิดของฉันคือการคำนวณเช่นนี้ใน GPU เนื่องจากภาพต้นฉบับของฉันมาจากมัน ฉันค้นหาความคิดบนเว็บเกี่ยวกับวิธีการเขียนเฉดสี (ฉันใช้ OpenGL ES 2.0) แต่ไม่มีอะไรเป็นรูปธรรม ความคิดใดที่ฉันจะเริ่มอัลกอริธึมแบบนั้นได้?


2
FAST ช้าไหม :)
endolith

1
ใช่ตลกใช่มั้ย ในความเป็นจริงมันเร็วกว่าอัลกอริธึมแบบก่อนหน้าเช่น SURF หรือ SIFT แต่แม่นยำน้อยกว่าค่อนข้างไม่แน่นอนจากภาพหนึ่งไปยังอีกภาพหนึ่งและยังไม่เร็วพอที่จะทำบนซีพียู
StéphanePéchard

การตรวจจับสิ่งเหล่านี้ในทุกเฟรมมีความสำคัญอย่างไร สี่เหลี่ยมเคลื่อนไหวเร็วแค่ไหน? ตกลงหรือไม่ที่จะตรวจจับมุมในเฟรมส่วนใหญ่และทำการแทรกเข้าไปในเฟรมที่อัลกอริธึมหายไป?
justis

@ เพียงแค่วิธีที่ฉันทำตอนนี้ (ผ่านการใช้ฟังก์ชั่น cvFindContours () และ cvApproxPoly () ของ OpenCV นั้นไม่เสถียรตลอดเวลาดังนั้นฉันจึงกรองผลลัพธ์ด้วยตัวกรอง low-pass ทำให้เกิดความล่าช้า คุณคิดว่าฉันจะได้ผลลัพธ์ที่มีเสถียรภาพมากขึ้นด้วยการแก้ไขหรือไม่?
StéphanePéchard

คำตอบ:


3

คุณใช้รูปขนาดอะไร อัตราเฟรมเท่าไหร่ เกี่ยวกับฮาร์ดแวร์อะไร FAST เป็นคนสวย, คนอื่น ๆ , เร็วในประสบการณ์ของฉัน

ฉันเคยเห็น FAST ใช้เป็นเครื่องตรวจจับ ROI ด้วยการทำงานที่ดีคุณลักษณะติดตามบน ROIs ที่ระบุว่าให้ความเสถียรที่ดีขึ้นโดยไม่เรียกใช้ค่าปรับ gFTT ในภาพรวมทั้งหมด

เครื่องมือตรวจจับมุม "แฮร์ริส"นั้นอาจเร็วมากเนื่องจากมันประกอบไปด้วยการทำงานที่ง่ายมาก (ไม่มี sqrt () ต่อพิกเซลเช่นกัน!) - ไม่เสถียรเท่า gFTT แต่อาจมากกว่า FAST

(ในแง่ของการใช้งาน GPU gpu cornerดูเหมือนว่าGoogling จะมีลิงค์จำนวนมาก แต่ฉันไม่รู้ว่ามันเหมาะสมแค่ไหน - ฉันมักจะนำไปใช้ใน FPGA)


ภาพของฉันมีขนาด 160x120 ซึ่งคาดว่าจะอยู่ที่ 30fps บน iPhone แต่แน่นอนว่าแอปพลิเคชั่นมีอีกมากที่ต้องทำ :-) ฉันเห็นแอปที่ใช้งาน FAST ได้อย่างรวดเร็วบนอุปกรณ์ดังกล่าว แต่มันเป็นเพียงตัวอย่างเท่านั้น ทำอย่างนั้น ... นั่นเป็นเหตุผลที่ฉันกำลังมองหาโซลูชั่นที่ใช้ GPU
StéphanePéchard

15

ฉันเพิ่งจะนำสิ่งนี้ไปใช้ใน OpenGL ES 2.0 โดยใช้การตรวจจับมุมของแฮร์ริสและในขณะที่ฉันยังไม่เสร็จสมบูรณ์ ฉันได้ทำสิ่งนี้เป็นส่วนหนึ่งของกรอบงานโอเพ่นซอร์สบน iOSดังนั้นคุณสามารถตรวจสอบรหัสได้หากคุณสงสัยว่าขั้นตอนบางอย่างทำงานอย่างไร

เมื่อต้องการทำสิ่งนี้ฉันใช้ขั้นตอนต่อไปนี้:

  • ลดภาพให้เป็นค่าความส่องสว่างโดยใช้ผลิตภัณฑ์จุดของค่า RGB ที่มีเวกเตอร์ (0.2125, 0.7154, 0.0721)
  • คำนวณอนุพันธ์ X และ Y โดยการลบค่าช่องสีแดงจากพิกเซลซ้ายและขวาและด้านบนและด้านล่างของพิกเซลปัจจุบัน จากนั้นฉันก็เก็บอนุพันธ์ x กำลังสองในช่องสีแดง, อนุพันธ์ Y กำลังสองในช่องสีเขียวและผลิตภัณฑ์ของอนุพันธ์ X และ Y ในช่องสีฟ้า ตัวแบ่งส่วนสำหรับสิ่งนี้มีลักษณะดังนี้:

    precision highp float;
    
    varying vec2 textureCoordinate;
    varying vec2 leftTextureCoordinate;
    varying vec2 rightTextureCoordinate;
    
    varying vec2 topTextureCoordinate; 
    varying vec2 bottomTextureCoordinate;
    
    uniform sampler2D inputImageTexture;
    
    void main()
    {
     float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;
     float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;
     float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;
     float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;
    
     float verticalDerivative = abs(-topIntensity + bottomIntensity);
     float horizontalDerivative = abs(-leftIntensity + rightIntensity);
    
     gl_FragColor = vec4(horizontalDerivative * horizontalDerivative, verticalDerivative * verticalDerivative, verticalDerivative * horizontalDerivative, 1.0);
    }
    

    โดยที่ความแตกต่างเป็นเพียงพิกัดพื้นผิวออฟเซ็ตในแต่ละทิศทาง ฉันทำการคำนวณค่าล่วงหน้าเหล่านี้ใน Shader Vertex เพื่อกำจัดการอ่านค่าของพื้นผิวที่ขึ้นต่อกันซึ่งช้ามากใน GPU มือถือเหล่านี้

  • ใช้การเบลอแบบเกาส์กับภาพอนุพันธ์นี้ ฉันใช้การเบลอแนวนอนและแนวตั้งที่แยกจากกันและใช้ประโยชน์จากการกรองพื้นผิวของฮาร์ดแวร์เพื่อทำการเบลอที่ได้รับผลกระทบเก้าครั้งโดยมีเพียงห้าการอ่านพื้นผิวในแต่ละรอบ ผมอธิบาย Shader นี้ในคำตอบนี้กองมากเกิน

  • เรียกใช้การคำนวณการตรวจจับมุมแฮร์ริสที่แท้จริงโดยใช้ค่าอนุพันธ์ที่เบลอ ในกรณีนี้ฉันใช้การคำนวณที่อธิบายโดย Alison Noble ในปริญญาเอกของเธอ วิทยานิพนธ์ "คำอธิบายของภาพพื้นผิว" Shader ที่จัดการสิ่งนี้ดูเหมือนว่าต่อไปนี้:

    varying highp vec2 textureCoordinate;
    
    uniform sampler2D inputImageTexture;
    
    const mediump float harrisConstant = 0.04;
    
    void main()
    {
     mediump vec3 derivativeElements = texture2D(inputImageTexture, textureCoordinate).rgb;
    
     mediump float derivativeSum = derivativeElements.x + derivativeElements.y;
    
     // This is the Noble variant on the Harris detector, from 
     // Alison Noble, "Descriptions of Image Surfaces", PhD thesis, Department of Engineering Science, Oxford University 1989, p45.     
     mediump float harrisIntensity = (derivativeElements.x * derivativeElements.y - (derivativeElements.z * derivativeElements.z)) / (derivativeSum);
    
     // Original Harris detector
     //     highp float harrisIntensity = derivativeElements.x * derivativeElements.y - (derivativeElements.z * derivativeElements.z) - harrisConstant * derivativeSum * derivativeSum;
    
     gl_FragColor = vec4(vec3(harrisIntensity * 10.0), 1.0);
    }
    
  • ดำเนินการปราบปรามในพื้นที่ที่ไม่ใช่ค่าสูงสุดและใช้เกณฑ์เพื่อเน้นพิกเซลที่ผ่าน ฉันใช้ตัวแบ่งส่วนต่อไปนี้เพื่อสุ่มตัวอย่างแปดพิกเซลในละแวกของพิกเซลกลางและระบุว่าเป็นจำนวนสูงสุดในการจัดกลุ่มนั้นหรือไม่:

    uniform sampler2D inputImageTexture;
    
    varying highp vec2 textureCoordinate;
    varying highp vec2 leftTextureCoordinate;
    varying highp vec2 rightTextureCoordinate;
    
    varying highp vec2 topTextureCoordinate;
    varying highp vec2 topLeftTextureCoordinate;
    varying highp vec2 topRightTextureCoordinate;
    
    varying highp vec2 bottomTextureCoordinate;
    varying highp vec2 bottomLeftTextureCoordinate;
    varying highp vec2 bottomRightTextureCoordinate;
    
    void main()
    {
        lowp float bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate).r;
        lowp float bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;
        lowp float bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;
        lowp vec4 centerColor = texture2D(inputImageTexture, textureCoordinate);
        lowp float leftColor = texture2D(inputImageTexture, leftTextureCoordinate).r;
        lowp float rightColor = texture2D(inputImageTexture, rightTextureCoordinate).r;
        lowp float topColor = texture2D(inputImageTexture, topTextureCoordinate).r;
        lowp float topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate).r;
        lowp float topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate).r;
    
        // Use a tiebreaker for pixels to the left and immediately above this one
        lowp float multiplier = 1.0 - step(centerColor.r, topColor);
        multiplier = multiplier * 1.0 - step(centerColor.r, topLeftColor);
        multiplier = multiplier * 1.0 - step(centerColor.r, leftColor);
        multiplier = multiplier * 1.0 - step(centerColor.r, bottomLeftColor);
    
        lowp float maxValue = max(centerColor.r, bottomColor);
        maxValue = max(maxValue, bottomRightColor);
        maxValue = max(maxValue, rightColor);
        maxValue = max(maxValue, topRightColor);
    
        gl_FragColor = vec4((centerColor.rgb * step(maxValue, centerColor.r) * multiplier), 1.0);
    }
    

กระบวนการนี้สร้างแผนที่ cornerness จากวัตถุของคุณที่มีลักษณะดังนี้:

แผนที่ Cornerness

จุดต่อไปนี้ถูกระบุว่าเป็นมุมที่ขึ้นอยู่กับการปราบปรามที่ไม่สูงสุดและการทำซ้ำ

มุมที่ระบุ

ด้วยการตั้งค่าขีด จำกัด ที่เหมาะสมสำหรับตัวกรองนี้มันสามารถระบุทั้ง 16 มุมในภาพนี้ได้แม้ว่ามันจะมีแนวโน้มที่จะวางมุมเป็นพิกเซลหรือดังนั้นภายในขอบที่แท้จริงของวัตถุ

บน iPhone 4 การตรวจจับมุมนี้สามารถเรียกใช้ที่ 20 FPS บนเฟรมวิดีโอ 640x480 ที่มาจากกล้องและ iPhone 4S สามารถประมวลผลวิดีโอขนาดนั้นที่ 60+ FPS ได้อย่างง่ายดาย นี่ควรจะเร็วกว่าการประมวลผลที่เชื่อมต่อกับ CPU สำหรับภารกิจเช่นนี้ถึงแม้ว่าตอนนี้กระบวนการอ่านกลับจุดจะถูกผูกกับ CPU และช้ากว่าที่ควรจะเป็น

หากคุณต้องการที่จะเห็นสิ่งนี้ในการดำเนินการคุณสามารถคว้ารหัสสำหรับกรอบงานของฉันและเรียกใช้ตัวอย่าง FilterShowcase ที่มาพร้อมกับมัน ตัวอย่างการตรวจจับมุมของแฮร์ริสที่ทำงานบนวิดีโอสดจากกล้องของอุปกรณ์แม้ว่าฉันได้กล่าวถึงจุดอ่านมุมหลังที่เกิดขึ้นบนซีพียูในปัจจุบันซึ่งช้าลงมาก ฉันกำลังเข้าสู่กระบวนการที่ใช้ GPU สำหรับสิ่งนี้เช่นกัน


1
ดีมาก! ฉันทำตามกรอบของคุณใน GitHub ดูเหมือนว่าน่าสนใจจริงๆขอแสดงความยินดี!
StéphanePéchard

คุณมีตัวอย่างที่จะนำพิกัดมุมกลับไปที่ CPU จริงหรือไม่? มีวิธีสมาร์ท GPU บางอย่างหรือจำเป็นต้องมีการอ่านซ้ำแล้ววนซ้ำบน CPU ผ่านบิตแมปที่ส่งคืนเพื่อค้นหาพิกเซลที่ทำเครื่องหมายไว้หรือไม่
Quasimondo

@Quasimondo - ฉันพยายามใช้ปิรามิดฮิสโทแกรมสำหรับการแยกจุด: tevs.eu/files/vmv06.pdfเพื่อหลีกเลี่ยงการวนซ้ำของ CPU ที่ทับพิกเซลสำหรับการตรวจจับมุม รับฟุ้งซ่านเล็กน้อยเมื่อเร็ว ๆ นี้ดังนั้นจึงยังไม่เสร็จ แต่ฉันต้องการที่จะเร็ว ๆ นี้
Brad Larson

สวัสดี @BradLarson ฉันรู้ว่านี่เป็นด้ายเก่ามากและขอบคุณสำหรับคำตอบของคุณ ฉันเพิ่งตรวจสอบ KGPUImageHarrisCornerDetection.m ในกรอบงาน GPUImage ในการแยกตำแหน่งมุมออกจากรูปภาพคุณได้ใช้ glReadPixels เพื่ออ่านภาพในบัฟเฟอร์แล้ววนลูปบนบัฟเฟอร์เพื่อเก็บคะแนนด้วย colotByte> 0 ใน Array มีวิธีใดที่จะทำสิ่งนี้ใน GPU ที่เราไม่จำเป็นต้องอ่านภาพใน buffer และ loop หรือไม่?
Sahil Bajaj

1
@SahilBajaj - เทคนิคหนึ่งที่ฉันเคยเห็น (และยังไม่มีเวลานำไปใช้) คือใช้ปิรามิดฮิสโทแกรมเพื่อทำการแยกคะแนนอย่างรวดเร็วจากภาพที่เบาบางเช่นนี้ ที่จะเร่งความเร็วนี้อย่างมีนัยสำคัญ
Brad Larson

3

เครื่องตรวจจับมุม "แข็งแกร่ง" อย่าง Shi-Tomasi และ Moravec นั้นช้ามาก ตรวจสอบพวกเขาที่นี่ - http://en.wikipedia.org/wiki/Corner_detection FAST อาจเป็นเครื่องตรวจจับมุมที่มีน้ำหนักเบาเพียงตัวเดียวเท่านั้น คุณสามารถปรับปรุง FAST ได้ด้วยการปราบปรามที่ไม่มากที่สุดเลือกเอาท์พุท FAST ด้วยคะแนน "cornerness" ที่ดีที่สุด (มีหลายวิธีที่ใช้งานง่ายในการคำนวณรวมถึง Shi-Tomasi และ Moravec เป็นคะแนน cornerness) นอกจากนี้คุณยังมีตัวเลือกจาก จาก FAST-5 ถึง FAST-12 และ FAST_ER (อันสุดท้ายอาจใหญ่เกินไปสำหรับมือถือ) อีกวิธีคือสร้าง FAST - รับตัวสร้างโค้ด FAST จากไซต์ผู้เขียนและฝึกอบรมในชุดของภาพที่น่าจะเป็น http://www.edwardrosten.com/work/fast.html


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