OpenCV 3 mit C++ – Teil 1 – Einführung

In dieser neuen Serie wollen wir uns einem spannenden, zukunftsträchtigen, aber auch sehr anspruchsvollen Thema widmen: Dem maschinellen Sehen oder auf englisch: Computer Vision.

Einleitung

Dabei geht es darum, dem Computer so zu programmieren, dass er Bilder (in den meisten Fällen von einer Kamera) auf bestimmte Eigenschaften hin untersuchen kann und abhängig von den Ergebnissen agieren kann. Das momentan sicherlich berühmteste Beispiel ist das autonome Fahren von Automobilen, aber auch Roboter und viele Systeme in der Industrie setzen auf das maschinelle Sehen auf. So soll das Programm beispielsweise Gesichter und Straßenschilder erkennen, fehlerhafte Produkte aussortieren oder das Glasdach eines Autos passend aufkleben.

Schon seit langer Zeit ist dabei eine Programmbibliothek sehr populär und bewährt: OpenCV. Das ursprünglich von Intel initiierte Projekt enthält mittlerweile Beiträge vieler großer Firmen und Universiäten sowie Privatpersonen und wird mittlerweile von der WillowGarage verwaltet, die unter anderem auch das populäre Robot Operating System (ROS) entwickelt. Der Source Code von OpenCV steht unter der BSD License und ist auf GitHub frei einsehbar. Es darf somit auch für kommerzielle Projekte verwendet werden (keine Garantie für diese Angaben, bitte diese Punkte vor Programmveröffentlichung nochmals selber prüfen). Einen populären Auftritt hatte OpenCV bei der DARPA-Challenge im Jahre 2005. Auch Tesla verwendet den Stellenausschreibungen nach zu urteilen OpenCV für den „Autopilot“.

OpenCV ist in C/C++ geschrieben (früher hauptsächlich C, in den letzten Jahren ging es immer mehr in Richtung C++ und Objektorientierung), es existieren aber auch zahlreiche Wrapper für andere Sprachen. Der populärste ist sicherlich der für Python. Der Code ist im höchsten Maße auf Effizienz getrimmt, da diese bei so vielen und aufwendigen Rechnungen auch bei der heutigen Leistungsfähigkeit von Computer sehr wichtig ist. Zudem gibt es die Möglichkeit, beim Kompilieren Bibliotheken wie CUDA (Nvidia), Integrated Performance Primitives (IPP, Intel) oder OpenCL einzubinden, um das letzte bisschen Performance aus dem Computer zu kitzeln. Um diese Bibliotheken zu benutzen, ist allerdings teilweise zusätzliche Arbeit bzw. veränderter Code notwenidg. Außerdem ist OpenCV auf allen wichtigen Plattformen (Windows, Linux, Unix, Mac OS, Android, iOS, Windows Store) lauffähig.

Installation

Da die Installation bei OpenCV wahrscheinlich das Schwierigste ist (zumindest für Einsteiger, die keine Ahnung von cmake o. Ä. haben), findet ihr auf der Seite für OpenCV eine Übersicht über Blogeinträge, welche die Installation mittels verschiedener Methoden und auf verschiedenen Plattformen behandeln (die Anleitungen kommen nach und nach dazu). Sollte eure noch fehlen, sagt mir Bescheid.

Die ersten beiden Testprogramme

Nachdem die Installation nun (hoffentlich) erfolgreich vonstatten gegangen ist, möchten wir natürlich ein erstes kleines Testprogramm schreiben. Dieses soll nichts anderes machen, als ein Bild aus einer Datei zu laden und dieses so lange anzuzeigen, bis der Benutzer eine Taste drückt.

Ich lade das Projekt auf Github hoch, damit ihr Zugriff auf den gesamten Code habt.

Erstes Programm

Zunächst erstellen wir ein Projekt in Visual Studio. Wählt unter „Visual C++“ „Win32-Konsolenanwendung“ aus und gebt einen Namen für die Projektmappe ein.

Neues Projekt erstellen
Neues Projekt erstellen

Danach taucht ein Dialog zum Erstellen des Projekts auf. Klickt zunächst auf „Weiter“.

Konsolenapplikation Schritt 1
Konsolenapplikation Schritt 1

Im nächsten Fenster klickt ihr auf „Leeres Projekt“ und dann auf „Fertig stellen“.

Konsolenapplikation Teil 2
Konsolenapplikation Teil 2

Im nächsten Schritt fügen Sie unter dem Ordner „Quelldateien“ eine Datei „main.cpp“ hinzu.

Datei hinzufügen Teil 1
Datei hinzufügen Teil 1
Datei hinzufügen Teil 2
Datei hinzufügen Teil 2

Die weitere Einrichtung von Visual Studio findet ihr hier im Abschnitt 5.

Zunächst schreiben wir dafür das Standard-Codegerüst für ein C++-Programm.

Danach müssen wir die include-Direktiven für OpenCV einfügen, um die notwendigen Funktionen zu laden. Wir binden zwei .hpp-Dateien ein:

Um auf die Klassen von OpenCV nicht immer mit cv::Klasse zugreifen zu müssen, binden wir den Namespace cv ein.

Bilder werden in der grundlegenden Datenstruktur Mat (für Matrix) gespeichert – dazu im nächsten Teil mehr. Die Funktion imload() lädt ein Bild aus einer Datei und gibt es als Mat zurück. Der Funktion imload() übergibt man den relativen Dateipfad zum Bild. Im Ordner der Projektmappe habe ich dazu einen Ordner „Images“ erstellt und dort ein Bild vom Hubble-Teleskop gespeichert. Somit sieht der Code wie folgt aus:

Bevor wir weitermachen, müssen wir sicherstellen, dass die Matrix nicht leer ist. Wir verlassen die Funktion mit einem Fehlercode, falls die Matrix leer ist.

Wir gehen also aus dem Projektordner in den Projektmappenexplorer, dann ins Verzeichnis „Hubble“ und laden dann die Datei „Hubble.jpg“. Danach erstellen wir ein beschriftetes Fenster mit der Funktion namedWindow(). Ihr übergibt man eine Zeichenkette, die gleichzeitig der Beschriftung wie auch der Identifikation des Fensters dient. Da wir die Zeichenkette also häufiger brauchen und Schreibfehler nicht so toll sind, erstellen wir eine Konstante, die wir dann übergeben.

Nun wollen wir das Bild im Fenster anzeigen lassen. Das geht mit der Funktion imshow(), der der Fenstername sowie das Bild übergeben wird.

Nun müssen wir nur noch verhindern, dass sich das Fenster sofort wieder schließt. Dafür gibt es die Methode waitKey(), die, wenn wir sie ohne Argumente oder mit dem Argument 0 aufrufen, auf das Drücken einer beliebigen Taste wartet und die Taste als char zurückgibt, die wir aber nicht brauchen.

Und hier nochmal der gesamt Programmcode:

Bevor das Programm nun gestartet wird, müssen wir die Entwicklungsumgebung einrichten. Wie das in Visual Studio (2017) gemacht wird, das zeige ich hier in Schritt 5. Danach könnt ihr das Programm starten.

Zweites Programm

Das zweite Programm soll die Kamera, die heutzutage ja in den meisten Laptops verbaut ist, auslesen, uns also wie eine Kamera-App den Videostream zeigen. Dafür essentiell ist die Klasse VideoCapture. Mit

wird auf die erste Kamera zugegriffen. Mit 1, 2, … greift ihr auf die zweite, dritte oder x-te Kamera zu. Wir müssen wieder prüfen, ob der Stream geöffnet ist, ansonsten verlassen wir die Funktion wieder mit einem Fehlercode:

Mit

wird der aktuelle Frame des Streams in eine Matrix geschrieben. Diese Zeile rufen wir in einer while-Schleife auf.

Dieses Programm kann nur mit der Taste ‚q‘ beendet werden. Durch waitKey()-Methode mit dem Parameter 33 wartet die Methode 33 Millisekunden, falls während dieser Zeit ‚q‘ gedrückt, gibt die Methode eben dieses Zeichen zurück. Falls das passiert, springen wir aus der Schleife und beenden somit das Programm. Das Ausführen sollte jetzt ein Fenster mit einem Livestream der Webcam auftauchen.

Ende

Im nächsten Artikel werden wir die grundlegenden Datentypen und Datenspeicherung von OpenCV betrachten.