OpenCV-Tutorial: Objekterkennung in Echtzeit mit MSER in iOS

Veröffentlicht: 2022-03-11

In den letzten Jahren hat sich die durchschnittliche Handyleistung deutlich erhöht. Sei es wegen der reinen CPU-Leistung oder der RAM-Kapazität, es ist jetzt einfacher, rechenintensive Aufgaben auf mobiler Hardware zu erledigen. Obwohl diese mobilen Technologien in die richtige Richtung gehen, gibt es auf mobilen Plattformen noch viel zu tun, insbesondere mit dem Aufkommen von Augmented Reality, Virtual Reality und künstlicher Intelligenz.

Eine große Herausforderung in der Computervision besteht darin, interessante Objekte in Bildern zu erkennen. Das menschliche Auge und das menschliche Gehirn leisten hervorragende Arbeit, und dies in Maschinen nachzubilden, ist immer noch ein Traum. In den letzten Jahrzehnten wurden Ansätze entwickelt, um dies in Maschinen nachzuahmen, und es wird immer besser.

In diesem Lernprogramm untersuchen wir einen Algorithmus, der zum Erkennen von Blobs in Bildern verwendet wird. Wir werden den Algorithmus aus der Open-Source-Bibliothek OpenCV auch verwenden, um einen Prototyp einer iPhone-Anwendung zu implementieren, die die Rückkamera verwendet, um Bilder zu erfassen und Objekte darin zu erkennen.

OpenCV-Tutorial

OpenCV ist eine Open-Source-Bibliothek, die Implementierungen wichtiger Algorithmen für maschinelles Sehen und maschinelles Lernen bereitstellt. Wenn Sie eine Anwendung zum Erkennen von Gesichtern, Spielkarten auf einem Pokertisch oder sogar eine einfache Anwendung zum Hinzufügen von Effekten zu einem beliebigen Bild implementieren möchten, ist OpenCV eine gute Wahl.

OpenCV ist in C/C++ geschrieben und hat Wrapper-Bibliotheken für alle wichtigen Plattformen. Dies macht es besonders einfach, es innerhalb der iOS-Umgebung zu verwenden. Um es in einer Objective-C iOS-Anwendung zu verwenden, laden Sie das OpenCV iOS Framework von der offiziellen Website herunter. Bitte stellen Sie sicher, dass Sie Version 2.4.11 von OpenCV für iOS verwenden (von der in diesem Artikel ausgegangen wird, dass Sie sie verwenden), da die neueste Version, 3.0, einige kompatibilitätsbrechende Änderungen in der Organisation der Header-Dateien enthält. Detaillierte Informationen zur Installation sind auf der Website dokumentiert.

MSER

MSER, kurz für Maximally Stable Extremal Regions, ist eine der vielen verfügbaren Methoden zur Erkennung von Blobs in Bildern. Mit einfachen Worten, der Algorithmus identifiziert zusammenhängende Sätze von Pixeln, deren Pixelintensitäten an der äußeren Grenze höher sind (um einen gegebenen Schwellenwert) als die Pixelintensitäten an der inneren Grenze. Solche Regionen werden als maximal stabil bezeichnet, wenn sie sich über eine variierende Menge an Intensitäten nicht stark verändern.

Obwohl es eine Reihe anderer Blob-Erkennungsalgorithmen gibt, wurde MSER hier gewählt, weil es eine ziemlich geringe Laufzeitkomplexität von O(n log(log(n))) hat, wobei n die Gesamtzahl der Pixel auf dem Bild ist. Der Algorithmus ist auch robust gegenüber Unschärfe und Skalierung, was von Vorteil ist, wenn es darum geht, Bilder zu verarbeiten, die von Echtzeitquellen wie der Kamera eines Mobiltelefons erfasst wurden.

Für dieses Tutorial entwerfen wir die Anwendung, um das Logo von Toptal zu erkennen. Das Symbol hat scharfe Ecken, und das könnte dazu führen, darüber nachzudenken, wie effektiv Eckenerkennungsalgorithmen bei der Erkennung des Toptal-Logos sein können. Schließlich ist ein solcher Algorithmus sowohl einfach zu verwenden als auch zu verstehen. Obwohl eckenbasierte Methoden eine hohe Erfolgsrate haben können, wenn es darum geht, Objekte zu erkennen, die deutlich vom Hintergrund getrennt sind (z. B. schwarze Objekte auf weißem Hintergrund), wäre es schwierig, eine Echtzeiterkennung des Toptal-Logos in der realen Welt zu erreichen Bilder, bei denen der Algorithmus ständig Hunderte von Ecken erkennen würde.

Strategie

maschinelles Lernen und opencv

Für jedes Bild, das die Anwendung über die Kamera erfasst, wird es zuerst in Graustufen konvertiert. Graustufenbilder haben nur einen Farbkanal, aber das Logo ist trotzdem sichtbar. Dies erleichtert dem Algorithmus den Umgang mit dem Bild und reduziert die Datenmenge, die der Algorithmus verarbeiten muss, erheblich, ohne dass ein zusätzlicher Gewinn erzielt wird.

Als nächstes werden wir die Implementierung des Algorithmus von OpenCV verwenden, um alle MSERs zu extrahieren. Als nächstes wird jede MSER normalisiert, indem ihr kleinstes Begrenzungsrechteck in ein Quadrat umgewandelt wird. Dieser Schritt ist wichtig, da das Logo aus verschiedenen Winkeln und Entfernungen erfasst werden kann und dies die Toleranz gegenüber perspektivischer Verzerrung erhöht.

Darüber hinaus werden für jede MSER eine Reihe von Eigenschaften berechnet:

  • Anzahl der Löcher
  • Verhältnis der Fläche von MSER zur Fläche seiner konvexen Hülle
  • Verhältnis der Fläche von MSER zur Fläche seines Rechtecks ​​mit minimaler Fläche
  • Verhältnis der Länge des MSER-Skeletts zur Fläche des MSER
  • Verhältnis der Fläche von MSER zur Fläche seiner größten Kontur

ios-anwendungen und maschinelles lernen

Um das Toptal-Logo in einem Bild zu erkennen, werden Eigenschaften aller MSERs mit bereits gelernten Toptal-Logo-Eigenschaften verglichen. Für die Zwecke dieses Lernprogramms wurden die maximal zulässigen Unterschiede für jede Eigenschaft empirisch ausgewählt.

Als Ergebnis wird schließlich die ähnlichste Region gewählt.

iOS-Anwendung

Die Verwendung von OpenCV von iOS aus ist einfach. Wenn Sie es noch nicht getan haben, finden Sie hier einen kurzen Überblick über die Schritte zum Einrichten von Xcode zum Erstellen einer iOS-Anwendung und zum Verwenden von OpenCV darin:

  1. Erstellen Sie einen neuen Projektnamen „SuperCool Logo Detector“. Lassen Sie als Sprache Objective-C ausgewählt.

  2. Fügen Sie eine neue Präfix-Header-Datei (.pch) hinzu und nennen Sie sie PrefixHeader.pch

  3. Gehen Sie in das Projekt „SuperCool Logo Detector“ Build Target und suchen Sie auf der Registerkarte „Build Settings“ die Einstellung „Prefix Headers“. Sie finden es im Abschnitt LLVM-Sprache oder verwenden Sie die Suchfunktion.

  4. Fügen Sie „PrefixHeader.pch“ zur Einstellung „Präfix-Header“ hinzu

  5. Wenn Sie OpenCV für iOS 2.4.11 noch nicht installiert haben, tun Sie dies jetzt.

  6. Ziehen Sie das heruntergeladene Framework per Drag-and-Drop in das Projekt. Überprüfen Sie „Verknüpfte Frameworks und Bibliotheken“ in Ihren Zieleinstellungen. (Es sollte automatisch hinzugefügt werden, aber besser, um auf Nummer sicher zu gehen.)

  7. Verknüpfen Sie außerdem die folgenden Frameworks:

    • AVStiftung
    • AssetsLibrary
    • CoreMedia
  8. Öffnen Sie „PrefixHeader.pch“ und fügen Sie die folgenden 3 Zeilen hinzu:

     #ifdef __cplusplus #include <opencv2/opencv.hpp> #endif”
  9. Ändern Sie die Erweiterungen automatisch erstellter Codedateien von „ .m“ in „ .mm“. OpenCV ist in C++ geschrieben und mit *.mm sagen Sie, dass Sie Objective-C++ verwenden werden.

  10. Importieren Sie „opencv2/highgui/cap_ios.h“ in ViewController.h und ändern Sie ViewController so, dass es mit dem Protokoll CvVideoCameraDelegate übereinstimmt:

     #import <opencv2/highgui/cap_ios.h>
  11. Öffnen Sie Main.storyboard und platzieren Sie eine UIImageView auf dem anfänglichen Ansichtscontroller.

  12. Erstellen Sie ein Outlet zu ViewController.mm mit dem Namen „imageView“.

  13. Erstellen Sie eine Variable „CvVideoCamera *camera;“ in ViewController.h oder ViewController.mm, und initialisieren Sie es mit einem Verweis auf die Rückfahrkamera:

     camera = [[CvVideoCamera alloc] initWithParentView: _imageView]; camera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack; camera.defaultAVCaptureSessionPreset = AVCaptureSessionPreset640x480; camera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait; camera.defaultFPS = 30; camera.grayscaleMode = NO; camera.delegate = self;
  14. Wenn Sie das Projekt jetzt erstellen, wird Xcode Sie warnen, dass Sie die „processImage“-Methode von CvVideoCameraDelegate nicht implementiert haben. Der Einfachheit halber nehmen wir vorerst nur die Bilder von der Kamera auf und überlagern sie mit einem einfachen Text:

    • Fügen Sie eine einzelne Zeile zu „viewDidAppear“ hinzu:
     [camera start];
    • Wenn Sie die Anwendung jetzt ausführen, werden Sie um Erlaubnis gebeten, auf die Kamera zuzugreifen. Und dann sollten Sie ein Video von der Kamera sehen.

    • Fügen Sie in der Methode „processImage“ die folgenden zwei Zeilen hinzu:

     const char* str = [@"Toptal" cStringUsingEncoding: NSUTF8StringEncoding]; cv::putText(image, str, cv::Point(100, 100), CV_FONT_HERSHEY_PLAIN, 2.0, cv::Scalar(0, 0, 255));

Das ist so ziemlich alles. Jetzt haben Sie eine sehr einfache Anwendung, die den Text „Toptal“ auf Bilder von der Kamera zeichnet. Wir können jetzt unsere Anwendung zur Erkennung von Ziellogos auf dieser einfacheren aufbauen. Der Kürze halber besprechen wir in diesem Artikel nur eine Handvoll Codesegmente, die für das allgemeine Verständnis der Funktionsweise der Anwendung von entscheidender Bedeutung sind. Der Code auf GitHub enthält eine ganze Reihe von Kommentaren, um zu erklären, was jedes Segment tut.

Da die Anwendung nur einen Zweck hat, nämlich das Logo von Toptal zu erkennen, werden MSER-Funktionen direkt nach dem Start aus dem angegebenen Vorlagenbild extrahiert und die Werte im Speicher gespeichert:

 cv::Mat logo = [ImageUtils cvMatFromUIImage: templateImage]; //get gray image cv::Mat gray; cvtColor(logo, gray, CV_BGRA2GRAY); //mser with maximum area is std::vector<cv::Point> maxMser = [ImageUtils maxMser: &gray]; //get 4 vertices of the maxMSER minrect cv::RotatedRect rect = cv::minAreaRect(maxMser); cv::Point2f points[4]; rect.points(points); //normalize image cv::Mat M = [GeometryUtil getPerspectiveMatrix: points toSize: rect.size]; cv::Mat normalizedImage = [GeometryUtil normalizeImage: &gray withTranformationMatrix: &M withSize: rect.size.width]; //get maxMser from normalized image std::vector<cv::Point> normalizedMser = [ImageUtils maxMser: &normalizedImage]; //remember the template self.logoTemplate = [[MSERManager sharedInstance] extractFeature: &normalizedMser]; //store the feature [self storeTemplate];

Die Anwendung hat nur einen Bildschirm mit einer Start/Stopp-Taste, und alle notwendigen Informationen, wie FPS und Anzahl der erkannten MSERs, werden automatisch auf das Bild gezeichnet. Solange die Anwendung nicht angehalten wird, wird für jeden Bildrahmen in der Kamera die folgende Methode processImage aufgerufen:

 -(void)processImage:(cv::Mat &)image { cv::Mat gray; cvtColor(image, gray, CV_BGRA2GRAY); std::vector<std::vector<cv::Point>> msers; [[MSERManager sharedInstance] detectRegions: gray intoVector: msers]; if (msers.size() == 0) { return; }; std::vector<cv::Point> *bestMser = nil; double bestPoint = 10.0; std::for_each(msers.begin(), msers.end(), [&] (std::vector<cv::Point> &mser) { MSERFeature *feature = [[MSERManager sharedInstance] extractFeature: &mser]; if(feature != nil) { if([[MLManager sharedInstance] isToptalLogo: feature] ) { double tmp = [[MLManager sharedInstance] distance: feature ]; if ( bestPoint > tmp ) { bestPoint = tmp; bestMser = &mser; } } } }); if (bestMser) { NSLog(@"minDist: %f", bestPoint); cv::Rect bound = cv::boundingRect(*bestMser); cv::rectangle(image, bound, GREEN, 3); } else { cv::rectangle(image, cv::Rect(0, 0, W, H), RED, 3); } // Omitted debug code [FPS draw: image]; }

Diese Methode erstellt im Wesentlichen eine Graustufenkopie des Originalbildes. Es identifiziert alle MSERs und extrahiert ihre relevanten Merkmale, bewertet jede MSER auf Ähnlichkeit mit der Vorlage und wählt die beste aus. Schließlich zieht es eine grüne Grenze um die beste MSER und überlagert das Bild mit Metainformationen.

Nachfolgend sind die Definitionen einiger wichtiger Klassen und ihrer Methoden in dieser Anwendung aufgeführt. Ihre Zwecke werden in Kommentaren beschrieben.

GeometryUtil.h

 /* This static class provides perspective transformation function */ @interface GeometryUtil : NSObject /* Return perspective transformation matrix for given points to square with origin [0,0] and with size (size.width, size.width) */ + (cv::Mat) getPerspectiveMatrix: (cv::Point2f[]) points toSize: (cv::Size2f) size; /* Returns new perspecivly transformed image with given size */ + (cv::Mat) normalizeImage: (cv::Mat *) image withTranformationMatrix: (cv::Mat *) M withSize: (float) size; @end

MSERManager.h

 /* Singelton class providing function related to msers */ @interface MSERManager : NSObject + (MSERManager *) sharedInstance; /* Extracts all msers into provided vector */ - (void) detectRegions: (cv::Mat &) gray intoVector: (std::vector<std::vector<cv::Point>> &) vector; /* Extracts feature from the mser. For some MSERs feature can be NULL !!! */ - (MSERFeature *) extractFeature: (std::vector<cv::Point> *) mser; @end

MLManager.h

 /* This singleton class wraps object recognition function */ @interface MLManager : NSObject + (MLManager *) sharedInstance; /* Stores feature from the biggest MSER in the templateImage */ - (void) learn: (UIImage *) templateImage; /* Sum of the differences between logo feature and given feature */ - (double) distance: (MSERFeature *) feature; /* Returns true if the given feature is similar to the one learned from the template */ - (BOOL) isToptalLogo: (MSERFeature *) feature; @end

Nachdem alles miteinander verkabelt ist, sollten Sie mit dieser Anwendung in der Lage sein, die Kamera Ihres iOS-Geräts zu verwenden, um das Logo von Toptal aus verschiedenen Winkeln und Ausrichtungen zu erkennen.

Vertikales Erkennen eines Bildes (das Toptal-Logo).

Erfassen eines Bildes (das Toptal-Logo) diagonal auf einem Hemd.

Augmented-Reality-Apps beginnen damit, Bilder zu verstehen, und so können Sie es tun.
Twittern

Fazit

In diesem Artikel haben wir gezeigt, wie einfach es ist, mit OpenCV einfache Objekte aus einem Bild zu erkennen. Der gesamte Code ist auf GitHub verfügbar. Fühlen Sie sich frei, Push-Anfragen zu forken und zu senden, da Beiträge willkommen sind.

Wie bei allen maschinellen Lernproblemen kann die Erfolgsrate der Logoerkennung in dieser Anwendung durch die Verwendung eines anderen Satzes von Merkmalen und einer anderen Methode zur Objektklassifizierung erhöht werden. Ich hoffe jedoch, dass dieser Artikel Ihnen beim Einstieg in die Objekterkennung mit MSER und Anwendungen von Computer-Vision-Techniken im Allgemeinen helfen wird.

Weiterführende Lektüre

  • J. Matas, O. Chum, M. Urban und T. Pajdla. „Robustes Stereo mit breiter Grundlinie aus maximal stabilen Extremregionen.“
  • Neumann, Lukas; Matas, Jiri (2011). „Eine Methode zur Textlokalisierung und -erkennung in realen Bildern“
Siehe auch: Ein Einführungs-Tutorial zur Roboterprogrammierung