ওপেনজিএল দিয়ে বাইনারি চিত্রগুলিতে কোণগুলি কীভাবে সনাক্ত করবেন?


13

আমার বাইনারি 160x120 চিত্র রয়েছে যেমন:

মূল চিত্র

আমি white সাদা ব্লবগুলির কোণগুলি সনাক্ত করতে চাই। এগুলি আগে গাণিতিক রূপচর্চা দ্বারা বন্ধ করা হয় যাতে কোনও অভ্যন্তর কোণ থাকে না। এই নির্দিষ্ট ক্ষেত্রে, আমি 16 কোণ চাই, যেমন:

কোণ সনাক্তকরণের উদাহরণ

আমার প্রথম প্রয়াসটি ওপেনসিভি ফাংশন যেমন গুডফাইটারসটোট্র্যাক বা ফাস্ট ব্যবহার করছিল তবে সেগুলি বিশেষ ধীরে ধীরে ( দ্রুততম খুব অস্থির)। আমার ধারণাটি জিপিইউতে যেমন একটি গণনা করা হবে, কারণ আমার উত্সের চিত্রটি এটি থেকে আসে। আমি কীভাবে এই জাতীয় শেডার লিখতে হয় তার জন্য ওয়েবে ধারণাগুলি সন্ধান করেছি (আমি ওপেনজিএল ইএস ২.০ ব্যবহার করছি), তবে কংক্রিটের কিছুই পাই নি। কোনও ধারণা কীভাবে আমি এই জাতীয় অ্যালগরিদম শুরু করতে পারি?


2
দ্রুত ধীর? :)
এন্ডোলিথ

1
হ্যাঁ, মজার কথা? প্রকৃতপক্ষে, এটি SURF বা SIFT এর মতো পূর্ববর্তী অ্যালগরিদমের চেয়ে দ্রুত, তবে এটি কম সুনির্দিষ্ট, এক চিত্র থেকে অন্য ছবিতে বেশ অস্থির এবং সিপিইউতে এখনও পর্যাপ্ত পর্যাপ্ত নয়
স্টাফেন পাচার্ড

এগুলি প্রতিটি ফ্রেমে সঠিকভাবে সনাক্ত করা কতটা গুরুত্বপূর্ণ? আয়তক্ষেত্রগুলি কত দ্রুত সরে যায়? বেশিরভাগ ফ্রেমের কোণগুলি সনাক্ত করা এবং অ্যালগরিদমটি যে ফ্রেমে মিস হয় সেগুলিতে এগুলি ফাঁকা করে দেওয়া কি ঠিক আছে?
Justis

@ ঠিক আছে, এখনই আমি যেভাবে এটি করি (ওপেনসিভির সিভিফাইন্ডকন্টারস () এবং সিভি অ্যাপ্রোক্সপলি () ফাংশনগুলি ব্যবহার করে) সময়ের সাথে সাথে খুব স্থিতিশীল নয়, তাই আমি লগটি প্রবর্তন করে লো-পাস ফিল্টার দিয়ে ফলাফল ফিল্টার করি। আপনি কি মনে করেন যে আমি কোনও প্রদাহের সাথে আরও স্থিতিশীল ফলাফল পেতে পারি?
স্টাফেন পাচার্ড

উত্তর:


3

আপনি কোন আকারের চিত্রগুলি পরিচালনা করছেন? কোন ফ্রেমের হারে? কি হার্ডওয়্যার? দ্রুততম আমার অভিজ্ঞতার থেকে সুন্দর।

পুরো ইমেজে জিএফটিটি-র জরিমানা না চালিয়ে আরও ভাল স্থিতিশীলতা সরবরাহের জন্য চিহ্নিত আরএআইআই-তে চালিত গুডফিটচার্স টো ট্র্যাকের সাথে আরওআই ডিটেক্টর হিসাবেও দ্রুত ব্যবহার করেছি।

"হ্যারিস" কোণ আবিষ্কারক এছাড়াও সম্ভাব্য খুব দ্রুত যেমন খুব সহজ অপারেশন দিয়ে তৈরি হয় (কোন বর্গমূল () উদাহরণস্বরূপ পিক্সেল প্রতি!) - না gFTT যেমন স্থিতিশীল, কিন্তু সম্ভবত আরও এত দ্রুত নয়।

(জিপিইউ বাস্তবায়নের ক্ষেত্রে, গুগলিং gpu cornerবেশ কয়েকটি লিঙ্ক উপস্থাপন করেছে বলে মনে হয় তবে এগুলি কতটা উপযুক্ত হতে পারে সে সম্পর্কে আমার কোনও ধারণা নেই - আমি এফপিজিএতে প্রয়োগ করার ঝোঁক।)


আমার চিত্রগুলি একটি আইফোনে 30fps- তে অনুমিতভাবে 160x120, তবে অবশ্যই অ্যাপ্লিকেশনটিতে আরও অনেক কিছু করার রয়েছে :-) আমি এমন একটি ডিভাইসে খুব দ্রুত দ্রুত প্রয়োগকারী একটি অ্যাপ্লিকেশন দেখেছি, তবে এটি কেবল একটি ডেমো ছিল এটি করছে ... এজন্য আমি জিপিইউ-ভিত্তিক সমাধানগুলির দিকে চেয়ে আছি।
স্টাফেন পেচার্ড

15

আমি হ্যারিস কর্নার সনাক্তকরণ ব্যবহার করে ওপেনজিএল ইএস 2.0 তে এরকম কিছু বাস্তবায়ন করতে পেরেছি এবং আমি সম্পূর্ণরূপে শেষ না হওয়ার পরে, আমি ভেবেছিলাম যে আমি এখনও অবধি শ্যাডার-ভিত্তিক বাস্তবায়নটি ভাগ করব। আমি এটি কোনও আইওএস-ভিত্তিক ওপেন সোর্স ফ্রেমওয়ার্কের অংশ হিসাবে করেছি , যাতে কোনও বিশেষ পদক্ষেপ কীভাবে কাজ করে সে সম্পর্কে আপনি যদি আগ্রহী হন তবে আপনি কোডটি পরীক্ষা করে দেখতে পারেন।

এটি করতে, আমি নিম্নলিখিত পদক্ষেপগুলি ব্যবহার করি:

  • ভেক্টর (0.2125, 0.7154, 0.0721) দিয়ে আরজিবি মানগুলির একটি বিন্দু পণ্য ব্যবহার করে চিত্রটিকে তার আলোকিত মানগুলিতে হ্রাস করুন।
  • বাম এবং ডান এবং বর্তমান পিক্সেলের উপরে এবং নীচে পিক্সেলগুলি থেকে লাল চ্যানেল মানগুলি বিয়োগ করে এক্স এবং ওয়াই ডেরিভেটিভগুলি গণনা করুন। আমি তখন লাল চ্যানেলে এক্স ডেরিভেটিভ স্কোয়ার, সবুজ চ্যানেলে 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);
    }
    

    যেখানে তারতম্যগুলি কেবল প্রতিটি দিকের অফসেট জমিনের স্থানাঙ্ক হয়। নির্ভরশীল টেক্সচার পাঠগুলি, যা এই মোবাইলের জিপিইউগুলিতে কুখ্যাত slow

  • এই ডেরাইভেটিভ চিত্রটিতে গাউসিয়ান ব্লার প্রয়োগ করুন। আমি একটি পৃথক অনুভূমিক এবং উল্লম্ব অস্পষ্টতা ব্যবহার করেছি, এবং প্রতিটি পাসে কেবল পাঁচটি টেক্সচার পড়ার সাথে নয়টি-হিট ব্লার করার জন্য হার্ডওয়্যার টেক্সচার ফিল্টারিংয়ের সুবিধা নেব। আমি এই স্ট্যাক ওভারফ্লো উত্তরে এই শেডারটি বর্ণনা করছি ।

  • অস্পষ্ট ইনপুট ডেরিভেটিভ মানগুলি ব্যবহার করে প্রকৃত হ্যারিস কর্নার সনাক্তকরণ গণনা চালান। এই ক্ষেত্রে, আমি আসলে তার পিএইচডি তে অ্যালিসন নোবেলের দ্বারা বর্ণিত গণনাটি ব্যবহার করছি। গবেষণাপত্র "চিত্র পৃষ্ঠার বর্ণনা"। এইটি হ্যান্ডেল করে শেডারটি নীচের মত দেখাচ্ছে:

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

এই প্রক্রিয়াটি আপনার অবজেক্টগুলি থেকে এমন এক কোণার মানচিত্র উত্পন্ন করে যা দেখে মনে হয়:

কর্নার মানচিত্র

নিম্নলিখিত পয়েন্টগুলি সর্বাধিক দমন এবং প্রান্তিকের উপর ভিত্তি করে কোণ হিসাবে চিহ্নিত করা হয়েছে:

চিহ্নিত কর্নার

এই ফিল্টারটির জন্য যথাযথ প্রান্তিক ধার্য সেট করে, এটি এই চিত্রের সমস্ত 16 টি কোণ সনাক্ত করতে পারে, যদিও এটি কোণারটিকে পিক্সেল বা তার অবজেক্টের আসল প্রান্তগুলির মধ্যে রাখে।

একটি আইফোন 4 এ, এই কোণার সনাক্তকরণটি ক্যামেরা থেকে আসা 640x480 ফ্রেমের ভিডিওতে 20 এফপিএসে চালানো যেতে পারে এবং একটি আইফোন 4 এস সহজেই 60+ এফপিএস এ আকারের ভিডিওটি প্রক্রিয়া করতে পারে। এটির মতো কোনও কাজের জন্য সিপিইউ-বাউন্ড প্রসেসিংয়ের চেয়ে দ্রুত একটি ভাল চুক্তি হওয়া উচিত, যদিও এই মুহূর্তে পয়েন্টগুলি পড়ার প্রক্রিয়াটি সিপিইউ-আবদ্ধ এবং তার চেয়ে সামান্য ধীর হওয়া উচিত।

আপনি যদি এটিকে ক্রিয়াতে দেখতে চান তবে আপনি আমার কাঠামোর কোডটি ধরতে পারেন এবং এটির সাথে উপস্থিত ফিল্টারশোভাস উদাহরণটি চালাতে পারেন। হ্যারিস কর্নার সনাক্তকরণের উদাহরণটি ডিভাইস ক্যামেরা থেকে সরাসরি ভিডিওতে চালিত হয়েছে, যদিও আমি যেমন কর্নার পয়েন্টের রিডিং ব্যাকটি উল্লেখ করেছি বর্তমানে এটি সিপিইউতে ঘটে যা সত্যিই এটি ধীর করে দিচ্ছে। আমি এর জন্য জিপিইউ-ভিত্তিক প্রক্রিয়াতে চলেছি।


1
খুব সুন্দর! আমি গিথুব আপনার কাঠামো অনুসরণ, এটি সত্যিই আকর্ষণীয় বলে মনে হচ্ছে, সম্মিলিত!
স্টাফেন পেচার্ড

কোণার স্থানাঙ্কগুলি কীভাবে সিপিইউতে ফিরে পাবেন কীভাবে আপনার কোনও উদাহরণ রয়েছে? কিছু স্মার্ট জিপিইউ উপায় আছে বা এর জন্য কি রিডব্যাকের দরকার পড়ে এবং তারপরে চিহ্নিত পিক্সেলগুলি অনুসন্ধান করে ফিরে আসা বিটম্যাপের মাধ্যমে সিপিইউতে লুপিং করা দরকার?
কোয়াসিমন্ডো

@ ক্যাসিমোনডো - কোণার সনাক্তকরণের জন্য পিক্সেলের উপরে সিপিইউ- গতির পুনরাবৃত্তি এড়ানোর জন্য আমি পয়েন্ট এক্সট্রাকশনের জন্য হিস্টোগ্রাম পিরামিডগুলি ব্যবহার করার কাজ করছি: tevs.eu/files/vmv06.pdf ইদানীং কিছুটা বিভ্রান্ত হয়ে পড়েছে, তাই এটি পুরোপুরি শেষ হয়নি, তবে আমি শীঘ্রই চাই।
ব্র্যাড লারসন

হাই ব্র্যাডলারসন, আমি জানি এটি একটি খুব পুরানো থ্রেড এবং আপনার উত্তরের জন্য আপনাকে ধন্যবাদ। আমি স্রেফ জিপিইউআইজেজ ফ্রেমওয়ার্কে কেজিপিইউআইমেজহরিস কর্নার ডিটেকশন.এম পরীক্ষা করেছি। চিত্র থেকে কোণার অবস্থান বের করতে, আপনি বাফারে চিত্রটি পড়তে glReadPixels ব্যবহার করেছেন এবং তারপরে একটি অ্যারেতে কলোটবাইট> 0 দিয়ে পয়েন্টগুলি সংরক্ষণ করতে বাফারে লুপ করেছেন। জিপিইউতে এই সমস্ত কিছু করার কোনও উপায় আছে যেখানে আমাদের বাফার এবং লুপে চিত্রটি পড়তে হবে না?
সাহিল বাজাজ

1
@ সাহিলবাজ - একটি কৌশল যা আমি দেখেছি (এবং এখনও প্রয়োগের সময় হয়নি) হিস্টোগ্রাম পিরামিডগুলি ব্যবহার করে এর মতো ছড়িয়ে থাকা চিত্রগুলির থেকে পয়েন্টগুলি দ্রুত উত্তোলনের জন্য। এটি উল্লেখযোগ্যভাবে এই গতি হবে।
ব্র্যাড লারসন

3

শি-তোমাসি এবং মোরাভেকের মতো "রবস্ট" কর্নার ডিটেক্টরগুলি কুখ্যাতভাবে ধীরে ধীরে। তাদের এখানে পরীক্ষা করুন - http://en.wikedia.org/wiki/Corner_detection FAST সম্ভবত কেবলমাত্র যথেষ্ট ভাল লাইটওয়েট কর্নার ডিটেক্টর। আপনি সর্বাধিক দমন না করে দ্রুত উন্নতি করতে পারেন - সেরা "কর্নারনেস" স্কোর সহ দ্রুততম আউটপুট বেছে নিয়েছেন (শিণা-টমাসি এবং মোরাভেক সহ কর্নারেন্স স্কোর হিসাবে এটি গণনা করার কয়েকটি স্বজ্ঞাত উপায় রয়েছে) আপনার বেশ কয়েকটি FAST ডিটেক্টর থেকেও একটি পছন্দ রয়েছে - 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.