Image Stitching mit OpenCV und Python

In diesem Tutorial werden Sie lernen, wie man mit Python, OpenCV und den Funktionen cv2.createStitcher und cv2.Stitcher_create Bilder zusammenfügt. Mit dem heutigen Code werden Sie in der Lage sein, mehrere Bilder zusammenzufügen und ein Panorama aus zusammengefügten Bildern zu erstellen.

Vor knapp zwei Jahren habe ich zwei Anleitungen zum Zusammenfügen von Bildern und zur Erstellung von Panoramen veröffentlicht:

  1. Grundlagen des Image Stitching
  2. Echtzeit-Panorama und Image Stitching

Beide dieser Anleitungen behandelten die Grundlagen des typischen Image Stitching-Algorithmus, der im Grunde genommen vier Schlüsselschritte erfordert:

  1. Erkennen von Keypoints (DoG, Harris, etc.) und die Extraktion lokaler invarianter Deskriptoren (SIFT, SURF, etc.) aus zwei Eingangsbildern
  2. Abgleich der Deskriptoren zwischen den Bildern
  3. Verwendung des RANSAC-Algorithmus zur Schätzung einer Homographie-Matrix unter Verwendung unserer abgestimmten Merkmalsvektoren
  4. Anwendung einer Warping-Transformation unter Verwendung der in Schritt 3 erhaltenen Homographie-Matrix

Das größte Problem meiner ursprünglichen Implementierungen ist jedoch, dass sie nicht in der Lage waren, mehr als zwei Eingangsbilder zu verarbeiten.

Im heutigen Tutorial werden wir uns erneut mit dem Zusammenfügen von Bildern mit OpenCV beschäftigen, einschließlich der Frage, wie man mehr als zwei Bilder zu einem Panoramabild zusammenfügt.

Um zu lernen, wie man Bilder mit OpenCV und Python zusammenfügt, lesen Sie einfach weiter!

Image Stitching mit OpenCV und Python

Im ersten Teil des heutigen Tutorials werden wir kurz den Algorithmus von OpenCV zum Zusammenfügen von Bildern besprechen, der über die Funktionen cv2.createStitcher und cv2.Stitcher_create in die OpenCV-Bibliothek selbst integriert ist.

Danach werden wir unsere Projektstruktur überprüfen und ein Python-Skript implementieren, das für das Stitching von Bildern verwendet werden kann.

Wir werden die Ergebnisse dieses ersten Skripts überprüfen, seine Beschränkungen beachten und dann ein zweites Python-Skript implementieren, das für ästhetisch ansprechendere Ergebnisse beim Stitching von Bildern verwendet werden kann.

Abschließend werden wir die Ergebnisse unseres zweiten Skripts überprüfen und erneut alle Beschränkungen oder Nachteile beachten.

OpenCVs Algorithmus zum Zusammenfügen von Bildern

Abbildung 1: Die Pipeline des Stitching-Moduls, implementiert in der Klasse Stitcher (Quelle).

Der Algorithmus, den wir heute verwenden werden, ähnelt der Methode, die Brown und Lowe in ihrer 2007 veröffentlichten Arbeit Automatic Panoramic Image Stitching with Invariant Features vorgeschlagen haben.

Im Gegensatz zu früheren Algorithmen zum Zusammenfügen von Bildern, die empfindlich auf die Reihenfolge der eingegebenen Bilder reagieren, ist die Methode von Brown und Lowe robuster und unempfindlich gegenüber:

  • Anordnung der Bilder
  • Ausrichtung der Bilder
  • Beleuchtungsänderungen
  • Rauschende Bilder, die eigentlich nicht Teil des Panoramas sind

Außerdem ist ihre Bildzusammensetzungsmethode in der Lage, durch den Einsatz von Verstärkungskompensation und Bildüberblendung ästhetisch ansprechendere Ausgangspanoramabilder zu erzeugen.

Eine vollständige, detaillierte Beschreibung des Algorithmus würde den Rahmen dieses Beitrags sprengen. Wenn Sie also mehr erfahren möchten, lesen Sie bitte die Originalveröffentlichung.

Projektstruktur

Sehen wir uns an, wie dieses Projekt mit dem tree-Befehl organisiert ist:

$ tree --dirsfirst.├── images│ └── scottsdale│ ├── IMG_1786-2.jpg│ ├── IMG_1787-2.jpg│ └── IMG_1788-2.jpg├── image_stitching.py├── image_stitching_simple.py└── output.png2 directories, 6 files

Die Eingabebilder kommen in den Ordner images/. Ich habe mich dafür entschieden, einen Unterordner für meine scottsdale/ Bilder zu erstellen, falls ich später weitere Unterordner hinzufügen möchte.

Heute werden wir zwei Python-Skripte durchsehen:

  • image_stitching_simple.py : Unsere einfache Version des Bildstitchings kann in weniger als 50 Zeilen Python-Code fertiggestellt werden!
  • image_stitching.py : Dieses Skript enthält meinen Hack, um einen ROI des zusammengesetzten Bildes für ein ästhetisch ansprechendes Ergebnis zu extrahieren.

Die letzte Datei, output.png , ist der Name des resultierenden zusammengesetzten Bildes. Mit Hilfe von Kommandozeilenargumenten können Sie den Dateinamen und den Pfad des Ausgabebildes leicht ändern.

Die Funktionen cv2.createStitcher und cv2.Stitcher_create

Abbildung 2: Die Konstruktorsignatur zum Erstellen eines Stitcher-Klassenobjekts mit OpenCV.

OpenCV hat bereits eine Methode ähnlich der von Brown und Lowe über die cv2.createStitcher (OpenCV 3.x) und cv2.Stitcher_create (OpenCV 4) implementiert.

Angenommen, Sie haben OpenCV richtig konfiguriert und installiert, dann können Sie die Funktionssignatur von cv2.createStitcher für OpenCV 3.x untersuchen:

createStitcher(...) createStitcher() -> retval

Beachten Sie, dass diese Funktion nur einen einzigen Parameter hat, try_gpu, der verwendet werden kann, um die gesamte Pipeline für das Zusammenfügen von Bildern zu verbessern. Die GPU-Unterstützung von OpenCV ist begrenzt und ich konnte diesen Parameter noch nie zum Funktionieren bringen, daher empfehle ich, ihn immer auf False zu belassen.

Die cv2.Stitcher_create-Funktion für OpenCV 4 hat eine ähnliche Signatur:

Stitcher_create(...) Stitcher_create() -> retval . @brief Creates a Stitcher configured in one of the stitching .modes. . . @param mode Scenario for stitcher operation. This is usually .determined by source of images to stitch and their transformation. .Default parameters will be chosen for operation in given scenario. . @return Stitcher class instance.

Um das eigentliche Bildstitching durchzuführen, müssen wir die .stitch-Methode aufrufen:

OpenCV 3.x:stitch(...) method of cv2.Stitcher instance stitch(images) -> retval, panoOpenCV 4.x:stitch(...) method of cv2.Stitcher instance stitch(images, masks) -> retval, pano . @brief These functions try to stitch the given images. . . @param images Input images. . @param masks Masks for each input image specifying where to .look for keypoints (optional). . @param pano Final pano. . @return Status code.

Diese Methode akzeptiert eine Liste von Eingabebildern images und versucht dann, sie zu einem Panorama zusammenzufügen, wobei das ausgegebene Panoramabild an die aufrufende Funktion zurückgegeben wird.

Die Variable status zeigt an, ob das Zusammenfügen der Bilder erfolgreich war oder nicht und kann eine von vier Variablen sein:

  • OK = 0 : Das Zusammenfügen der Bilder war erfolgreich.
  • ERR_NEED_MORE_IMGS = 1 : Falls Sie diesen Statuscode erhalten, benötigen Sie weitere Eingabebilder, um Ihr Panorama zu erstellen. Typischerweise tritt dieser Fehler auf, wenn in den Eingabebildern nicht genügend Keypoints erkannt wurden.
  • ERR_HOMOGRAPHY_EST_FAIL = 2 : Dieser Fehler tritt auf, wenn die RANSAC-Homographie-Schätzung fehlschlägt. Auch hier benötigen Sie möglicherweise mehr Bilder oder Ihre Bilder haben nicht genügend unterscheidbare, einzigartige Texturen/Objekte, damit die Keypoints genau zugeordnet werden können.
  • ERR_CAMERA_PARAMS_ADJUST_FAIL = 3 : Dieser Fehler ist mir noch nie begegnet, so dass ich nicht viel darüber weiß, aber die Grundaussage ist, dass er damit zusammenhängt, dass die intrinsischen/extrinsischen Eigenschaften der Kamera aus den Eingabebildern nicht richtig geschätzt wurden. Wenn Sie auf diesen Fehler stoßen, müssen Sie möglicherweise die OpenCV-Dokumentation zu Rate ziehen oder sogar in den OpenCV-C++-Code eintauchen.

Nachdem wir nun die Methoden cv2.createStitcher , cv2.Stitcher_create und .stitch besprochen haben, lassen Sie uns zur tatsächlichen Implementierung von Image Stitching mit OpenCV und Python übergehen.

Implementierung von Image Stitching mit Python

Lassen Sie uns beginnen, unseren Image Stitching Algorithmus zu implementieren!

Öffnen Sie die image_stitching_simple.py Datei und fügen Sie den folgenden Code ein:

# import the necessary packagesfrom imutils import pathsimport numpy as npimport argparseimport imutilsimport cv2# construct the argument parser and parse the argumentsap = argparse.ArgumentParser()ap.add_argument("-i", "--images", type=str, required=True,help="path to input directory of images to stitch")ap.add_argument("-o", "--output", type=str, required=True,help="path to the output image")args = vars(ap.parse_args())

Unsere benötigten Pakete werden in den Zeilen 2-6 importiert. Vor allem werden wir OpenCV und imutils verwenden. Wenn Sie es noch nicht getan haben, installieren Sie sie:

  • Um OpenCV zu installieren, folgen Sie einfach einer meiner OpenCV-Installationsanleitungen.
  • Das imutils-Paket kann mit pip installiert/aktualisiert werden: pip install --upgrade imutils . Achten Sie darauf, es zu aktualisieren, da häufig neue Funktionen hinzugefügt werden.

Von dort aus werden wir zwei Befehlszeilenargumente in den Zeilen 9-14 analysieren:

  • --images : Der Pfad zum Verzeichnis der Eingabebilder zum Zusammenfügen.
  • --output : Der Pfad zum Ausgabebild, in dem das Ergebnis gespeichert werden soll.

Wenn Sie mit den Konzepten von argparse und Befehlszeilenargumenten nicht vertraut sind, lesen Sie diesen Blogbeitrag.

Laden wir unsere Eingabebilder:

# grab the paths to the input images and initialize our images listprint(" loading images...")imagePaths = sorted(list(paths.list_images(args)))images = # loop over the image paths, load each one, and add them to our# images to stitch listfor imagePath in imagePaths:image = cv2.imread(imagePath)images.append(image)

Hier nehmen wir unser imagePaths (Zeile 18).

Dann laden wir für jedes imagePath das image und fügen es der images-Liste hinzu (Zeilen 19-25).

Nun, da die images im Speicher sind, können wir sie mit Hilfe der in OpenCV eingebauten Fähigkeit zu einem Panorama zusammenfügen:

# initialize OpenCV's image stitcher object and then perform the image# stitchingprint(" stitching images...")stitcher = cv2.createStitcher() if imutils.is_cv3() else cv2.Stitcher_create()(status, stitched) = stitcher.stitch(images)

Das stitcher-Objekt wird in Zeile 30 erstellt. Beachten Sie, dass je nachdem, ob Sie OpenCV 3 oder 4 verwenden, ein anderer Konstruktor aufgerufen wird.

Danach können wir unser images an die Methode .stitch übergeben (Zeile 31). Der Aufruf von .stitch gibt sowohl ein status als auch unser stitched Bild zurück (vorausgesetzt, das Stitching war erfolgreich).

Schließlich schreiben wir (1) das zusammengesetzte Bild auf die Festplatte und (2) zeigen es auf dem Bildschirm an:

# if the status is '0', then OpenCV successfully performed image# stitchingif status == 0:# write the output stitched image to diskcv2.imwrite(args, stitched)# display the output stitched image to our screencv2.imshow("Stitched", stitched)cv2.waitKey(0)# otherwise the stitching failed, likely due to not enough keypoints)# being detectedelse:print(" image stitching failed ({})".format(status))

Angenommen, unser status-Flag zeigt Erfolg an (Zeile 35), schreiben wir das stitched-Bild auf die Festplatte (Zeile 37) und zeigen es an, bis eine Taste gedrückt wird (Zeilen 40 und 41).

Andernfalls geben wir einfach eine Fehlermeldung aus (Zeilen 45 und 46).

Basic image stitching results

Um unser Skript zum Zusammenfügen von Bildern auszuprobieren, stellen Sie sicher, dass Sie den Quellcode und die Beispielbilder im Abschnitt „Downloads“ des Tutorials herunterladen.

Im Verzeichnis images/scottsdale/ finden Sie drei Fotos, die ich bei einem Besuch von Frank Lloyd Wrights berühmtem Haus Taliesin West in Scottsdale, AZ aufgenommen habe:

Abbildung 3: Drei Fotos zum Testen von OpenCV Image Stitching. Diese Bilder wurden von mir in Scottsdale, AZ in Frank Lloyd Wrights berühmtem Taliesin West Haus aufgenommen.

Unser Ziel ist es, diese drei Bilder zu einem einzigen Panoramabild zusammenzufügen. Um das Zusammenfügen durchzuführen, öffnen Sie ein Terminal, navigieren Sie zu dem Ort, an dem Sie den Code und die Bilder heruntergeladen haben, und führen Sie den folgenden Befehl aus:

$ python image_stitching_simple.py --images images/scottsdale --output output.png loading images... stitching images...
Abbildung 4: Mit OpenCV durchgeführte Bildzusammenfügung. Dieses Bild wurde bereits zusammengefügt, muss aber noch beschnitten werden.

Beachten Sie, wie erfolgreich wir das Zusammenfügen von Bildern durchgeführt haben!

Aber was ist mit den schwarzen Bereichen, die das Panorama umgeben?

Diese Bereiche stammen von den perspektivischen Verzerrungen, die für die Konstruktion des Panoramas erforderlich sind.

Es gibt eine Möglichkeit, sie loszuwerden… aber wir müssen im nächsten Abschnitt eine zusätzliche Logik implementieren.

Ein besseres Bild-Stitching mit OpenCV und Python

Abbildung 5: In diesem Abschnitt lernen wir, wie wir das Bild-Stitching mit OpenCV verbessern können, indem wir den Bereich des Panoramas innerhalb des rot-gestrichelten Rahmens, der in der Abbildung zu sehen ist, herausschneiden.

Unser erstes Bild-Stitching-Skript war ein guter Anfang, aber diese schwarzen Bereiche, die das eigentliche Panorama umgeben, sind nichts, was wir „ästhetisch ansprechend“ nennen würden.

Und um es noch deutlicher zu sagen: Sie würden ein solches Bild nicht in den gängigen Bildbearbeitungsprogrammen für iOS, Android usw. sehen.

Deshalb werden wir unser Skript ein wenig hacken und einige zusätzliche Logik einbauen, um ästhetisch ansprechendere Panoramen zu erstellen.

Ich möchte noch einmal betonen, dass diese Methode ein Hack ist.

Wir werden grundlegende Bildverarbeitungsoperationen wie Schwellenwerte, Konturextraktion, morphologische Operationen usw. durchgehen, um das gewünschte Ergebnis zu erzielen.

So weit ich weiß, stellen uns die Python-Bindings von OpenCV nicht die erforderlichen Informationen zur Verfügung, um manuell den maximalen inneren rechteckigen Bereich des Panoramas zu extrahieren. Wenn OpenCV dies tut, lassen Sie es mich bitte in den Kommentaren wissen, denn ich würde es gerne wissen.

Legen wir los und fangen wir an – öffnen Sie das image_stitching.py-Skript und fügen Sie den folgenden Code ein:

# import the necessary packagesfrom imutils import pathsimport numpy as npimport argparseimport imutilsimport cv2# construct the argument parser and parse the argumentsap = argparse.ArgumentParser()ap.add_argument("-i", "--images", type=str, required=True,help="path to input directory of images to stitch")ap.add_argument("-o", "--output", type=str, required=True,help="path to the output image")ap.add_argument("-c", "--crop", type=int, default=0,help="whether to crop out largest rectangular region")args = vars(ap.parse_args())# grab the paths to the input images and initialize our images listprint(" loading images...")imagePaths = sorted(list(paths.list_images(args)))images = # loop over the image paths, load each one, and add them to our# images to stich listfor imagePath in imagePaths:image = cv2.imread(imagePath)images.append(image)# initialize OpenCV's image sticher object and then perform the image# stitchingprint(" stitching images...")stitcher = cv2.createStitcher() if imutils.is_cv3() else cv2.Stitcher_create()(status, stitched) = stitcher.stitch(images)

Der gesamte Code ist identisch mit unserem vorherigen Skript, mit einer Ausnahme.

Das --crop-Befehlszeilenargument wurde hinzugefügt. Wenn ein 1 für dieses Argument im Terminal angegeben wird, führen wir unseren Cropping Hack aus.

Im nächsten Schritt beginnen wir mit der Implementierung zusätzlicher Funktionen:

# if the status is '0', then OpenCV successfully performed image# stitchingif status == 0:# check to see if we supposed to crop out the largest rectangular# region from the stitched imageif args > 0:# create a 10 pixel border surrounding the stitched imageprint(" cropping...")stitched = cv2.copyMakeBorder(stitched, 10, 10, 10, 10,cv2.BORDER_CONSTANT, (0, 0, 0))# convert the stitched image to grayscale and threshold it# such that all pixels greater than zero are set to 255# (foreground) while all others remain 0 (background)gray = cv2.cvtColor(stitched, cv2.COLOR_BGR2GRAY)thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)

Beachten Sie, dass ich einen neuen Block für das Setzen des --crop-Flags in Zeile 40 erstellt habe. Beginnen wir damit, diesen Block durchzugehen:

  • Zunächst fügen wir einen 10-Pixel-Rahmen zu allen Seiten unseres stitched-Bildes hinzu (Zeilen 43 und 44), um sicherzustellen, dass wir später in diesem Abschnitt in der Lage sind, die Konturen des gesamten Panorama-Umrisses zu finden.
  • Dann erstellen wir eine gray-Version unseres stitched-Bildes (Zeile 49).
  • Und von dort aus begrenzen wir das gray-Bild (Zeile 50).

Hier ist das Ergebnis (thresh ) dieser drei Schritte:

Abbildung 6: Nach der Schwellenwertbildung sehen wir diese Schwellenwertmaske, die hervorhebt, wo sich das mit OpenCV zusammengesetzte und verzerrte Bild befindet.

Wir haben nun ein binäres Bild unseres Panoramas, bei dem weiße Pixel (255) den Vordergrund und schwarze Pixel (0) den Hintergrund darstellen.

Anhand unseres mit Schwellenwerten versehenen Bildes können wir eine Konturextraktion durchführen und die Bounding Box der größten Kontur (d.h.,

# find all external contours in the threshold image then find# the *largest* contour which will be the contour/outline of# the stitched imagecnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)cnts = imutils.grab_contours(cnts)c = max(cnts, key=cv2.contourArea)# allocate memory for the mask which will contain the# rectangular bounding box of the stitched image regionmask = np.zeros(thresh.shape, dtype="uint8")(x, y, w, h) = cv2.boundingRect(c)cv2.rectangle(mask, (x, y), (x + w, y + h), 255, -1)

Die Konturen werden in den Zeilen 55-57 extrahiert und geparst. Zeile 58 greift dann die Kontur mit der größten Fläche (d.h. den Umriss des zusammengesetzten Bildes selbst).

Hinweis: Die Funktion imutils.grab_contours ist neu in imutils==0.5.2, um OpenCV 2.4, OpenCV 3 und OpenCV 4 und ihre unterschiedlichen Rückgabesignaturen für cv2.findContours zu berücksichtigen.

Zeile 62 weist Speicher für unsere neue rechteckige Maske zu. In Zeile 63 wird dann das Begrenzungsrechteck unserer größten Kontur berechnet. Mit Hilfe der Bounding-Rechteck-Informationen zeichnen wir in Zeile 64 ein durchgehendes weißes Rechteck auf die Maske.

Die Ausgabe des obigen Code-Blocks würde wie folgt aussehen:

Abbildung 7: Der kleinste rechteckige Bereich, in den das gesamte OpenCV-Panorama passen kann.

Diese Bounding-Box ist der kleinste rechteckige Bereich, in den das gesamte Panorama passen kann.

Jetzt kommt einer der größten Hacks, die ich je für einen Blogbeitrag zusammengestellt habe:

# create two copies of the mask: one to serve as our actual# minimum rectangular region and another to serve as a counter# for how many pixels need to be removed to form the minimum# rectangular regionminRect = mask.copy()sub = mask.copy()# keep looping until there are no non-zero pixels left in the# subtracted imagewhile cv2.countNonZero(sub) > 0:# erode the minimum rectangular mask and then subtract# the thresholded image from the minimum rectangular mask# so we can count if there are any non-zero pixels leftminRect = cv2.erode(minRect, None)sub = cv2.subtract(minRect, thresh)

In den Zeilen 70 und 71 erstellen wir zwei Kopien unseres maskBildes:

  1. Die erste Maske, minMask , wird langsam verkleinert, bis sie in den inneren Teil des Panoramas passt (siehe Abbildung 5 oben in diesem Abschnitt).
  2. Die zweite Maske, sub , wird verwendet, um festzustellen, ob minMask weiter verkleinert werden muss.

Zeile 75 startet eine while -Schleife, die so lange läuft, bis keine Vordergrundpixel mehr in sub vorhanden sind.

Zeile 79 führt eine morphologische Erosionsoperation durch, um die Größe von minRect zu verringern.

Zeile 80 subtrahiert dann thresh von minRect – sobald es keine Vordergrundpixel mehr in minRect gibt, können wir die Schleife verlassen.

Ich habe unten eine Animation des Hacks eingefügt:

Abbildung 8: Eine Animation des Hacks, den ich mir ausgedacht habe, um die minRect-Region des OpenCV-Panoramabildes zu extrahieren, was ein ästhetisch ansprechendes, zusammengefügtes Bild ergibt

Oben haben wir unser sub-Bild und unten das minRect-Bild.

Beachte, wie die Größe von minRect schrittweise reduziert wird, bis keine Vordergrundpixel mehr in sub vorhanden sind – an diesem Punkt wissen wir, dass wir die kleinste rechteckige Maske gefunden haben, die in den größten rechteckigen Bereich des Panoramas passt.

Mit dem minimalen inneren Rechteck können wir wieder Konturen finden und die Bounding Box berechnen, aber dieses Mal extrahieren wir einfach die ROI aus dem stitched-Bild:

# find contours in the minimum rectangular mask and then# extract the bounding box (x, y)-coordinatescnts = cv2.findContours(minRect.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)cnts = imutils.grab_contours(cnts)c = max(cnts, key=cv2.contourArea)(x, y, w, h) = cv2.boundingRect(c)# use the bounding box coordinates to extract the our final# stitched imagestitched = stitched

Hier haben wir:

  • Konturen in minRect gefunden (Zeilen 84 und 85).
  • Konturen für mehrere OpenCV-Versionen geparst (Zeile 86). Sie benötigen imutils>=0.5.2, um diese Funktion zu verwenden.
  • Die größte Kontur wurde erfasst (Zeile 87).
  • Die Bounding Box der größten Kontur wurde berechnet (Zeile 88).
  • Die ROI wurde mit Hilfe der Bounding Box-Informationen aus unserer stitched extrahiert (Zeile 92).

Das endgültige stitchedBild kann auf dem Bildschirm angezeigt und dann auf der Festplatte gespeichert werden:

# write the output stitched image to diskcv2.imwrite(args, stitched)# display the output stitched image to our screencv2.imshow("Stitched", stitched)cv2.waitKey(0)# otherwise the stitching failed, likely due to not enough keypoints)# being detectedelse:print(" image stitching failed ({})".format(status))

Die Zeilen 95-99 sorgen für das Speichern und Anzeigen des Bildes, unabhängig davon, ob unser Beschneidungs-Hack durchgeführt wurde oder nicht.

Wie zuvor geben wir eine Fehlermeldung aus, wenn das status-Flag nicht erfolgreich war (Zeilen 103 und 104).

Schauen wir uns nun die Ergebnisse unserer verbesserten Image Stitching + OpenCV Pipeline an.

Verbesserte Image Stitching Ergebnisse

Auch hier gilt: Stellen Sie sicher, dass Sie den „Downloads“-Abschnitt des heutigen Tutorials verwendet haben, um den Quellcode und die Beispielbilder herunterzuladen.

Öffnen Sie nun ein Terminal und führen Sie den folgenden Befehl aus:

$ python image_stitching.py --images images/scottsdale --output output.png \--crop 1 loading images... stitching images... cropping...
Abbildung 8: Das Ergebnis des Stitchings mehrerer Bilder mit OpenCV und Python.

Beachten Sie, dass wir diesmal die schwarzen Bereiche aus den gestitchten Bildern entfernt haben (die durch die Verzerrungstransformationen verursacht wurden), indem wir unseren im obigen Abschnitt beschriebenen Hack angewendet haben.

Einschränkungen und Nachteile

In einem früheren Tutorial habe ich gezeigt, wie man ein Echtzeit-Panorama und einen Algorithmus zum Zusammenfügen von Bildern erstellen kann – dieses Tutorial basierte auf der Tatsache, dass wir die Erkennung von Keypoints, die Extraktion von Merkmalen und den Abgleich von Keypoints manuell durchgeführt haben, was uns Zugang zur Homographie-Matrix verschaffte, mit der wir unsere beiden Eingangsbilder zu einem Panorama verzerren konnten.

Und obwohl die in OpenCV eingebauten cv2.createStitcher und cv2.Stitcher_create Funktionen sicherlich in der Lage sind, akkurate, ästhetisch ansprechende Panoramen zu konstruieren, ist einer der Hauptnachteile der Methode, dass sie jeglichen Zugriff auf die Homographiematrizen abstrahiert.

Eine der Annahmen der Echtzeit-Panoramakonstruktion ist, dass sich die Szene selbst inhaltlich nicht viel verändert.

Wenn wir einmal die anfängliche Homographie-Schätzung berechnet haben, sollten wir die Matrix nur gelegentlich neu berechnen müssen.

Dass wir keinen vollständigen Keypoint-Matching- und RANSAC-Schätzvorgang durchführen müssen, gibt uns einen enormen Geschwindigkeitsschub bei der Erstellung unseres Panoramas, so dass es ohne Zugriff auf die rohen Homographie-Matrizen eine Herausforderung wäre, den in OpenCV eingebauten Bild-Stitching-Algorithmus zu nehmen und ihn in Echtzeit zu konvertieren.

Stoßen Sie auf Fehler, wenn Sie mit OpenCV ein Bild zusammenfügen?

Es ist möglich, dass Sie auf Fehler stoßen, wenn Sie versuchen, entweder die cv2.createStitcher-Funktion oder die cv2.Stitcher_create-Funktionen zu verwenden.

Die beiden „leicht zu behebenden“ Fehler, die ich bei Leuten sehe, sind, dass sie vergessen haben, welche Version von OpenCV sie verwenden.

Wenn du zum Beispiel OpenCV 4 verwendest und versuchst, cv2.createSticher aufzurufen, wirst du die folgende Fehlermeldung erhalten:

>>> cv2.createStitcherTraceback (most recent call last): File "<stdin>", line 1, in <module>AttributeError: module 'cv2' has no attribute 'createStitcher'

Du solltest stattdessen die cv2.Stitcher_create Funktion verwenden.

Gleichermaßen, wenn du OpenCV 3 verwendest und versuchst, cv2.Sticher_create aufzurufen, wirst du diese Fehlermeldung erhalten:

>>> cv2.Stitcher_createTraceback (most recent call last): File "<stdin>", line 1, in <module>AttributeError: module 'cv2' has no attribute 'Stitcher_create'

Du solltest stattdessen die cv2.createSticher Funktion verwenden.

Wenn Sie sich nicht sicher sind, welche OpenCV-Version Sie verwenden, können Sie mit cv2.__version__ prüfen:

>>> cv2.__version__'4.0.0'

Hier sehen Sie, dass ich OpenCV 4.0.0 verwende.

Sie können die gleiche Prüfung auf Ihrem System durchführen.

Der letzte Fehler, auf den Sie stoßen können und der wohl der häufigste ist, hängt damit zusammen, dass OpenCV (1) keine Contrib-Unterstützung hat und (2) ohne die aktivierte Option OPENCV_ENABLE_NONFREE=ON kompiliert wurde.

Um diesen Fehler zu beheben, müssen Sie die opencv_contrib-Module zusammen mit der OPENCV_ENABLE_NONFREE-Option auf ON installiert haben.

Wenn Sie auf einen Fehler stoßen, der mit OpenCVs non-free und contrib-Modulen zusammenhängt, stellen Sie sicher, dass Sie meine OpenCV-Installationsanleitungen lesen, um sicherzustellen, dass Sie die vollständige Installation von OpenCV haben.

Hinweis: Bitte beachten Sie, dass ich Ihnen nicht helfen kann, Ihre eigene OpenCV-Installation zu debuggen, wenn Sie nicht einer meiner Installationsanleitungen gefolgt sind, also stellen Sie bitte sicher, dass Sie meine OpenCV-Installationsanleitungen verwenden, wenn Sie Ihr System konfigurieren.

Zusammenfassung

Im heutigen Tutorial haben Sie gelernt, wie man mit OpenCV und Python mehrere Bilder zusammenfügt.

Mit OpenCV und Python konnten wir mehrere Bilder zusammenfügen und Panoramabilder erstellen.

Unsere ausgegebenen Panoramabilder waren nicht nur genau in ihrer Anordnung, sondern auch ästhetisch ansprechend.

Einer der größten Nachteile der in OpenCV eingebauten Klasse für das Zusammenfügen von Bildern ist jedoch, dass sie einen Großteil der internen Berechnungen abstrahiert, einschließlich der resultierenden Homographiematrizen selbst.

Wenn Sie versuchen, das Zusammenfügen von Bildern in Echtzeit durchzuführen, wie wir es in einem früheren Beitrag getan haben, kann es von Vorteil sein, die Homographiematrix zwischenzuspeichern und nur gelegentlich die Erkennung von Schlüsselpunkten, die Merkmalsextraktion und den Merkmalsabgleich durchzuführen.

Wenn man diese Schritte überspringt und die zwischengespeicherte Matrix zur Durchführung des perspektivischen Warpings verwendet, kann man die Rechenlast der Pipeline reduzieren und letztlich den Algorithmus für das Zusammenfügen von Bildern in Echtzeit beschleunigen, aber leider bieten uns die cv2.createStitcher Python-Bindings von OpenCV keinen Zugriff auf die Rohmatrizen.

Wenn Sie mehr über die Echtzeit-Panoramakonstruktion erfahren möchten, lesen Sie bitte meinen vorherigen Beitrag.

Ich hoffe, dass Ihnen das heutige Tutorial über das Zusammenfügen von Bildern gefallen hat!

Um den Quellcode des heutigen Beitrags herunterzuladen und benachrichtigt zu werden, wenn Tutorials hier auf PyImageSearch veröffentlicht werden, geben Sie einfach Ihre E-Mail-Adresse in das Formular unten ein!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.