मैं अभी कुछ इसी तरह से 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-आधारित प्रक्रिया पर जा रहा हूं, साथ ही।