Krótka teoria wprowadzająca do OpenCV oraz rozwiązania prostych projektów (opis + Jupyter notebooki).
OpenCV - szybkie wprowadzenie
Szybkie wprowadzenie: Learn X in Y minutes: OpenCV
Jupyter Notebook
Jupyter Notebook - uznałem że w przypadku OpenCV wygodniej będzie umieszczać treść w notatnikach Jupytera niż pisać ją na blogu. Dlatego każdy wpis z OpenCV będzie posiadał odnośnik do niego.
Instalacja
Prosto:
pip install opencv-contrib-python
Dlib
Do niektórych zagadnień oprócz OpenCV potrzebna jest biblioteka Dlib. Instrukcja instalacji dla Ubuntu:
- Utworzenie środowiska z python 3.7:
conda create -n cenv python=3.7.0
- Instalacja cmake:
conda install cmake
- Instalacja Dlib :
pip install dlib
- Sprawdzenie poprawności w IPython:
python
Python 3.7.0 (default, Oct 9 2018, 10:31:47)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import dlib
>>> dlib.__version__
'19.21.0'
Wczytanie OpenCV, Numpy i Pillow:
# sudo apt install libgl1-mesa-glx
import cv2
import numpy as np
from PIL import Image
Podstawowe operacje
Stworzenie pustego obrazu i wyświetlenie z pomoca biblioteki Pillow:
img = np.zeros((100,120,3), dtype='uint8')
Image.fromarray(img)
Koordynaty w OpenCV są liczone wg ponizszego układu współrzędnych:
0/0---X--->
|
|
Y
|
|
v
OpenCV Point(x,y)
Wczytanie istniejącego obrazu:
img = cv2.imread('Lenna.png')
Image.fromarray(img)
Numpy przechowuje kanały kolorów jako RGB, OpenCV zaś jako BGR
- Matplotlib
pyplot.imshow()
: M x N x 3 image, where last dimension is RGB. - OpenCV
cv2.imshow()
: M x N x 3 image, where last dimension is BGR
OpenCV zawiera funkcję która pozwala zamienić kolejność kanałów. Można też skorzystać z pomocy Numpy, choć nie jest to optymalne:
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # or numpy:
img = img[...,::-1] # or:
img = img[:,:,::-1]
Wycięcie fragmentu zdjęcia
# img_sliced = img[y1:y2,x1:x2]
img = img[0:200, 0:200, :]
Zapisywanie obrazu:
cv2.imwrite('save.jpg', img)
Rysowanie
cv2.line(img, (0,0), (200,200), (255,0,0), 5)
cv2.circle(img, (100,100), 50, (255,0,0), 5)
cv2.rectangle(img, (10,10), (100,100), (255,0,0), 5 )
Tekst
cv2.putText(img, "TXT", (10,190), # lewy dolny pkt
cv2.FONT_HERSHEY_SIMPLEX, 1.2, (0,255,200))
Listę dostępnych fontów można znaleźć w pliku imgproc.hpp:
FONT_HERSHEY_SIMPLEX = 0, //!< normal size sans-serif font
FONT_HERSHEY_PLAIN = 1, //!< small size sans-serif font
FONT_HERSHEY_DUPLEX = 2, //!< normal size sans-serif font (more complex than FONT_HERSHEY_SIMPLEX)
FONT_HERSHEY_COMPLEX = 3, //!< normal size serif font
FONT_HERSHEY_TRIPLEX = 4, //!< normal size serif font (more complex than FONT_HERSHEY_COMPLEX)
FONT_HERSHEY_COMPLEX_SMALL = 5, //!< smaller version of FONT_HERSHEY_COMPLEX
FONT_HERSHEY_SCRIPT_SIMPLEX = 6, //!< hand-writing style font
FONT_HERSHEY_SCRIPT_COMPLEX = 7, //!< more complex variant of FONT_HERSHEY_SCRIPT_SIMPLEX
FONT_ITALIC = 16 //!< flag for italic font
Kolory
- grayscale
- RGB
- HSV (hue, saturation, value) :
cv2.COLOR_BGR2HSV
- HLS (hue, saturation, lightness):
COLOR_BGR2HLS
Why do we use the HSV colour space so often in vision and image processing?
RGB v/s HSV for Computer Vision
Finding Lane Lines — Simple Pipeline For Lane Detection
Operacje morfologiczne
Bardzo dobry opis operacji morfologicznych znajduje się na polskiej wersji Wikipedii, np: Dylatacja i Erozja
opening(A) = dilate(erode(A))
closing(A) = erode(dilate(A))
Operatory tophat (ekstrakcja obszarów jasnych) i blackhat (ekstrakcja obszarów ciemnych) służą odpowiednio ekstrakcji jasnych i ciemnych obszarów w obrazie (poziom jasności określany w odniesieniu do najbliższego otoczenia).
- tophat(A) = A − open(A)
- blackhat(A) = close(A) − A
Wykrywanie konturów
contours, hierarchy = cv2.findContours(image, mode, method)
Obraz należy sprowadzić do postaci czarno-białej. Kontury są tworzone tylko wokół białych obszarów.
img = cv2.imread('img/rotate/cnt.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img = cv2.bitwise_not(img)
Tryby wykrywania konturów:
CV_RETR_EXTERNAL
- wykrywa jedynie zewnętrzen kontury, wszystkie kontury zagnieżdzone są ignorowane.
W hierarchii konturów dwie ostatnie koumny mają wrtość -1
[[[ 1 -1 -1 -1] # kontur 0
[ 2 0 -1 -1] # kontur 1
[-1 1 -1 -1]]] # kontur 2
CV_RETR_LIST
- zwraca wszystkie kontury, ale nie określa hierarchii między nimi . Należy stosować jeżeli nie potrzebujemy informacjii o tym czy któryś kontur jest zagnieżdzony wewnątrz kolejnego.
Ponieważ tym razem również nie liczymy hierarchii konturów, to dwie ostatnie koumny mają wrtość -1 Kolumny “Next” i “Previous” mają wymagane wartości
[[[ 1 -1 -1 -1] # kontur 0
[ 2 0 -1 -1] # kontur 1
[ 3 1 -1 -1] # kontur 2
[ 4 2 -1 -1] # ...
[ 5 3 -1 -1]
[ 6 4 -1 -1]
[ 7 5 -1 -1]
[-1 6 -1 -1]]]
CV_RETR_CCOMP
- znajduje kontury i organizuje je w kontury wewnetrzne i zewnetrzne. gives contours and organises them into outer and inner contours. Every contour is either the outline of an object, or the outline of an object inside another object (i.e. hole). The hierarchy is adjusted accordingly. This can be useful if (say) you want to find all holes.
This flag retrieves all the contours and arranges them to a 2-level hierarchy. ie external contours of the object (ie its boundary) are placed in hierarchy-1. And the contours of holes inside object (if any) is placed in hierarchy-2. If any object inside it, its contour is placed again in hierarchy-1 only. And its hole in hierarchy-2 and so on.
[[[ 1 -1 -1 -1]
[ 2 0 -1 -1]
[ 4 1 3 -1]
[-1 -1 -1 2]
[ 6 2 5 -1]
[-1 -1 -1 4]
[ 7 4 -1 -1]
[-1 6 -1 -1]]]
CV_RETR_TREE
- wylicza pełną hierarchę konturów. Widać np. ze kontur 4 jest zagnieżdzony o 4 poziomy względem konturu zerowego.
[[[ 6 -1 1 -1] # kontur 0 - równy 6, rodzic 1
[-1 -1 2 0] # kontur 1 - rodzic 2, dziecko 0
[-1 -1 3 1] # kontur 2 - rodzic 3, dziecko 1
[-1 -1 4 2] # kontur 3 - rodzic konturu 4, dziecko 2
[ 5 -1 -1 3] # kontur 4 - dziecko konturu 3 (4-ty poziom zagnieżdzenia)
[-1 4 -1 3] # kontur 5 - dziecko konturu 3
[ 7 0 -1 -1] # kontur 6 - równy 7, bezdzietny
[-1 6 -1 -1]]] # kontur 7 - bezdzietny
Hierarchia obiektów:
[Next (same level), Previous (same level), First_Child, Parent]
[Next (same level), Previous (same level), First_Child, Parent]
[Next (same level), Previous (same level), First_Child, Parent]
...
- “Next” oznacza następny kontur na tym samym poziomie hierarchii.
- “Previous” oznacza poprzedni kontur na tym samym poziomie hierarchii.
- “First_Child” oznacza jego pierwszy kontur dziecka.
- “Parent” oznacza indeks konturu rodzica.
Projekty
Rotate images
Tematy które poznałem przy okzaji tego ćwiczenia:
- findContours - (RetrievalModes)
- drawCountours - podanie 1 jako grubość linii powoduje wypełnienie obiektu
- Konwersja
cv2.COLOR_BGR2RGB
icv2.COLOR_BGR2GRAY
to nie to samo co wyłączniecv2.COLOR_BGR2GRAY
Building a Pokedex in Python: Finding the Game Boy Screen
Text skew correction
Lista tematów które poznałem przy okazji tego ćwiczenia:
- Układy współrzędnych w OpenCV
- Treshold
- BoundingBox
Watermarking Images
- Tryby wczytywania obrazów ImreadModes