Jak widzieliśmy razem w materiale, http://analityk.edu.pl/czym-jest-obraz-dla-komputera/ pokazany był obraz człowieka z czerwoną różą na czarno-białym tle.
.
.
W tym materiale przedstawiony będzie proces doprowadzający do powyższego efektu.
Jeśli nie masz jeszcze zainstalowanej biblioteki OpenCV bardzo łatwo to zrobić, wystarczy w Terminalu, bądź Anaconda prompt (jeśli korzystasz z Anacondy):
Wpisać komendę:
pip install opencv-python
Co tak naprawdę widać na obrazku?
Wczytajmy bibliotekę OpenCV oraz pomocniczo numpy:
import cv2
import numpy as np
Wczytajmy zdjęcie i zmieńmy reprezentacje na HSV:
img = cv2.imread('D:\Biznes\Analityk.edu.pl\kolory\Red-rose.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
metoda cv2.cvtColor pozwala na zmianę reprezentacji koloru z RGB ( dla przypomnienia jest to mix czerwonego, zielonego oraz niebieskiego, polecam szczegóły w artykule poprzedzającym) na reprezentacje HSV ( odcień, nasycenie, jasność)
Aby zobaczyć, jak wygląda każdy z kanałów należy skorzystać z funkcji cv2.split:
h,s,v = cv2.split(hsv)
cv2.imshow('odcień', h)
cv2.imshow('nasycenie', s)
cv2.imshow('jasność', v)
cv2.waitKey(0)
cv2.destroyAllWindows()
Aby oddzielić kolorową różę od obrazka należy stworzyć MASKę, czyli swoiste sitko przez które przelejemy kolorowy obrazek i zostanie nam tylko czerwona róża.
.
.
Najbardziej oczywistym sposobem patrząc na obrazek oryginalny byłoby wydzielenie odcienia czerwonego czyli w tej reprezentacji koloru czerwonego 170-179 w odcieniu, pozostawiając saturacje i jasność od 0 do 255.
# mask
lower_red = np.array([170,0,0])
upper_red = np.array([179,255,255])
mask0 = cv2.inRange(hsv, lower_red, upper_red)
cv2.imshow('mask', mask0)
cv2.waitKey(0)
cv2.destroyAllWindows()
Robiąc maskę korzystając z tego podejścia otrzymujemy poniższy obrazek.
Widzieliśmy natomiast, że w kanale saturacji mamy dużą szanse na jednoznaczne wydzielenie róży od reszty obiektów z obrazka gdyż ma dużo większą saturacje (kolor biały).
W tym celu możemy stworzyć MASKę przez określenie wartości saturacji od 165 do 255 (wartość maksymalna, biel na obrazie), oraz ustawienie odcienia i jasności na pełen zakres – odcień 0-179, jasność 0-255.
# mask
lower_red = np.array([0,165,0])
upper_red = np.array([179,255,255])
mask0 = cv2.inRange(hsv, lower_red, upper_red)
Aby wyświetlić maskę korzystamy z funkcji cv2.imshow:
cv2.imshow('mask', mask)
cv2.waitKey(0)
cv2.destroyAllWindows()
Jak widać nie wystarczyło to na jednoznaczne wydzielenie róży, gdyż podobne nasycenie jest też częścią liści oraz tło. Natomiast wiemy, że zarówno liście jak i tło nie posiada czerwonego koloru nasycenia.
Żadne z tych pojedynczych rozwiązań nie daje nam oczekiwanego efektu, natomiast moglibyśmy je połączyć.
# mask
lower_red = np.array([170,165,0])
upper_red = np.array([179,255,255])
mask0 = cv2.inRange(hsv, lower_red, upper_red)
cv2.imshow('mask', mask0)
cv2.waitKey(0)
cv2.destroyAllWindows()
Otrzymamy wtedy poniższy efekt:
Ostatecznym krokiem jest rozszerzenie zakresu i odcięcie niepotrzebnych resztek, najlepszym sposobem jest metoda prób i błędów przez połączenie dwóch takich masek :
# lower mask (0-10)
lower_red = np.array([0,165,50])
upper_red = np.array([10,255,255])
mask0 = cv2.inRange(hsv, lower_red, upper_red)
# upper mask (170-180)
lower_red = np.array([170,165,50])
upper_red = np.array([179,255,255])
mask1 = cv2.inRange(hsv, lower_red, upper_red)
# join my masks
mask = mask0+mask1
.
.
Przygotowujemy obrazek czarno biały:
im_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#musimy przetłumaczyć obrazek czarno-biały na 3 kanały ale #już w kolorach szarości
im_gray3=cv2.cvtColor(im_gray, cv2.COLOR_GRAY2BGR)
Następnie odwracamy maskę oraz obrazek szarości
mask=cv2.bitwise_not(mask)
im_gray3=cv2.bitwise_not(im_gray3)
Ostatnim krokiem jest połączenie obrazka czarno-białego z obrazkiem kolorowym oraz maską:
im_red = cv2.bitwise_not(im_gray3, img, mask=mask)
Na końcu otrzymujemy taki oto efekt:
cv2.imshow('output', im_red)
.
.
Aby zapisać obrazek korzystamy z metody cv2.imwrite
cv2.imwrite('D:\Biznes\Analityk.edu.pl\kolory\only_rose.png', im_red)