نقوم بلصق عدة صور في صورة واحدة طويلة باستخدام رؤية الكمبيوتر

وصفت المقالات السابقة طريقة النقاط الست لفك الملصقات وكيف قمنا بتدريب الشبكة العصبية . توضح هذه المقالة كيفية لصق الأجزاء المصنوعة من زوايا مختلفة في صورة واحدة طويلة.





يتم تقسيم الملصقات مسبقًا ونشرها بواسطة الشبكة العصبية الموضحة في المقالة السابقة.







كيف يعمل اللصق بشكل عام؟ أنت بحاجة إلى التقاط صورتين متداخلتين ، وحساب التحول المتبادل وتركيب واحدة فوق الأخرى. يبدو الأمر بسيطًا جدًا ، ولكن دعنا ننتقل إلى كل خطوة من الخطوات.



لحساب التحول المتبادل ، تحتاج إلى العثور على بعض الكائنات الموجودة في كلتا الصورتين وحساب تحويل النقاط بطريقة ما من صورة إلى أخرى. يمكن تمثيل هذا التحول من خلال مصفوفة التحويل ، حيث تقوم عناصر المصفوفة بترميز عدة تحويلات في وقت واحد - القياس والترجمة والدوران.



يوجد جدول ممتاز على ويكيبيديا يوضح كيف وأي العناصر تؤثر على التحول.



كما ترى في الصورة أدناه ، هناك عدد كافٍ من الكائنات الشائعة:







ولكن هناك مشكلة في الكائنات المحددة - يصعب اكتشافها بطريقة حسابية. بدلاً من ذلك ، من المعتاد البحث عن كائنات أبسط - ما يسمى بـ "الزوايا" ، وهي أيضًا واصفات ("الواصفات" ، "الميزات").



هناك مقال رائع في وثائق OpenCV حول سبب سهولة تحديد الزوايا - باختصار ، تحديد الخط أمر سهل ، لكنه يمنحك إحداثيًا واحدًا فقط. لذلك ، من الضروري أيضًا اكتشاف الخط الثاني (غير المتوازي). إذا تقاربت عند نقطة ما ، فهذا المكان مثالي للعثور على واصف ، وهو أيضًا ركن (على الرغم من أن الواصفات الحقيقية ليست زوايا بالمعنى الهندسي للكلمة).



إحدى الخوارزميات الخاصة بإيجاد الواصفات هي SIFT (تحويل ميزة المقياس الثابت). على الرغم من أنه تم اختراعه في عام 1999 ، إلا أنه يتمتع بشعبية كبيرة بسبب بساطته وموثوقيته. تم تسجيل براءة اختراع هذه الخوارزمية ، لكن براءة الاختراع انتهت صلاحيتها هذا الربيع (2020). ومع ذلك ، لم يتمكنوا من نقله إلى التجميع الرئيسي لـ OpenCV ، لذلك تحتاج إلى استخدام بنية خاصة غير مجانية.



لنجد زوايا متشابهة في كلتا الصورتين:



sift = cv2.xfeatures2d.SIFT_create()
features_left = sift.detectAndCompute(left_image, None)






features_right = sift.detectAndCompute(left_image, None)






لنستخدم أداة تطابق Flann - فهي تتمتع بأداء جيد حتى لو كان عدد الواصفات كبيرًا.



KNN = 2
LOWE = 0.7
TREES = 5
CHECKS = 50

matcher = cv2.FlannBasedMatcher({'algorithm': 0, 'trees': TREES}, {'checks': CHECKS})
matches = matcher.knnMatch(left_descriptors, right_descriptors, k=KNN)

logging.debug("filtering matches with lowe test")

positive = []
for left_match, right_match in matches:
    if left_match.distance < LOWE * right_match.distance:
        positive.append(left_match)


توضح الخطوط الصفراء كيف وجد المطابق التطابقات.







كما ترى بوضوح ، لا يوجد سوى نصف التطابقات الصحيحة. ومع ذلك ، إذا كانت المطابقات الصحيحة تعطي دائمًا نفس التحويل ، فإن المطابقات غير الصحيحة تظهر اتجاهًا جديدًا بشكل فوضوي. أولئك. من الناحية النظرية ، يمكن فصلها بطريقة ما عن بعضها البعض:







إحدى الخوارزميات للعثور على التحويل الصحيح هي RANSAC. تعمل هذه الخوارزمية بشكل رائع عندما تريد فصل القيم الجيدة عن الضوضاء - هذا هو الحال تمامًا.



لحسن الحظ ، يحتوي OpenCV بالفعل على وظائف من شأنها العثور على مصفوفة التحويل عن طريق التطابقات باستخدام RANSAC ، أي في الواقع ، ليس عليك كتابة أي شيء.



دعنا نستخدم وظيفة EstimAffinePartial2D التي تبحث عن التحولات التالية: التدوير والقياس والترجمة (4 درجات من الحرية).



H, _ = cv2.estimateAffinePartial2D(right_matches, left_matches, False)


عندما يتم العثور على مصفوفة التحويل ، يمكننا تحويل الصورة الصحيحة للالتصاق.



الجزء الأيسر: الجزء





الأيمن:







أولاً ، دعنا نستخدم أبسط طريقة للصق الأجزاء معًا ، عندما يتم حساب كل بكسل من تقاطعها كمتوسط. لسوء الحظ ، كانت النتيجة جيدة جدًا - تتضاعف الصورة بشكل ملحوظ ، خاصة بالقرب من خط اللصق.







في الرسوم المتحركة ، يكون الفرق بين الإطارين أكثر وضوحًا:







هذا ليس مفاجئًا - تم التقاط الصور من زوايا مختلفة ، كما قامت الشبكة العصبية بتحويلها بشكل مختلف قليلاً ، ونتيجة لذلك ، كانت هناك اختلافات صغيرة.



من أجل اللصق السلس ، من الضروري تعويض التشوه غير الخطي. يمكن تمثيل التشويه كحقل متجه بنفس دقة الصورة الأصلية ، فقط بدلاً من اللون ، سيتم تشفير التحول في كل بكسل. هذا المجال المتجه يسمى "التدفق البصري".



بشكل عام ، هناك طرق مختلفة لحساب التدفق البصري - بعضها مبني مباشرة في OpenCV ، وهناك أيضًا شبكات عصبية خاصة.



في حالتنا ، سأحذف التقنية المحددة ، لكنني سأقوم بنشر النتيجة:







لكن التعويض يجب أن يتم بالتناسب مع كلا الجزأين. للقيام بذلك ، سنقسمه إلى مصفوفتين: الجزء







الأيسر سيتم تعويضه من اليسار إلى اليمين بطريقة متزايدة ، بينما الجزء الأيمن - العكس.



الآن كلا الجزأين يتداخلان بشكل مثالي تقريبًا:







الآن التراكب صحيح هندسيًا ، لكننا نلاحظ قفزة ملحوظة جدًا في السطوع عند اللحامات:







يمكن تصحيح هذه المشكلة بسهولة إذا تم تركيبها بتدرج بدلاً من القيم المتوسطة:







مع هذا النهج ، يكون التماس غير مرئي على الإطلاق: من







حيث المبدأ ، هناك أيضًا تقنيات لصق أخرى ، على سبيل المثال ، مزج متعدد النطاقات ، يُستخدم في خياطة الصور البانورامية ، لكنها لا تعمل بشكل جيد مع النص - فقط تعويض التدفق البصري يمكنه إزالة الظلال تمامًا على النص.



الآن نقوم بلصق الصورة الكاملة:







النسخة النهائية:







يمكن أن تكون التحسينات الإضافية هي التعويض عن تأثير الظل (الجانب الأيمن من الصورة) ، أو حتى المزيد من المعالجة اللاحقة للون والتباين. يمكنك أيضًا أن ترى أن الهندسة العالمية قد عانت قليلاً - فالخطوط الموجودة على اليمين تسللت قليلاً. من الناحية النظرية ، يمكن أيضًا تصحيح هذه المشكلة عن طريق إضافة تصحيح شامل للقياس ، ولكن هذه أيضًا ليست مهمة تافهة تمامًا.



لقد درسنا كيفية عمل اللصق ، يتوفر حل جاهز هنا في شكل واجهة برمجة تطبيقات REST ، أوصي أيضًا بالنظر في الروابط التالية:






All Articles