Zszywanie obrazów za pomocą OpenCV i Pythona

W tym poradniku dowiesz się, jak wykonać zszywanie obrazów za pomocą Pythona, OpenCV oraz funkcji cv2.createStitcher i cv2.Stitcher_create. Używając dzisiejszego kodu, będziesz w stanie zszyć wiele obrazów razem, tworząc panoramę zszytych obrazów.

Nieco ponad dwa lata temu opublikowałem dwa przewodniki na temat zszywania obrazów i konstruowania panoram:

  1. Fundamentals of image stitching
  2. Real-time panorama and image stitching

Oba te poradniki obejmowały podstawy typowego algorytmu zszywania obrazów, które, w absolutnym minimum, wymagają czterech kluczowych kroków:

  1. Detecting keypoints (DoG, Harris, itp.) i wyodrębnienie lokalnych niezmiennych deskryptorów (SIFT, SURF, itp.) z dwóch obrazów wejściowych
  2. Pasowanie deskryptorów między obrazami
  3. Użycie algorytmu RANSAC do oszacowania macierzy homografii przy użyciu naszych dopasowanych wektorów cech
  4. Zastosowanie transformacji wypaczającej przy użyciu macierzy homografii uzyskanej z kroku #3

Jednakże największym problemem z moimi oryginalnymi implementacjami jest to, że nie były one w stanie obsłużyć więcej niż dwóch obrazów wejściowych.

W dzisiejszym tutorialu zajmiemy się zszywaniem obrazów za pomocą OpenCV, włączając w to sposób na zszycie więcej niż dwóch obrazów razem w obraz panoramiczny.

Aby dowiedzieć się jak zszywać obrazy za pomocą OpenCV i Pythona, po prostu czytaj dalej!

Image Stitching with OpenCV and Python

W pierwszej części dzisiejszego poradnika, krótko omówimy algorytm zszywania obrazów OpenCV, który jest wbudowany w samą bibliotekę OpenCV poprzez funkcje cv2.createStitcher i cv2.Stitcher_create.

Potem przejrzymy strukturę naszego projektu i zaimplementujemy skrypt Pythona, który może być użyty do zszywania obrazów.

Przejrzymy wyniki tego pierwszego skryptu, zauważymy jego ograniczenia, a następnie zaimplementujemy drugi skrypt Pythona, który może być użyty do bardziej estetycznych wyników zszywania obrazów.

Na koniec przejrzymy wyniki naszego drugiego skryptu i ponownie zauważymy wszelkie ograniczenia lub wady.

Algorytm zszywania obrazu w OpenCV

Ryc. 1: Potok modułu zszywania zaimplementowany w klasie Stitcher (źródło).

Algorytm, którego będziemy tu dziś używać, jest podobny do metody zaproponowanej przez Browna i Lowe’a w ich pracy z 2007 r., Automatic Panoramic Image Stitching with Invariant Features.

W przeciwieństwie do poprzednich algorytmów zszywania obrazów, które są wrażliwe na uporządkowanie obrazów wejściowych, metoda Browna i Lowe’a jest bardziej odporna, co czyni ją niewrażliwą na:

  • Porządkowanie obrazów
  • Orientację obrazów
  • Zmiany iluminacji
  • Szumy obrazów, które w rzeczywistości nie są częścią panoramy

Co więcej, ich metoda zszywania obrazów jest zdolna do wytwarzania bardziej estetycznych wyjściowych obrazów panoramicznych dzięki zastosowaniu kompensacji wzmocnienia i mieszania obrazów.

Kompletny, szczegółowy przegląd algorytmu jest poza zakresem tego postu, więc jeśli jesteś zainteresowany dowiedzeniem się więcej, zapoznaj się z oryginalną publikacją.

Struktura projektu

Zobaczmy, jak ten projekt jest zorganizowany za pomocą polecenia tree:

$ 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

Obrazy wejściowe znajdują się w folderze images/. Zdecydowałem się utworzyć podfolder dla mojego scottsdale/ zestawu obrazów na wypadek, gdybym chciał później dodać tu dodatkowe podfoldery.

Dzisiaj przejrzymy dwa skrypty Pythona:

  • image_stitching_simple.py : Nasza prosta wersja zszywania obrazów może być ukończona w mniej niż 50 wierszach kodu Pythona!
  • image_stitching.py : Ten skrypt zawiera mój hack do wyodrębniania ROI zszytego obrazu w celu uzyskania estetycznego wyniku.

Ostatni plik, output.png , to nazwa wynikowego zszytego obrazu. Używając argumentów wiersza poleceń, można łatwo zmienić nazwę pliku + ścieżkę dostępu do obrazu wyjściowego.

Funkcje cv2.createStitcher i cv2.Stitcher_create

Rysunek 2: Sygnatura konstruktora do tworzenia obiektu klasy Stitcher za pomocą OpenCV.

OpenCV zaimplementowało już metodę podobną do pracy Browna i Lowe’a poprzez funkcje cv2.createStitcher (OpenCV 3.x) i cv2.Stitcher_create (OpenCV 4).

Zakładając, że masz poprawnie skonfigurowane i zainstalowane OpenCV, będziesz w stanie zbadać sygnaturę funkcji cv2.createStitcher dla OpenCV 3.x:

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

Zauważ, że ta funkcja ma tylko jeden parametr, try_gpu, który może być użyty do poprawienia całego twojego potoku zszywania obrazów. Obsługa GPU w OpenCV jest ograniczona i nigdy nie udało mi się sprawić, by ten parametr działał, więc zalecam pozostawienie go zawsze jako False.

Funkcja cv2.Stitcher_create dla OpenCV 4 ma podobny podpis:

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.

Aby wykonać faktyczne zszywanie obrazów, będziemy musieli wywołać metodę .stitch:

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.

Ta metoda przyjmuje listę wejściowych images , a następnie próbuje zszyć je w panoramę, zwracając wyjściowy obraz panoramy do funkcji wywołującej.

Zmienna status wskazuje, czy zszywanie obrazu zakończyło się sukcesem, czy nie, i może być jedną z czterech zmiennych:

  • OK = 0 : Zszywanie obrazu zakończyło się sukcesem.
  • ERR_NEED_MORE_IMGS = 1 : W przypadku otrzymania tego kodu stanu będziesz potrzebował więcej obrazów wejściowych do skonstruowania panoramy. Zazwyczaj ten błąd występuje, gdy na obrazach wejściowych nie wykryto wystarczającej liczby punktów kluczowych.
  • ERR_HOMOGRAPHY_EST_FAIL = 2 : Ten błąd występuje, gdy estymacja homografii RANSAC nie powiodła się. Ponownie, możesz potrzebować więcej obrazów lub twoje obrazy nie mają wystarczającej ilości wyróżniających się, unikalnych tekstur/obiektów, aby punkty kluczowe zostały dokładnie dopasowane.
  • ERR_CAMERA_PARAMS_ADJUST_FAIL = 3 : Nigdy wcześniej nie spotkałem się z tym błędem, więc nie mam zbyt dużej wiedzy na jego temat, ale sedno jest takie, że jest on związany z niepowodzeniem w prawidłowym oszacowaniu intrinsics/extrinsics kamery z obrazów wejściowych. Jeśli napotkasz ten błąd, być może będziesz musiał odwołać się do dokumentacji OpenCV lub nawet zanurkować w kodzie OpenCV C++.

Teraz, gdy już przejrzeliśmy metody cv2.createStitcher , cv2.Stitcher_create i .stitch , przejdźmy do faktycznej implementacji zszywania obrazów za pomocą OpenCV i Pythona.

Implementowanie zszywania obrazów za pomocą Pythona

Zacznijmy implementować nasz algorytm zszywania obrazów!

Otwórz plik image_stitching_simple.py i wstaw następujący kod:

# 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())

Nasze wymagane pakiety są importowane w liniach 2-6. W szczególności, będziemy używać OpenCV i imutils. Jeśli jeszcze tego nie zrobiłeś, zainstaluj je:

  • Aby zainstalować OpenCV, po prostu podążaj za jednym z moich przewodników instalacji OpenCV.
  • Pakiet imutils może być zainstalowany/uaktualniony za pomocą pip: pip install --upgrade imutils . Pamiętaj, aby go uaktualnić, ponieważ często dodawane są nowe funkcje.

Z tego miejsca będziemy parsować dwa argumenty wiersza poleceń w liniach 9-14:

  • --images : Ścieżka do katalogu obrazów wejściowych do zszycia.
  • --output : Ścieżka do obrazu wyjściowego, gdzie wynik zostanie zapisany.

Jeśli nie jesteś zaznajomiony z pojęciami argparse i argumentami wiersza poleceń, to przeczytaj ten wpis na blogu.

Załadujmy nasze obrazy wejściowe:

# 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)

Tutaj złapiemy nasz imagePaths (Linia 18).

Potem dla każdego imagePath , załadujemy image i dodamy go do listy images (Linie 19-25).

Teraz, gdy images znajdują się w pamięci, przejdźmy dalej i zszyjmy je razem w panoramę, używając wbudowanych możliwości OpenCV:

# 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)

Obiekt stitcher jest tworzony w linii 30. Zauważ, że w zależności od tego, czy używasz OpenCV 3 czy 4, wywoływany jest inny konstruktor.

Następnie możemy przekazać nasz obiekt images do metody .stitch (linia 31). Wywołanie metody .stitch zwraca zarówno obraz status, jak i nasz stitched (zakładając, że zszywanie się powiodło).

W końcu (1) zapiszemy zszyty obraz na dysku i (2) wyświetlimy go na ekranie:

# 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))

Zakładając, że nasza flaga status oznacza sukces (Linia 35), zapiszemy obraz stitched na dysku (Linia 37) i wyświetlimy go, dopóki nie zostanie naciśnięty klawisz (Linie 40 i 41).

W przeciwnym razie po prostu wydrukujemy komunikat o niepowodzeniu (Linie 45 i 46).

Podstawowe wyniki zszywania obrazów

Aby wypróbować nasz skrypt zszywania obrazów, upewnij się, że skorzystasz z sekcji „Pliki do pobrania” w samouczku, aby pobrać kod źródłowy i przykładowe obrazy.

Wewnątrz katalogu images/scottsdale/ znajdują się trzy zdjęcia, które zrobiłem podczas wizyty w słynnym domu Franka Lloyda Wrighta Taliesin West w Scottsdale, AZ:

Rysunek 3: Trzy zdjęcia do przetestowania w OpenCV zszywania obrazów. Zdjęcia te zostały wykonane przeze mnie w Scottsdale, AZ w słynnym domu Franka Lloyda Wrighta Taliesin West.

Naszym celem jest zszycie tych trzech obrazów w jeden obraz panoramiczny. Aby wykonać zszywanie, otwórz terminal, przejdź do miejsca, z którego pobrałeś kod + obrazy, i wykonaj następujące polecenie:

$ python image_stitching_simple.py --images images/scottsdale --output output.png loading images... stitching images...
Rysunek 4: Zszywanie obrazów wykonane za pomocą OpenCV. Ten obraz został już zszyty, ale nie został jeszcze wykadrowany.

Zauważ, że udało nam się zszyć obraz!

Ale co z tymi czarnymi obszarami otaczającymi panoramę? Co to jest?

Te regiony pochodzą z wykonywania wypaczenia perspektywy wymaganego do skonstruowania panoramy.

Jest sposób, aby się ich pozbyć… ale będziemy musieli zaimplementować pewną dodatkową logikę w następnej sekcji.

Lepsze zszywanie obrazów za pomocą OpenCV i Pythona

Rysunek 5: W tej sekcji dowiemy się, jak ulepszyć zszywanie obrazów za pomocą OpenCV poprzez wykadrowanie obszaru panoramy wewnątrz czerwonej kreski pokazanej na rysunku.

Nasz pierwszy skrypt zszywania obrazów był dobrym początkiem, ale te czarne obszary otaczające samą panoramę nie są czymś, co nazwalibyśmy „estetycznym”.

I bardziej do punktu, nie zobaczyłbyś takiego obrazu wyjściowego z popularnych aplikacji do zszywania obrazów wbudowanych w iOS, Android, itp.

Dlatego zamierzamy zhakować nasz skrypt trochę i włączyć trochę dodatkowej logiki, aby stworzyć bardziej estetyczne panoramy.

Jeszcze raz powtórzę, że ta metoda jest zhakowana.

Będziemy analizować podstawowe operacje przetwarzania obrazu, w tym progowanie, ekstrakcję konturów, operacje morfologiczne, itp. w celu uzyskania pożądanego rezultatu.

Według mojej wiedzy, wiązania OpenCV w Pythonie nie dostarczają nam wymaganych informacji, aby ręcznie wyodrębnić maksymalny wewnętrzny prostokątny region panoramy. Jeśli OpenCV to robi, proszę dać mi znać w komentarzach, ponieważ bardzo chciałbym się tego dowiedzieć.

Dalej i zacznijmy – otwórz skrypt image_stitching.py i wstaw następujący kod:

# 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)

Cały ten kod jest identyczny z naszym poprzednim skryptem z jednym wyjątkiem.

Dodany został argument wiersza poleceń --crop. Gdy 1 zostanie podany dla tego argumentu w terminalu, przejdziemy dalej i wykonamy nasz hack kadrowania.

Następny krok jest tym, w którym zaczynamy implementować dodatkową funkcjonalność:

# 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)

Zauważ, że stworzyłem nowy blok dla sytuacji, gdy flaga --crop jest ustawiona na linii 40. Zacznijmy przechodzić przez ten blok:

  • Po pierwsze, dodamy 10 pikselowe obramowanie do wszystkich boków naszego stitched obrazu (Linie 43 i 44), zapewniając, że będziemy w stanie znaleźć kontury pełnego zarysu panoramy w dalszej części tej sekcji.
  • Potem utworzymy wersję gray naszego stitched obrazu (Linia 49).
  • I stamtąd progujemy obraz gray (Linia 50).

Oto rezultat (thresh ) tych trzech kroków:

Rysunek 6: Po progowaniu, otrzymujemy maskę progowania, która podkreśla miejsce, w którym znajduje się zszyty i wypaczony obraz OpenCV.

Mamy teraz binarny obraz naszej panoramy, gdzie białe piksele (255) są pierwszym planem, a czarne piksele (0) są tłem.

Dając nasz progowany obraz możemy zastosować ekstrakcję konturu, obliczyć pole ograniczające największego konturu (tj, kontur samej panoramy) i narysować pole ograniczające:

# 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)

Kontury są wyodrębniane i przetwarzane w liniach 55-57. Linia 58 pobiera następnie kontur o największym obszarze (tj. kontur samego zszytego obrazu).

Uwaga: Funkcja imutils.grab_contours jest nowa w imutils==0.5.2, aby dostosować się do OpenCV 2.4, OpenCV 3 i OpenCV 4 oraz ich różnych sygnatur zwrotnych dla cv2.findContours .

Linia 62 alokuje pamięć dla naszej nowej prostokątnej maski. Następnie linia 63 oblicza prostokąt ograniczający naszego największego konturu. Korzystając z informacji o prostokącie ograniczającym, w linii 64 rysujemy na masce jednolity biały prostokąt.

Wyjście powyższego bloku kodu wyglądałoby następująco:

Rysunek 7: Najmniejszy prostokątny region, w którym zmieści się cała panorama OpenCV.

Ten prostokąt ograniczający jest najmniejszym prostokątnym regionem, w którym zmieści się cała panorama.

Teraz następuje jeden z największych hacków, jakie kiedykolwiek stworzyłem na potrzeby wpisu na blogu:

# 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)

W liniach 70 i 71 tworzymy dwie kopie naszego mask obrazu:

  1. Pierwsza maska, minMask , będzie powoli zmniejszana, aż zmieści się w wewnętrznej części panoramy (zobacz rysunek 5 na górze tej sekcji).
  2. Druga maska, sub , zostanie użyta do określenia, czy musimy dalej zmniejszać rozmiar minMask .

Linia 75 uruchamia pętlę while , która będzie się zapętlać, dopóki w sub nie będzie już pikseli pierwszego planu .

Linia 79 wykonuje operację morfologiczną erozji, aby zmniejszyć rozmiar minRect .

Linia 80 następnie odejmuje thresh od minRect – gdy w minRect nie ma już pikseli pierwszego planu, wtedy możemy wyłamać się z pętli.

Załączyłem animację tego hacka poniżej:

Ryc. 8: Animacja hacka, który wymyśliłem, aby wyodrębnić region minRect z obrazu panoramy OpenCV, tworząc estetycznie zszyty obraz

Na górze mamy nasz obraz sub, a na dole mamy obraz minRect.

Zauważ, jak rozmiar minRect jest stopniowo zmniejszany aż do momentu, gdy w sub nie pozostaną już żadne piksele pierwszego planu – w tym momencie wiemy, że znaleźliśmy najmniejszą prostokątną maskę, która może zmieścić się w największym prostokątnym regionie panoramy.

Dając minimalny wewnętrzny prostokąt, możemy ponownie znaleźć kontury i obliczyć ramkę ograniczającą, ale tym razem po prostu wyodrębnimy ROI z obrazu stitched:

# 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

Tutaj mamy:

  • Znalezienie konturów w minRect (Linie 84 i 85).
  • Obsługa parsowania konturów dla wielu wersji OpenCV (Linia 86). Będziesz potrzebował imutils>=0.5.2 do użycia tej funkcji.
  • Pobranie największego konturu (linia 87).
  • Obliczenie ramki ograniczającej największego konturu (linia 88).
  • Wyodrębnienie ROI z naszego stitched przy użyciu informacji o ramce ograniczającej (linia 92).

Końcowy obraz stitched może zostać wyświetlony na naszym ekranie, a następnie zapisany na dysku:

# 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))

Linie 95-99 obsługują zapisywanie i wyświetlanie obrazu niezależnie od tego, czy nasz hack kadrowania został wykonany, czy nie.

Tak jak poprzednio, jeśli flaga status nie wróciła jako sukces, wydrukujemy komunikat o błędzie (Linie 103 i 104).

Przejdźmy dalej i sprawdźmy rezultaty naszego ulepszonego potoku OpenCV.

Ulepszone wyniki zszywania obrazów

Ponownie, upewnij się, że skorzystałeś z sekcji „Downloads” w dzisiejszym tutorialu, aby pobrać kod źródłowy i przykładowe obrazy.

Potem otwórz terminal i wykonaj następującą komendę:

$ python image_stitching.py --images images/scottsdale --output output.png \--crop 1 loading images... stitching images... cropping...
Rysunek 8: Wynik naszego wielokrotnego zszywania obrazów za pomocą OpenCV i Pythona.

Zauważ, że tym razem usunęliśmy czarne regiony z wyjściowych zszytych obrazów (spowodowane przez transformacje wypaczające), stosując nasz hack opisany w sekcji powyżej.

Ograniczenia i wady

W poprzednim tutorialu zademonstrowałem, jak można zbudować algorytm tworzenia panoramy i zszywania obrazów w czasie rzeczywistym – ten tutorial opierał się na tym, że ręcznie wykonywaliśmy detekcję punktów kluczowych, ekstrakcję cech i dopasowywanie punktów kluczowych, co dało nam dostęp do macierzy homografii użytej do przekształcenia naszych dwóch obrazów wejściowych w panoramę.

I chociaż wbudowane w OpenCV funkcje cv2.createStitcher i cv2.Stitcher_create są z pewnością zdolne do konstruowania dokładnych, estetycznych panoram, jedną z podstawowych wad tej metody jest to, że abstrahuje ona od dostępu do macierzy homografii.

Jednym z założeń konstruowania panoram w czasie rzeczywistym jest to, że sama scena nie zmienia się zbytnio pod względem zawartości.

Po obliczeniu wstępnej estymacji homografii powinniśmy mieć tylko okazjonalną potrzebę rekompilacji macierzy.

Brak konieczności wykonywania pełnego dopasowania punktów kluczowych i estymacji RANSAC daje nam ogromny wzrost szybkości podczas budowania naszej panoramy, więc bez dostępu do surowych macierzy homografii, wyzwaniem byłoby wykorzystanie wbudowanego w OpenCV algorytmu zszywania obrazów i przekonwertowanie go na czas rzeczywisty.

Występowanie błędów podczas wykonywania zszywania obrazów przy użyciu OpenCV?

Możliwe jest, że możesz napotkać błędy podczas próby użycia funkcji cv2.createStitcher lub cv2.Stitcher_create.

Dwa „łatwe do rozwiązania” błędy, na które napotykają ludzie to zapominanie, jakiej wersji OpenCV używają.

Na przykład, jeśli używasz OpenCV 4, ale próbujesz wywołać cv2.createSticher, napotkasz następujący komunikat o błędzie:

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

Powinieneś zamiast tego użyć funkcji cv2.Stitcher_create.

Podobnie, jeśli używasz OpenCV 3 i próbujesz wywołać cv2.Sticher_create, otrzymasz ten błąd:

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

Zamiast tego użyj funkcji cv2.createSticher.

Jeśli nie jesteś pewien, której wersji OpenCV używasz, możesz sprawdzić używając cv2.__version__ :

>>> cv2.__version__'4.0.0'

Tutaj możesz zobaczyć, że używam OpenCV 4.0.0.

Możesz wykonać to samo sprawdzenie w swoim systemie.

Ostatni błąd, który możesz napotkać, i prawdopodobnie najczęstszy, jest związany z OpenCV (1) nie posiadającym wsparcia contrib i (2) skompilowanym bez włączonej opcji OPENCV_ENABLE_NONFREE=ON.

Aby rozwiązać ten błąd musisz mieć zainstalowane moduły opencv_contrib wraz z opcją OPENCV_ENABLE_NONFREE ustawioną na ON .

Jeśli napotkasz błąd związany z modułami OpenCV non-free i contrib, upewnij się, że zapoznałeś się z moimi przewodnikami instalacji OpenCV, aby upewnić się, że masz pełną instalację OpenCV.

Uwaga: Proszę zauważyć, że nie mogę pomóc w debugowaniu twojej własnej instalacji OpenCV, jeśli nie zastosowałeś się do jednego z moich przewodników instalacji, więc upewnij się, że używasz moich przewodników instalacji OpenCV podczas konfigurowania systemu.

Podsumowanie

W dzisiejszym poradniku dowiedziałeś się jak wykonać zszywanie wielu obrazów używając OpenCV i Pythona.

Używając zarówno OpenCV jak i Pythona byliśmy w stanie zszyć wiele obrazów razem i stworzyć obrazy panoramiczne.

Nasze wyjściowe obrazy panoramiczne były nie tylko dokładne w ich rozmieszczeniu, ale także estetyczne.

Jedną z największych wad korzystania z wbudowanej klasy zszywania obrazów OpenCV jest to, że abstrahuje ona od wielu wewnętrznych obliczeń, w tym wynikowych macierzy homografii.

Jeśli próbujesz wykonać zszywanie obrazów w czasie rzeczywistym, tak jak zrobiliśmy to w poprzednim poście, możesz uznać za korzystne buforowanie macierzy homografii i tylko od czasu do czasu wykonywać wykrywanie punktów kluczowych, ekstrakcję cech i dopasowywanie cech.

Pominięcie tych kroków i użycie buforowanej macierzy do wykonania wypaczania perspektywy może zmniejszyć obciążenie obliczeniowe twojego potoku i ostatecznie przyspieszyć algorytm zszywania obrazu w czasie rzeczywistym, ale niestety, wiązania OpenCV do Pythona nie zapewniają nam dostępu do surowych macierzy.

Jeśli chcesz dowiedzieć się więcej na temat konstruowania panoram w czasie rzeczywistym, zajrzyj do mojego poprzedniego wpisu.

Mam nadzieję, że podobał ci się dzisiejszy tutorial na temat zszywania obrazów!

Aby pobrać kod źródłowy do dzisiejszego wpisu i być powiadamianym o publikacjach tutoriali na PyImageSearch, wpisz swój adres e-mail w poniższym formularzu!

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.