OpenGL के साथ एक द्विआधारी छवियों में कोनों का पता लगाने के लिए कैसे?


13

मेरे पास बाइनरी 160x120 चित्र हैं जैसे:

मूल छवि

मैं उन सफ़ेद बूँद के कोनों का पता लगाना चाहूँगा। वे पहले गणितीय आकृति विज्ञान द्वारा बंद कर दिए गए हैं इसलिए कोई आंतरिक कोनों नहीं होना चाहिए। इस विशिष्ट मामले में, मुझे 16 कोने चाहिए, जैसे:

कोनों का पता लगाने का उदाहरण

मेरा पहला प्रयास कुछ OpenCV फ़ंक्शंस जैसे GoodFeaturesToTrack या FAST का उपयोग कर रहा था, लेकिन वे विशेष रूप से धीमे हैं (प्लस FAST बहुत अस्थिर है)। मेरा विचार GPU पर इस तरह की गणना करने का होगा, क्योंकि मेरी स्रोत छवि इससे आती है। मैंने इस तरह के शेड्स लिखने के लिए वेब पर विचारों की तलाश की (मैं OpenGL ES 2.0 का उपयोग कर रहा हूं), लेकिन कुछ भी ठोस नहीं मिला। किसी भी विचार कैसे मैं इस तरह के एक एल्गोरिथ्म शुरू कर सकता है?


2
फास्ट धीमी है? :)
एंडोलिथ

1
हाँ, मज़ेदार सही? वास्तव में, यह SURF या SIFT जैसे पूर्ववर्ती एल्गोरिदम की तुलना में तेज़ है, लेकिन यह कम सटीक है, एक छवि से दूसरी छवि में काफी अस्थिर है और अभी भी सीपीयू पर होने के लिए पर्याप्त तेज़ नहीं है
स्टीफन पेचर्ड 12-12-2017

हर फ्रेम पर इनका सही-सही पता लगाना कितना महत्वपूर्ण है? आयतें कितनी जल्दी चलती हैं? क्या अधिकांश फ़्रेमों पर कोनों का पता लगाना और उन्हें उन फ़्रेमों पर प्रक्षेपित करना ठीक है, जहां एल्गोरिथ्म याद करता है?
justis

@ अन्याय ठीक है, जिस तरह से मैं इसे अभी (OpenCV के cvFindContours () और cvApproxPoly () फ़ंक्शन के उपयोग के माध्यम से) समय के साथ बहुत स्थिर नहीं है, इसलिए मैं एक कम-पास फिल्टर के साथ परिणाम को फ़िल्टर करता हूं, लैग को पेश करता है। क्या आपको लगता है कि मैं प्रक्षेप के साथ अधिक स्थिर परिणाम प्राप्त कर सकता हूं?
स्टीफन पेचार्ड

जवाबों:


3

आप किस आकार की छवियां संचालित कर रहे हैं? किस फ्रेम दर पर? किस हार्डवेयर पर? तेजी से सुंदर है, मेरे अनुभव में तेजी से erm।

मैंने यह भी देखा है कि FAST का उपयोग ROF डिटेक्टर के रूप में किया जाता है, जिसके साथ ROF पर चलाए जाने वाले ROF डिटेक्टर होते हैं, जो पूरी छवि पर GFTT के दंड को चलाने के बिना बेहतर स्थिरता प्रदान करने के लिए पहचाने जाते हैं।

"हैरिस" कोने डिटेक्टर भी संभवतः बहुत जल्दी के रूप में यह बहुत ही सरल संचालन से बना है (कोई sqrt () उदाहरण के लिए पिक्सेल प्रति!) - नहीं gFTT के रूप में स्थिर के रूप में है, लेकिन संभवतः अधिक इतनी तेजी से।

(GPU कार्यान्वयन के संदर्भ में, Googling gpu cornerकाफी लिंक प्रस्तुत करता है, लेकिन मुझे पता नहीं है कि वे कितने उपयुक्त हो सकते हैं - मैं FPGA में लागू होता हूं।)


मेरी छवियां 160x120 हैं, माना जाता है कि 30fps पर, एक iPhone पर, लेकिन निश्चित रूप से, आवेदन करने के लिए बहुत कुछ है :-) मैंने एक ऐप को ऐसे डिवाइस पर बहुत तेज़ी से लागू करते देखा है, लेकिन यह केवल एक डेमो था कर रहा हूँ ... यही कारण है कि मैं gpu आधारित समाधान की ओर देख रहा हूँ।
स्टीफन पेचर्ड

15

मैं अभी कुछ इसी तरह से OpenGL ES 2.0 पर हैरिस कॉर्नर डिटेक्शन का उपयोग करते हुए किया जा रहा था, और जब तक मैं पूरी तरह से समाप्त नहीं हो जाता, मैंने सोचा कि मैं अब तक मेरे द्वारा किए गए shader- आधारित कार्यान्वयन को साझा करूँगा। मैंने इसे एक iOS- आधारित ओपन सोर्स फ्रेमवर्क के हिस्से के रूप में किया है , ताकि आप कोड की जांच कर सकें कि आप कुछ विशेष चरण में कैसे काम करते हैं।

ऐसा करने के लिए, मैं निम्नलिखित चरणों का उपयोग करता हूं:

  • वेक्टर (0.2125, 0.7154, 0.01521) के साथ आरजीबी मूल्यों के एक डॉट उत्पाद का उपयोग करके छवि को इसके ल्यूमिनेंस मानों तक कम करें।
  • वर्तमान पिक्सेल के बाएँ और दाएँ और ऊपर और नीचे पिक्सेल से लाल चैनल मान घटाकर एक्स और वाई डेरिवेटिव की गणना करें। मैं फिर लाल चैनल में एक्स व्युत्पन्न वर्ग, ग्रीन चैनल में वाई व्युत्पन्न वर्ग और नीले चैनल में एक्स और वाई डेरिवेटिव के उत्पाद को संग्रहीत करता हूं। इस के लिए टुकड़ा shader निम्नलिखित की तरह लग रहा है:

    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 का वर्णन करता हूं ।

  • धुंधला इनपुट व्युत्पन्न मूल्यों का उपयोग करके वास्तविक हैरिस कोने का पता लगाने की गणना करें। इस मामले में, मैं वास्तव में उसके पीएच.डी. में एलिसन नोबल द्वारा वर्णित गणना का उपयोग कर रहा हूं। शोध प्रबंध "छवि सतहों का वर्णन"। इसे संभालने वाला शेड निम्न की तरह दिखता है:

    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);
    }
    
  • स्थानीय गैर-अधिकतम दमन का प्रदर्शन करें और पास होने वाले पिक्सेल को उजागर करने के लिए एक सीमा लागू करें। मैं एक केंद्रीय पिक्सेल के पड़ोस में आठ पिक्सेल का नमूना देने के लिए निम्न खंड shader का उपयोग करता हूं और यह पहचानता हूं कि उस समूह में अधिकतम है या नहीं:

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

यह प्रक्रिया आपकी वस्तुओं से एक कोने का नक्शा बनाती है जो इस तरह दिखता है:

मकई का नक्शा

निम्नलिखित बिंदुओं को गैर-अधिकतम दमन और थ्रेसहोल्डिंग के आधार पर कोनों के रूप में पहचाना जाता है:

कोनों की पहचान की

इस फ़िल्टर के लिए उचित थ्रॉल्ड्स सेट करने के साथ, यह इस छवि के सभी 16 कोनों की पहचान कर सकता है, हालाँकि यह ऑब्जेक्ट के वास्तविक किनारों के अंदर कोनों को पिक्सेल के रूप में रखने की प्रवृत्ति रखता है।

IPhone 4 पर, कैमरे से आने वाले वीडियो के 640x480 फ्रेम पर इस कोने का पता 20 एफपीएस पर चलाया जा सकता है, और एक iPhone 4S आसानी से 60+ FPS पर उस आकार के वीडियो को प्रोसेस कर सकता है। इस तरह के कार्य के लिए सीपीयू-बाउंड प्रोसेसिंग की तुलना में यह एक अच्छा सौदा होना चाहिए, हालांकि अभी पॉइंट्स वापस पढ़ने की प्रक्रिया सीपीयू-बाउंड है और इसके मुकाबले थोड़ा धीमा होना चाहिए।

यदि आप इसे क्रिया में देखना चाहते हैं तो आप मेरी रूपरेखा के लिए कोड को पकड़ सकते हैं और इसके साथ आने वाले FilterShowcase उदाहरण को चला सकते हैं। हैरिस कॉर्नर डिटेक्शन उदाहरण डिवाइस कैमरा से लाइव वीडियो पर चलता है, हालांकि जैसा कि मैंने वर्तमान में सीपीयू पर कोने के बिंदुओं के रीडिंग बैक का उल्लेख किया है, जो वास्तव में यह धीमा है। मैं इसके लिए GPU-आधारित प्रक्रिया पर जा रहा हूं, साथ ही।


1
बहुत अच्छा! मैं जीथब पर आपके ढांचे का पालन करता हूं, यह वास्तव में दिलचस्प लगता है, बधाई!
स्टीफन पेकार्ड

क्या आपके पास कहीं एक उदाहरण है कि कोने के निर्देशांक कैसे प्राप्त करें वास्तव में सीपीयू में वापस? वहाँ कुछ स्मार्ट GPU तरीका है या यह एक बिटबैक की आवश्यकता है और फिर सीपीयू पर चिह्नित बिटमैप के माध्यम से चिह्नित पिक्सल की तलाश में है?
क्वासिमोंडो '

@ क्वसीमोंडो - मैं पॉइंट एक्सट्रैक्शन के लिए हिस्टोग्राम पिरामिड का उपयोग करने पर काम कर रहा हूं: कोने का पता लगाने के लिए पिक्सल पर सीपीयू-बाउंड पुनरावृत्ति से बचने के लिए tevs.eu/files/vmv06.pdf । हाल ही में थोड़ा विचलित हुआ है, इसलिए इसे समाप्त नहीं किया है, लेकिन मैं जल्द ही करना चाहता हूं।
ब्रैड लार्सन

हाय @BradLarson, मुझे पता है कि यह एक बहुत पुराना धागा है और आपके उत्तर के लिए धन्यवाद। मैं अभी GPUImage ढांचे में KGPUImageHarrisCornerDetection.m की जाँच करता हूँ। छवि से कोने के स्थान को निकालने के लिए, आपने बफर में छवि को पढ़ने के लिए glReadPixels का उपयोग किया है और फिर एक सरणी में colotByte> 0 के साथ अंक स्टोर करने के लिए बफर पर लूप किया है। क्या GPU में यह सब करने का कोई तरीका है जहाँ हमें बफर और लूप में इमेज नहीं पढ़ना है?
साहिल बजाज

1
@SahilBajaj - एक तकनीक जिसे मैंने देखा है (और अभी तक लागू करने का समय नहीं था) हिस्टोग्राम पिरामिड का उपयोग इस तरह की विरल छवियों से बिंदुओं का तेजी से निष्कर्षण करने के लिए किया जाता है। यह महत्वपूर्ण रूप से इसे गति देगा।
ब्रैड लार्सन

3

शी-टॉमासी और मोरवेक जैसे "रोबस्ट" कॉर्नर डिटेक्टर कुख्यात हैं। उन्हें यहाँ देखें - http://en.wikipedia.org/wiki/Corner_detection FAST शायद एकमात्र अच्छा पर्याप्त हल्का हल्का डिटेक्टर है। आप गैर-अधिकतम दमन करके FAST में सुधार कर सकते हैं - सर्वश्रेष्ठ "कॉर्नर्न" स्कोर के साथ फास्ट आउटपुट को चुना (इसे गणना करने के लिए कई सहज तरीके हैं, जिसमें शि-टॉमासी और मोरवेक को कॉर्नर्नस स्कोर के रूप में शामिल किया गया है) आपके पास कई फास्ट डिटेक्टरों का विकल्प भी है - FAST-5 से FAST-12 और FAST_ER (अंतिम एक शायद मोबाइल के लिए बहुत बड़ा है) दूसरा तरीका है FAST उत्पन्न करना - लेखक साइट से FAST कोड जनरेटर प्राप्त करें और इसे संभावित छवियों के सेट पर प्रशिक्षित करें। http://www.edwardrosten.com/work/fast.html


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.