Objekterkennung mit OpenCV und Swift
Veröffentlicht: 2022-03-11Swift ist jetzt schon eine Weile bei uns und hat uns durch seine Iterationen alle Funktionen einer modernen objektorientierten Programmiersprache gebracht. Dazu gehören Optionen, Generika, Tupel, Strukturen, die Methoden, Erweiterungen und Protokolle unterstützen, und vieles mehr. Wenn Ihre Anwendung jedoch auf eine Bibliothek angewiesen ist, die mit C++ geschrieben wurde, können Sie sich nicht mehr auf Swift verlassen. Glücklicherweise ist Objective-C++ hier, um uns zu helfen.
Seit seiner Einführung verfügt Swift über eine hervorragende Interoperabilität mit Objective-C, und wir werden Objective-C verwenden, um Swift mit C++ zu verbinden. Objective-C++ ist nichts anderes als Objective-C mit der Fähigkeit, mit C++-Code zu verknüpfen, und damit werden wir in diesem Blogbeitrag eine einfache App erstellen, die das Toptal-Logo im Bild mit OpenCV erkennt. Wenn wir dieses Logo erkennen, öffnen wir die Toptal-Homepage.
Wie auf der OpenCV-Webseite angegeben:
"OpenCV wurde für Recheneffizienz und mit einem starken Fokus auf Echtzeitanwendungen entwickelt. Die in optimiertem C/C++ geschriebene Bibliothek kann die Vorteile der Multi-Core-Verarbeitung nutzen."
Dies ist eine großartige Lösung, wenn Sie eine schnell zu entwickelnde und zuverlässige Computer Vision wünschen.
Erstellen des OpenCV Objective-C++ Wrappers
In diesem Tutorial entwerfen wir die Anwendung, die mit einem Toptal-Logo in einem Bild übereinstimmt, und öffnen die Toptal-Webseite. Erstellen Sie zunächst ein neues Xcode-Projekt und richten Sie CocoaPods mit pod init
ein. Fügen Sie OpenCV zu Podfile pod 'OpenCV
hinzu und führen Sie pod install
in Terminal aus. Stellen Sie sicher, dass Sie use_frameworks
! Anweisung in Podfile.
Wenn wir jetzt OpenCV im Xcode-Projekt haben, müssen wir es mit Swift verbinden. Hier ist ein kurzer Überblick über die erforderlichen Schritte:
Schritt 1: Erstellen Sie eine neue Objective-C-Klasse OpenCVWrapper
. Wenn Xcode Sie fragt: „ Möchten Sie einen Objective-C-Bridging-Header konfigurieren? “ wählen Sie „ Bridging Header erstellen “. Der Bridging-Header ist der Ort, an dem Sie Objective-C-Klassen importieren, und dann sind sie in Swift sichtbar.
Schritt 2: Um C++ in Objective-C verwenden zu können, müssen wir die Dateierweiterung von OpenCVWrapper.m
in OpenCVWrapper.mm
. Sie können dies tun, indem Sie die Datei einfach im Projektnavigator von Xcode umbenennen. Das Hinzufügen von .mm
als Erweiterung ändert den Dateityp von Objective-C in Objective-C++.
Schritt 3: Importieren Sie OpenCV in OpenCVWrapper.mm
mit dem folgenden Import. Es ist wichtig, den angegebenen Import oben #import "OpenCVWrapper.h"
zu schreiben, da wir auf diese Weise einen bekannten BOOL-Konflikt vermeiden. OpenCV enthält eine Aufzählung mit dem Wert NO
, was einen Konflikt mit dem Objective-C BOOL NO
-Wert verursacht. Wenn Sie keine Klassen benötigen, die eine solche Aufzählung verwenden, ist dies der einfachste Weg. Andernfalls müssen Sie BOOL vor dem Importieren von OpenCV aufheben.
#ifdef __cplusplus #import <opencv2/opencv.hpp> #import <opencv2/imgcodecs/ios.h> #import <opencv2/videoio/cap_ios.h> #endif
Schritt 4: Fügen Sie #import "OpenCVWrapper.h"
zu Ihrem Bridging-Header hinzu.
Öffnen OpenCVWrapper.mm
und erstellen Sie eine private Schnittstelle, in der wir private Eigenschaften deklarieren:
@interface OpenCVWrapper() <CvVideoCameraDelegate> @property (strong, nonatomic) CvVideoCamera *videoCamera; @property (assign, nonatomic) cv::Mat logoSample; @end
Um CvVideoCamera
zu erstellen, müssen wir UIImageView
daran übergeben, und wir tun dies über unseren Designator-Initialisierer.
- (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; }
Darin konfigurieren wir CvVideoCamera
, die Videos innerhalb der angegebenen parentView
und uns durch den Delegaten ein cv::Mat
-Bild zur Analyse sendet.

Die Methode processImage processImage:
stammt aus dem CvVideoCameraDelegate
Protokoll, und darin führen wir einen Vorlagenabgleich durch.
- (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]; } }
Zuerst konvertieren wir das angegebene Bild in ein Graustufenbild, da wir innerhalb der Init-Methode unser Toptal-Logo-Vorlagen-Matching-Bild in Graustufen konvertiert haben. Der nächste Schritt besteht darin, nach Übereinstimmungen mit einem bestimmten Schwellenwert zu suchen, der uns bei Skalierung und Winkeln hilft. Wir müssen nach Winkeln suchen, da Sie ein Foto in verschiedenen Winkeln aufnehmen können, in denen wir das Logo noch erkennen möchten. Nach Erreichen des angegebenen Schwellenwerts rufen wir den Delegaten auf und öffnen die Webseite von Toptal.
Vergessen Sie nicht, NSCameraUsageDescription
zu Ihrer Info.plist hinzuzufügen, andernfalls stürzt Ihre Anwendung direkt nach dem Aufruf [self.videoCamera start];
.
Jetzt Endlich Swift
Bisher haben wir uns auf Objective-C++ konzentriert, weil die gesamte Logik darin ausgeführt wird. Unser Swift-Code wird ziemlich einfach sein:
- Erstellen
UIImageView
in ViewController.swiftViewController.swift
, woCvVideoCamera
Inhalte rendert. - Erstellen Sie eine Instanz von
OpenCVWrapper
und übergeben Sie ihr dieUIImageView
Instanz. - Implementieren Sie das
OpenCVWrapperDelegate
-Protokoll, um die Webseite von Toptal zu öffnen, wenn wir das Logo erkennen.
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 in Aktion
In diesem Artikel haben wir gezeigt, wie Sie C++-Code mit Swift integrieren und Wrapper-Klassen erstellen können, die dazu dienen, C++-Code mit Swift zu überbrücken. Wenn wir nun das Toptal-Logo durch die Kamera erkennen, öffnen wir die Homepage von Toptal.
Für zukünftige Updates möchten Sie vielleicht den CV-Vorlagenabgleich in einem Hintergrund-Thread ausführen. Auf diese Weise blockieren Sie den Hauptthread nicht und die Benutzeroberfläche bleibt reaktionsfähig. Da dies ein einfaches Beispiel für OpenCV ist, ist der Vorlagenabgleich möglicherweise nicht besonders erfolgreich, aber der Zweck dieses Artikels war es, Ihnen zu zeigen, wie Sie damit beginnen können.
Wenn Sie immer noch daran interessiert sind, OpenCV und seine komplexeren Verwendungen in iOS zu lernen, empfehle ich Real-time Object Detection Using MSER in iOS , das Sie durch die Bilderkennung mit der Rückkamera des iPhones führt.