37
Instalacja pip install opencv-python run pip install opencv-contrib-python CZĘŚĆ II

CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Instalacja

pip install opencv-python

run pip install opencv-contrib-python

CZĘŚĆ II

Page 2: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Przydatne

Potrzebne importy: • import cv2 • import numpy as np

Odczyt, zapis i wyświetlanie obrazu: • img=cv2.imread('cell.jpg') • cv2.imwrite(‚new_image.jpg', img) • cv2.imshow('bin',img)

Page 3: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Operacje morfologiczne

Operacje morfologiczne pozwalają przeprowadzić zaawansowaną analizę kształtów poszczególnych obiektów w obrazie oraz na wyznaczenie ich wzajemnej odległości. Ważną cechą tych przekształceń jest ich łączność, która pozwala na generowanie skomplikowanych algorytmów analizy obrazu: • usuwanie szumu, • izolowanie obiektów, • ekstrakcja cech obiektów, • rozdzielanie i łączenie elementów

Page 4: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Operacje morfologiczne: erozja

• Erozja jest operacją odwrotną do dylatacji; wartość każdego piksela zamieniana jest na wartość lokalnego minimum wszystkich wartości pikseli, które obejmuje jądro transformacji.

• Erozję najczęściej stosuje się do usunięcia usterek obrazu, przykładowo w postaci zaszumienia typu „sól i pieprz” (pojedyncze punkty znikają w wyniku erozji, zaś większe struktury prezentujące wartościową część obrazu pozostają).

Page 5: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Operacje morfologiczne: dylatacja

Dylatacja stanowi splot obrazu ze zdefiniowanym jądrem; wartość każdego piksela zamieniania jest na wartość lokalnego maksimum wszystkich wartości pikseli, które obejmuje wspomniane jądro. Efektem dylatacji jest rozrost w obrazie wypełnionych (różnych ode 0) obszarów. Dylatacja powoduje rozszerzenie jasnych obszarów oraz wypełnianie zagłębień) a erozja ich zmniejszanie oraz likwidacje wypukłości. Ostateczny efekt działania obu operatorów zależy od wyboru jądra. Dylatację najczęściej stosuje się dla wyszukania połączonych składowych obrazu (dużych obszarów o podobnym poziomie intensywności lub barwie).

Page 6: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Erozja i dylatacja: obraz zbinaryzowany

#erozja erosion = cv2.erode(img,kernel,iterations = 1)

#dylatacja dilatation = cv2.dilate(img,kernel,iterations = 1)

kernel = np.ones((5,5),np.uint8)

Page 7: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Erozja i dylatacja: obraz w skali szarości

Page 8: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Gradient morfologiczny • Operacja gradientu morfologicznego polega na odjęciu od wyniku

dylatacji obrazu (nieznacznie zredukowanego) wyniku erozji obrazu (nieznacznie powiększonego). Fakt odjęcia od obrazu powiększonego obrazu pomniejszonego pozwala zachować ciągłość w przebiegu krawędzi, a tym samym może być wstępem do segmentacji obiektów.

• Skutkiem jest pozostawienie w obrazie przebiegu krawędzi i konturów obrazu oryginalnego.

• W przypadku obrazu monochromatycznego zastosowanie gradientu pozwala uzyskać informację o szybkości zmian w poziomie intensywności sąsiadujących pikseli.

gradient A = dilate A − erode(A)

• najczęściej stosowana jest do ekstrakcji krawędzi jasnych obszarów,

które w konsekwencji mogą być rozważane jako całe obiekty (lub fragmenty większych całości).

Page 9: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Otwarcie i zamknięcie

• Operację otwarcia (opening) i zamknięcia (closing) opierają się na złożeniu erozji i dylatacji, wykonanych sekwencyjnie:

opening A = dilate erode A

closing A = erode(dilate A ) • Operacje te nie ograniczają się jedynie do obrazów binarnych:

– operacja zamknięcia na obrazie monochromatycznym pozwala na wyeliminowanie z obrazu wartości mniejszych od swoich sąsiadów,

– operacja otwarcia- na wyeliminowanie wartości większych od tych w sąsiadujących pikselach.

Page 10: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Otwarcie i zamknięcie

• Głównym zastosowaniem operacji otwarcia jest zliczanie obszarów w obrazach binarnych. Przykładowo określając próg dyskryminacji dla komórek w obrazie mikroskopowym, przed przystąpieniem do ich zliczania poprzez otwarcie, można oddzielić komórki znajdujące się w bezpośrednim sąsiedztwie.

Page 11: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

• Operacja zamknięcia stosuje się w przetwarzaniu obrazów przedstawiających złączone komponenty, celem usunięcia ich nadmiarowej liczby (przykładowo usunięcie segmentów powstałych z zaszumienia obrazu).

• Wynik operacji zamknięcia jest zbliżony do wyniku erozji, a wynik otwarcia do wyniku dylatacji. Otwarcie i zamknięcie pozwalają jednak lepiej zachować pole obszaru.

Otwarcie i zamknięcie

Page 12: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Otwarcie i zamknięcie: obraz zbinaryzowany

opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)

Page 13: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Otwarcie i zamknięcie: obraz w skali szarości

Page 14: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

TopHat i BlackHat

• Operatory tophat i blackhat służą odpowiednio ekstrakcji jasnych i ciemnych obszarów w obrazie (poziom jasności określany w odniesieniu do najbliższego otoczenia).

• Ekstrakcja obszarów jasnych odejmuje wynik operacji otwarcia (open) wykonanej na obrazie A od obrazu wejściowego A (nieprzetworzonego )

tophat A = A − open A • Ekstrakcja obszarów ciemnych: blackhat A = close A − A • podstawowym zastosowaniem obu operacji jest wyszczególnienie w

obrazie obszarów charakteryzujących się zmianą poziomu jasności w stosunku do obiektu z którym sąsiadują lub są związane (często spotykane w przypadku obrazów mikroskopowych)

Page 15: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

TopHat i BlackHat: obraz zbinaryzowany

tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel) blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)

Page 16: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

TopHat i BlackHat: obraz w skali szarości

Page 17: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Dyskretna Transformata Fouriera

Funkcja cv2.dft implementuje algorytm szybkiej transformaty Fouriera zarówno dla sygnałów jedno- jak i dwuwymiarowych (w przypadku obrazów możliwe jest zarówno policzenie dyskretnej transformaty Fouriera dla całego obrazu jako sygnału 2D jak również potraktowanie każdego wiersza osobno jako sygnału jednowymiarowego).

Page 18: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Dyskretna Transformata Fouriera (DFT) img = cv2.imread('cell.jpg',0) f = np.fft.fft2(img) fshift = np.fft.fftshift(f) magnitude_spectrum = 20*np.log(np.abs(fshift))

Page 19: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Poszukiwanie wzorców (Template matching)

• Template matching to metoda wyszukiwania i znajdowania położenia zdefiniowanego wzorca (szablonu) w większym obrazie.

• W bibliotece OpenCV służy do tego funkcja cv2.matchTemplate(), która „przesuwa” szablon nad obrazem wejściowym (jak dla splotu maski i obrazu) z równoczesnym porównaniem szablonu i badanego fragmentu obrazu wejściowego.

Page 20: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Poszukiwanie wzorców (Template Matching)

Page 21: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

import cv2 import numpy as np from matplotlib import pyplot as plt img_rgb = cv2.imread('cell.jpg') img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY) template = cv2.imread('cell_temp.jpg',0) w, h = template.shape[::-1] res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED) threshold = 0.8 loc = np.where( res >= threshold) for pt in zip(*loc[::-1]): cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2) cv2.imwrite('res2.png',img_rgb)

Poszukiwanie wzorców (Template Matching)

Page 22: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Poszukiwanie wzorców (Template Matching)

Page 23: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Transformata Hougha (wykrywanie okręgów)

W matematyce koło jest reprezentowane równaniem:

(x − x0)2+(y − y

0)2= r2

gdzie: (x0,y0) reprezentuje współrzędne środka okręgu, zaś r jego promień. Równanie to zawiera 3 parametry, stąd obliczenie go wprost z transformaty Hougha wymagałoby implementacji silnika 3D. Biblioteka OpenCV do poszukiwania okręgów wykorzystuje metodę gradientową opartą na informacji o przebiegu krawędzi:

cv2.HoughCircles()

Page 24: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Transformata Hougha (wykrywanie okręgów)

Page 25: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Transformata Hougha (wykrywanie okręgów)

Page 26: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

import cv2 import numpy as np img = cv2.imread('cell.jpg',0) img = cv2.medianBlur(img,5) cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR) circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,20, param1=100,param2=50,minRadius=15,maxRadius=50) circles = np.uint16(np.around(circles)) for i in circles[0,:]: # draw the outer circle cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2) # draw the center of the circle cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3) cv2.imshow('detected circles',cimg) cv2.imwrite('circles5.jpg', cimg) cv2.waitKey(0) cv2.destroyAllWindows()

Transformata Hougha (wykrywanie okręgów)

Page 27: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Segmentacja (watershed)

Page 28: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

img = cv2.imread('cell_gray.jpg') gray= cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU) kernel = np.ones((3,3),np.uint8) # noise removal opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2) sure_bg = cv2.dilate(opening,kernel,iterations=3) # sure background area # Finding sure foreground area dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5) ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0) sure_fg = np.uint8(sure_fg) # Finding unknown region unknown = cv2.subtract(sure_bg,sure_fg) ret, markers = cv2.connectedComponents(sure_fg) # marker labelling # Add one to all labels so that sure background is not 0, but 1 markers = markers+1 markers[unknown==255] = 0 # now, mark the region of unknown with zero markers = cv2.watershed(img,markers) img[markers == -1] = [255,0,0] cv2.imwrite('wshed.jpg',img)

Page 29: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Rekonstrukcja obrazu (inpainting) • Rekonstrukcja metodą inpaintingu przeprowadzana jest

w przypadku zdjęć zawierających usterki, mogące wynikać choćby z zabrudzenia obiektywu lub uszkodzeń mechanicznych samego zdjęcia.

• Metoda ta opiera się na pobraniu informacji o kolorze i

teksturze zniszczonego fragmentu z jego krawędzi, a w dalszej kolejności powieleniu i „wymieszaniu” ich wartości.

• Biblioteka OpenCV daje możliwość zdefiniowania

promienia wokół odtwarzanego piksela, określającego zakres pikseli z których informacja będzie rekonstruowana.

Page 30: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Rekonstrukcja obrazu (inpainting)

• Metoda inpaintingu sprawdza się jedynie dla stosunkowo niewielkich obszarów uszkodzenia i z niezbyt zróżnicowaną teksturą (w przeciwnym razie rekonstrukcji może towarzyszyć efekt rozmycia). Metoda nie sprawdzi się również jeśli w brakującym fragmencie znajduje się cała struktura (brak możliwości odtworzenia z krawędzi obszaru).

• Biblioteka OpenCV oferuje 2 algorytmy inpaintingu dostępne jako argumenty funkcji cv2.inpaint():

• INPAINT_TELEA

• INPAINT_NS

Page 31: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Rekonstrukcja obrazu: INPAINT_TELEA (2004) • Algorytm oparty jest o Technikę Szybkiego Marszu (Fast Marching

Technique) • Dla każdego obszaru który ma być zrekonstruowany, algorytm startuje na

granicy zdefiniowanego sąsiedztwa i w kolejnych krokach wypełnia „do środka” wszystkie brakujące obszary.

• Nowa wartość każdego piksela stanowi średnią ważoną wartości pikseli w

otoczeniu o małym promieniu. • Kluczowym czynnikiem jest wybór wag: największe wagi

przyporządkowywane są pikselom w bezpośrednim sąsiedztwie wypełnianego piksela, oraz pikselom wyznaczającym kontur całego obszaru. Po zrekonstruowaniu wartości piksela algorytm przesuwa się do kolejnego, metodą szybkiego marszu.

• Metoda FMM zapewnia, iż w pierwszej kolejności rekonstruowane są piksele

leżące w bezpośrednim sąsiedztwie tych o znanej wartości

Page 32: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Rekonstrukcja obrazu: INPAINT_NS (2001) • Metoda Naviera-Stokesa • Algorytm oparty jest na dynamice płynów i wykorzystuje

równania różniczkowe cząstkowe. • Najpierw wędruje wzdłuż krawędzi od znanych regionów

do nieznanych regionów (warunek ciągłości krawędzi). • Algorytm analizuje linie łączące punkty o tej samej

intensywności, dopasowując wektory gradientowe na granicy odtwarzanego obszaru (wykorzystanie metod z dynamiki płynów). Po ich uzyskaniu kolor jest wypełniany w celu zmniejszenia minimalnej wariancji w tym obszarze

Page 33: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Rekonstrukcja obrazu (inpainting)

Page 34: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Rotacja rows,cols = img.shape M = cv2.getRotationMatrix2D((cols/2,rows/2),45,1) dst = cv2.warpAffine(img,M,(cols,rows))

Page 35: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Deskryptory W OpenCV wykonuje to funkcja cv2.goodFeaturesToTrack():

cv2.goodFeaturesToTrack(img, N, quality_level, euclid_dist) gdzie:

• img – obraz wejściowy (w skali szarości) • N- liczba poszukiwanych rogów • quality_level – współczynnik jakości z przedziału (0,1}> Najczęściej

przyjmuje się wartości z przedziału (0.01,0.1) • euclid_dist – minimalna odległość euklidesowa pomiędzy znalezionymi

rogami

Funkcja ta pozwala obliczyć operatory pochodnych, a następnie w toku analizy wybrać z ich listy drobne punkty do śledzenia oraz zdefiniować ich liczbę (N).

Page 36: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

Deskryptory

Page 37: CZĘŚĆ IIhome.agh.edu.pl › ~jsw › aipofm › opencvlab2.pdf · dilatation = cv2.dilate(img,kernel,iterations = 1) kernel = np.ones((5,5),np.uint8) Erozja i dylatacja: obraz

import numpy as np import cv2 from matplotlib import pyplot as plt img = cv2.imread('squares2.jpg') gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) corners = cv2.goodFeaturesToTrack(gray,25,0.01,10) corners = np.int0(corners) for i in corners: x,y = i.ravel() cv2.circle(img,(x,y),3,255,-1) cv2.imshow('bin',img) cv2.imwrite('descriptors.jpg',img)

Deskryptory