Developer.

OpenCV - wprowadzenie

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]]]

OpenCV Countours: Dice

  • 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

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 i cv2.COLOR_BGR2GRAY to nie to samo co wyłącznie cv2.COLOR_BGR2GRAY

Building a Pokedex in Python: Finding the Game Boy Screen

Contours Hierarchy

Text skew correction

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

Watermarking images

Determining object color

Determining object color

Shape detection

Shape detection

Center of contour

Center of contour

Recognizing LCD digits

Recognizing LCD Digits

Determining object color

Determining object color

Panorama stitching

panorama stitching

Foreground Segmentation and Extraction

OpenCV GrabCut: Foreground Segmentation and Extraction