2015-02-27 28 views
5

Pracuję nad obrazami siatkówki. Obraz składa się z okrągłej siatkówki na czarnym tle. Dzięki OpenCV udało mi się uzyskać kontur, który otacza całą okrągłą siatkówkę. To, czego potrzebuję, to wykadrować okrągłą siatkówkę z czarnego tła.Jak przyciąć wewnętrzny obszar konturu?

+2

co masz na myśli przez kadrowanie? Obrazy są zawsze prostokątne, więc możesz utworzyć maskę i wykonać następujące operacje (przetwarzanie/renderowanie) tylko w maskowanych pikselach. Możesz też przyciąć obraz tak, aby był reprezentowany przez obwiednię siatkówki, która może być znacznie mniejsza niż oryginalny obraz, ale nadal będzie zawierała czarne części (ponieważ siatkówka nie jest prostokątna).Lub możesz przyciąć do maksymalnego prostokątnego regionu WEWNĄTRZ siatkówki, który nie miałby żadnych czarnych pikseli tła, ale również usunie części siatkówki. Który chcesz? – Micka

+2

Jeśli jest to ostatni scenariusz, spróbuj http://stackoverflow.com/questions/21410449/how-do-i-crop-to-largest-interior-bounding-box-in-opencv/21479072#21479072 – Micka

+0

@GauravPatil - Chociaż ta odpowiedź ma kilka lat, ciągle otrzymuję upvotes na moją odpowiedź ... co oznacza, że ​​prawdopodobnie jest to poprawne. Jeśli to pomogło ci w jakikolwiek sposób, byłbym wdzięczny, gdybyś mógł zaakceptować odpowiedź, aby ludzie wiedzieli, że nie potrzebujesz już pomocy w tym zakresie. Dzięki! – rayryeng

Odpowiedz

17

Nie jest jasne, czy w danym pytaniu chcesz wykadrować informacje zdefiniowane w konturze lub zamaskować informacje, które nie są istotne dla wybranego konturu. Zbadam, co robić w obu sytuacjach.


Maskowanie informacje

Zakładając, że prowadził cv2.findContours na obrazie, można otrzymaliśmy strukturę, która zawiera listę wszystkich dostępnych konturów w obrazie. Zakładam również, że znasz kontur, który był używany do otaczania pożądanego obiektu. Zakładając, że jest to przechowywane w idx, najpierw użyj cv2.drawContours, aby narysować wypełnioną wersję tego konturu na pustym obrazie, a następnie użyj tego obrazu, aby zindeksować obraz, aby wyodrębnić obiekt. Ta logika maskuje poza wszelką nieistotną informacją i zachowuje tylko to, co jest ważne - co jest zdefiniowane w zaznaczonym konturze. Kod zrobić to będzie wyglądać mniej więcej tak, zakładając, że obraz jest obraz w skali szarości zapisane w img:

import numpy as np 
import cv2 
img = cv2.imread('...', 0) # Read in your image 
contours, _ = cv2.findContours(...) # Your call to find the contours 
idx = ... # The index of the contour that surrounds your object 
mask = np.zeros_like(img) # Create mask where white is what we want, black otherwise 
cv2.drawContours(mask, contours, idx, 255, -1) # Draw filled contour in mask 
out = np.zeros_like(img) # Extract out the object and place into output image 
out[mask == 255] = img[mask == 255] 

# Show the output image 
cv2.imshow('Output', out) 
cv2.waitKey(0) 
cv2.destroyAllWindows() 

Jeśli rzeczywiście chcesz przyciąć ...

Jeśli chcesz upraw obraz, należy zdefiniować minimalne okno ograniczające rozciągłość obszaru zdefiniowanego przez kontur. Możesz znaleźć lewy górny i dolny prawy róg obwiedni, a następnie użyć indeksowania, aby wykadrować to, czego potrzebujesz. Kod będzie taki sam jak poprzednio, ale będzie dodatkowym etapem przycinania:

import numpy as np 
import cv2 
img = cv2.imread('...', 0) # Read in your image 
contours, _ = cv2.findContours(...) # Your call to find the contours 
idx = ... # The index of the contour that surrounds your object 
mask = np.zeros_like(img) # Create mask where white is what we want, black otherwise 
cv2.drawContours(mask, contours, idx, 255, -1) # Draw filled contour in mask 
out = np.zeros_like(img) # Extract out the object and place into output image 
out[mask == 255] = img[mask == 255] 

# Now crop 
(x, y) = np.where(mask == 255) 
(topx, topy) = (np.min(x), np.min(y)) 
(bottomx, bottomy) = (np.max(x), np.max(y)) 
out = out[topx:bottomx+1, topy:bottomy+1] 

# Show the output image 
cv2.imshow('Output', out) 
cv2.waitKey(0) 
cv2.destroyAllWindows() 

kod przycinania działa tak, że kiedy możemy zdefiniować maskę, aby wyodrębnić z obszaru określonego konturu, możemy dodatkowo wybrać najmniejsze współrzędne poziome i pionowe, które definiują lewy górny róg konturu. Podobnie znajdujemy największe współrzędne poziome i pionowe, które definiują lewy dolny róg konturu. Następnie używamy indeksowania z tymi współrzędnymi, aby przyciąć to, czego faktycznie potrzebujemy. Zwróć uwagę, że powoduje to przycięcie obrazu zamaskowanego - to jest zdjęcie, które usuwa wszystko oprócz informacji zawartych w największym konturze.

Uwaga z OpenCV 3.x

Należy zauważyć, że powyższy kod zakłada używasz OpenCV 2.4.x. Zwróć uwagę, że w OpenCV 3.x zmieniono definicję cv2.drawContours. W szczególności wyjście to trzyelementowe wyjście krotkowe, w którym pierwszym obrazem jest obraz źródłowy, a pozostałe dwa parametry są takie same, jak w OpenCV 2.4.x. Dlatego po prostu zmień instrukcję cv2.findContours w powyższym kodzie, aby zignorować pierwsze wyjście:

_, contours, _ = cv2.findContours(...) # Your call to find contours 
+0

@RedetGetachew - Nie, współrzędne nie są zamieniane. Dane wyjściowe 'np.where' udostępniają lokalizacje wierszy w' x' i lokalizacje kolumn w 'y', które są niezerowe. Dlatego indeksowanie w tablicy jest poprawne. Proszę przetestuj swoje zmiany, zanim zaproponujesz zmianę. – rayryeng