اكتشاف الكائن باستخدام OpenCV و Swift

نشرت: 2022-03-11

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

منذ تقديمها ، تتمتع Swift بإمكانية تشغيل تفاعلي رائعة مع Objective-C وسنستخدم Objective-C لربط Swift بـ C ++. لا يعد Objective-C ++ أكثر من Objective-C مع القدرة على الارتباط برمز C ++ ، وباستخدام ذلك ، في منشور المدونة هذا ، سننشئ تطبيقًا بسيطًا يتعرف على شعار Toptal داخل الصورة باستخدام OpenCV. عندما نكتشف هذا الشعار ، سنفتح صفحة Toptal الرئيسية.

كما هو مذكور في صفحة الويب OpenCV:

"تم تصميم OpenCV لتحقيق الكفاءة الحسابية مع التركيز القوي على التطبيقات في الوقت الفعلي. مكتوبة بلغة C / C ++ المحسّنة ، يمكن للمكتبة الاستفادة من المعالجة متعددة النواة."

يعد هذا حلاً رائعًا إذا كنت تريد تطوير رؤية كمبيوتر موثوقة بسرعة.

إنشاء غلاف OpenCV Objective-C ++

في هذا البرنامج التعليمي ، سنقوم بتصميم التطبيق الذي يتطابق مع شعار Toptal داخل صورة ويفتح صفحة ويب Toptal. للبدء ، قم بإنشاء مشروع Xcode جديد وقم بإعداد CocoaPods باستخدام pod init . أضف OpenCV إلى Podfile pod 'OpenCV وقم بتشغيل pod install في Terminal. تأكد من use_frameworks ! بيان داخل Podfile.

الآن ، عندما يكون لدينا OpenCV داخل مشروع Xcode ، يتعين علينا توصيله بـ Swift. فيما يلي ملخص سريع للخطوات المتضمنة:

الخطوة 1: قم بإنشاء فئة OpenCVWrapper من فئة Objective-C جديدة. عندما يسألك Xcode " هل ترغب في تكوين رأس توصيل Objective-C؟ "اختر" إنشاء رأس توصيل ". رأس التجسير هو المكان الذي تقوم فيه باستيراد فئات Objective-C ، ومن ثم تكون مرئية داخل Swift.

الخطوة 2: من أجل استخدام C ++ داخل Objective-C ، يتعين علينا تغيير امتداد الملف من OpenCVWrapper.m إلى OpenCVWrapper.mm . يمكنك القيام بذلك ببساطة عن طريق إعادة تسمية الملف داخل متصفح مشروع Xcode. ستؤدي إضافة .mm إلى تغيير نوع الملف من Objective-C إلى Objective-C ++.

الخطوة 3: استيراد OpenCV إلى OpenCVWrapper.mm باستخدام الاستيراد التالي. من المهم كتابة الاستيراد المحدد أعلاه #import "OpenCVWrapper.h" لأننا بهذه الطريقة نتجنب تعارض BOOL المعروف. يحتوي OpenCV على تعداد يحتوي على القيمة NO مما يتسبب في حدوث تعارض مع قيمة Objective-C BOOL NO . إذا لم تكن بحاجة إلى فئات تستخدم هذا التعداد ، فهذه هي أبسط طريقة. خلاف ذلك ، يجب عليك إلغاء تعريف BOOL قبل استيراد OpenCV.

 #ifdef __cplusplus #import <opencv2/opencv.hpp> #import <opencv2/imgcodecs/ios.h> #import <opencv2/videoio/cap_ios.h> #endif

الخطوة 4: أضف #import "OpenCVWrapper.h" إلى رأس التوصيل الخاص بك.

افتح OpenCVWrapper.mm وأنشئ واجهة خاصة سنعلن فيها عن الخصائص الخاصة:

 @interface OpenCVWrapper() <CvVideoCameraDelegate> @property (strong, nonatomic) CvVideoCamera *videoCamera; @property (assign, nonatomic) cv::Mat logoSample; @end

من أجل إنشاء CvVideoCamera ، يتعين علينا تمرير UIImageView إليها ، وسنفعل ذلك من خلال مُهيئ التعيين الخاص بنا.

 - (instancetype)initWithParentView:(UIImageView *)parentView delegate:(id<OpenCVWrapperDelegate>)delegate { if (self = [super init]) { self.delegate = delegate; parentView.contentMode = UIViewContentModeScaleAspectFill; self.videoCamera = [[CvVideoCamera alloc] initWithParentView:parentView]; self.videoCamera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack; self.videoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPresetHigh; self.videoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait; self.videoCamera.defaultFPS = 30; self.videoCamera.grayscaleMode = [NSNumber numberWithInt:0].boolValue; self.videoCamera.delegate = self; // Convert UIImage to Mat and store greyscale version UIImage *templateImage = [UIImage imageNamed:@"toptal"]; cv::Mat templateMat; UIImageToMat(templateImage, templateMat); cv::Mat grayscaleMat; cv::cvtColor(templateMat, grayscaleMat, CV_RGB2GRAY); self.logoSample = grayscaleMat; [self.videoCamera start]; } return self; }

بداخله ، نقوم بتكوين CvVideoCamera الذي يعرض الفيديو داخل العرض parentView المعطى ومن خلال المندوب يرسل لنا صورة cv::Mat للتحليل.

processImage: الطريقة من بروتوكول CvVideoCameraDelegate ، وداخلها ، سنقوم بمطابقة القالب.

 - (void)processImage:(cv::Mat&)image { cv::Mat gimg; // Convert incoming img to greyscale to match template cv::cvtColor(image, gimg, CV_BGR2GRAY); // Get matching cv::Mat res(image.rows-self.logoSample.rows+1, self.logoSample.cols-self.logoSample.cols+1, CV_32FC1); cv::matchTemplate(gimg, self.logoSample, res, CV_TM_CCOEFF_NORMED); cv::threshold(res, res, 0.5, 1., CV_THRESH_TOZERO); double minval, maxval, threshold = 0.9; cv::Point minloc, maxloc; cv::minMaxLoc(res, &minval, &maxval, &minloc, &maxloc); // Call delegate if match is good enough if (maxval >= threshold) { // Draw a rectangle for confirmation cv::rectangle(image, maxloc, cv::Point(maxloc.x + self.logoSample.cols, maxloc.y + self.logoSample.rows), CV_RGB(0,255,0), 2); cv::floodFill(res, maxloc, cv::Scalar(0), 0, cv::Scalar(.1), cv::Scalar(1.)); [self.delegate openCVWrapperDidMatchImage:self]; } }

أولاً ، نقوم بتحويل الصورة المعطاة إلى صورة ذات تدرج رمادي لأننا داخل طريقة init قمنا بتحويل صورة مطابقة قالب شعار Toptal إلى تدرج رمادي. الخطوة التالية هي التحقق من التطابقات بحد معين سيساعدنا في القياس والزوايا. يتعين علينا التحقق من الزوايا لأنه يمكنك التقاط صورة من زوايا مختلفة لا نزال نريد اكتشاف الشعار فيها. بعد الوصول إلى الحد المعين ، سنقوم باستدعاء المندوب وفتح صفحة الويب الخاصة بـ Toptal.

لا تنس إضافة NSCameraUsageDescription إلى Info.plist الخاص بك وإلا ، فسوف يتعطل تطبيقك مباشرة بعد استدعاء [self.videoCamera start]; .

الآن أخيرا سويفت

حتى الآن كنا نركز على Objective-C ++ لأن كل المنطق يتم بداخله. سيكون كود Swift الخاص بنا بسيطًا إلى حد ما:

  1. داخل ViewController.swift ، قم بإنشاء UIImageView حيث CvVideoCamera المحتوى.
  2. قم بإنشاء مثيل لـ OpenCVWrapper وقم بتمرير مثيل UIImageView إليه.
  3. قم بتنفيذ بروتوكول OpenCVWrapperDelegate لفتح صفحة الويب الخاصة بـ Toptal عندما نكتشف الشعار.
 class ViewController: UIViewController { var wrapper: OpenCVWrapper! @IBOutlet var imageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. wrapper = OpenCVWrapper.init(parentView: imageView, delegate: self) } } extension ViewController: OpenCVWrapperDelegate { //MARK: - OpenCVWrapperDelegate func openCVWrapperDidMatchImage(_ wrapper: OpenCVWrapper) { UIApplication.shared.open(URL.init(string: "https://toptal.com")!, options: [:], completionHandler: nil) } }

OpenCV Swift قيد التشغيل

في هذه المقالة ، أوضحنا كيف يمكنك دمج كود C ++ مع Swift وإنشاء فئات مجمعة موجودة هنا لتوصيل كود C ++ مع Swift. الآن ، عندما نكتشف شعار Toptal من خلال الكاميرا ، نفتح الصفحة الرئيسية لـ Toptal.

الكشف عن شعار Toptal باستخدام OpenCV Swift

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

إذا كنت لا تزال مهتمًا بتعلم OpenCV واستخداماته الأكثر تعقيدًا في iOS ، فإنني أوصي باستخدام ميزة اكتشاف الكائنات في الوقت الفعلي باستخدام MSER في iOS ، والتي ترشدك خلال اكتشاف الصور باستخدام الكاميرا الخلفية لجهاز iPhone.