Main Body

Identyfikacja obiektów

Ważnym elementem analizy obrazu jest wychwycenie pewnych charakterystycznych cech. Nie tylko kolory lub kształty mogą być użyteczne w tym zadaniu. Okazuje się, że całkiem dobrze spisują się charakterystyczne punkty obrazu związane z krawędziami czy rogami. Znalezione punkty charakterystyczne nazywamy punktami kluczowymi (keypoint). Każdy punkt kluczowy możemy opisać za pomocą deskryptora.

Każdy z nas intuicyjnie czuje co możemy nazwać rogiem, jednak istnieje kilka definicji oraz metod wyznaczania dobrych punktów kluczowych w tym rogów obrazu. W zadaniu wykrycia rogów możemy wykorzystać metodę Harrisa lub Shi i Tomasiego. Natomiast w praktyce zadanie wykrycia dobrych punktów kluczowych, możemy zrealizować z wykorzystaniem funkcji goodFeaturesToTrack. W wyniku działania funkcji otrzymujemy listę punktów kluczowych spełniających pewne kryteria.

Na listingu 1 zaprezentowano przykład programu wykorzystujący funkcję goodFeaturesToTrack do znalezienia punktów kluczowych. Oprócz obrazu wejściowego na którym chcemy wyszukać punktów charakterystycznych, należy podać liczbę szukanych punktów, oraz jakość punktów qualityLevel w zakresie 0-1 oraz minimalny dystans pomiędzy kolejnymi punktami. Na rysunku 1 zaprezentowano przykład wykrycia rogów dla prostej grafiki natomiast na rysunku 2 zaprezentowano wynik detekcji rogów dla zdjęcia.

 

Listing 1. Przykład znalezienia rogów z wykorzystaniem funkcji goodFeaturesToTrack.


import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt

img = cv.imread('box_a.jpg')
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)

corners = cv.goodFeaturesToTrack(gray,55,0.01,10)
corners = np.int0(corners)

for i in corners:
   x,y = i.ravel()
   cv.circle(img,(x,y),3,255,-1)

plt.imshow(img),plt.show()

Rysunek 1. Przykład znalezienia rogów dla grafiki.

 

Rysunek 2. Przykład znalezienia rogów dla zdjęcia.

Nie tylko same punkty charakterystyczne mogą być użyteczne. Jedną z koncepcji jest poszukiwanie pewnych obszarów obrazu podobnych do plamy (blob). Biblioteka OpenCV wspiera wykrywanie plam z wykorzystaniem funkcji SimpleBlobDetector. Przykład programu do detekcji plam zaprezentowano na listingu 2. Wynik działania programu zaprezentowano na rysunku 3.

Listing 2. Przykład programu wykrywającego plamy na obrazie


import cv2
import numpy as np

image = cv2.imread('lewandowski.jpg', 0)

params = cv2.SimpleBlobDetector_Params()

params.filterByArea = True
params.minArea = 20

detector = cv2.SimpleBlobDetector_create(params)
keypoints = detector.detect(image)

blank = np.zeros((1, 1))
blobs = cv2.drawKeypoints(image, keypoints, blank, (0, 0, 255),cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

cv2.imshow("Blobs", blobs)
cv2.waitKey(0)
cv2.destroyAllWindows()

cv2.imwrite('wynik_plamy.jpg',blobs)

Rysunek 3. Wynik programu wykrywającego plamy o zadanych parametrach.

 

Istnieje możliwość wykrycia plam o zadanych parametrach. Na przykład możemy zdefiniować wielkość plamy, podobieństwo do koła. W zależności od ustawień, możliwe jest wykrycie interesujących plam na obrazie. Przykład listingu wykrywającego wszystkie plamy zaprezentowano na listingu 3. Program wykrywający plamy zbliżone kształtem do okręgu zaprezentowano na listingu 4. Wyniki programu wykrywającego wszystkie plamy oraz plamy o kształcie koła zaprezentowano na rysunkach 4 oraz 5. Proszę zwrócić uwagę oraz przeanalizować w dokumentacji na możliwe opcje wykrywania plam.

 

Listing 3. Przykład programu wykrywającego wszystkie plamy

import cv2
import numpy as np

image = cv2.imread('plamy.jpg', 0)
img=cv2.imread('plamy.jpg',1)

params = cv2.SimpleBlobDetector_Params()

#params.filterByArea = True
params.minArea = 10

detector = cv2.SimpleBlobDetector_create(params)
keypoints = detector.detect(image)

blank = np.zeros((1, 1))
blobs = cv2.drawKeypoints(img, keypoints, blank, (0, 0, 255),cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

cv2.imshow('plamy', blobs)
cv2.waitKey(0)
cv2.destroyAllWindows()

cv2.imwrite('plamy_wykryte.jpg',blobs)

 

Listing 3. Przykład programu wykrywającego plamy w kształcie koła

import cv2
import numpy as np

image = cv2.imread('plamy.jpg', 0)
img=cv2.imread('plamy.jpg',1)

params = cv2.SimpleBlobDetector_Params()

params.filterByArea = True
params.minArea = 10

params.filterByCircularity = True
params.minCircularity = 0.88


params.filterByConvexity = True
params.minConvexity = 0.2

params.filterByInertia = True
params.minInertiaRatio = 0.01

detector = cv2.SimpleBlobDetector_create(params)
keypoints = detector.detect(image)

blank = np.zeros((1, 1))
blobs = cv2.drawKeypoints(img, keypoints, blank, (0, 0, 255),cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

cv2.imshow('Plamy', blobs)
cv2.waitKey(0)
cv2.destroyAllWindows()

cv2.imwrite('plamy_wykryte_kola.jpg',blobs)

 

Rysunek 4. Wynik programu wykrywającego plamy o zadanych parametrach.

 

Rysunek 5. Wynik programu wykrywającego plamy o zadanych parametrach w kształcie okręgu.

Opracowano wiele technik wykrywania punktów kluczowych i wyznaczania deskryptorów. Do najpopularniejszych należą metoda FAST (Features from Accelerated Segments Test). Metoda bazuje na koncepcji porównywania punktów wokół danego punktu. Jeśli otaczające piksele są podobne, to zapewne nie jest to dobry punkt charakterystyczny i nie będzie dobrym kandydatem na cechę obrazu.  Algorytm FAST jest rozwinięciem algorytmu SUSAN, jednak porównuje tylko punkty leżące na pierścieniu otaczającym punkt. Druga różnica polega na tym, że punkty są klasyfikowane jako jaśniejsze i ciemniejsze niż rozważany punkt a następnie zliczane. Bardziej zaawansowaną metodą detekcji cech jest SIFT (Scale Invariant Transform). Metoda SIFT wymaga większej mocy obliczeniowej w porównaniu do innych metod. Nazwa metody pochodzi on wykrywania pewnych cech związanych z niezmiennością względem skali. Na początku obliczany jest zbiór splotów pomiędzy obrazem wejściowym a gausowskimi jądrami o większym rozmiarze. Następnie obliczana jest kombinacja splotów z bezpośrednim następcą. W praktyce, jeśli chcemy znaleźć punkty charakterystyczne na obrazie wideo zależy nam na szybkim działaniu. W zadaniu tym sprawdzić się może detektor cech ORB. W pierwszym etapie wykrywane są punkty charakterystyczne z wykorzystaniem algorytmu FAST a następnie wyznaczane deskryptory z wykorzystaniem rogów Harrisa. Przykład wykorzystania algorytmu ORB do znalezienia punktów charakterystycznych zaprezentowano na listingu 4. W tym celu obraz wejściowy poddano modyfikacjom polegającym na obrocie, przeskalowaniu. Do wyznaczenia punktów kluczowych oraz cech służy funkcja detectAndCompute() a do porównania punktów kluczowych match(). Program łączy liniami 10 najlepszych dopasowań. Wynik działania programu zaprezentowano na rysunku 6. Na rysunku 7 oraz 8 zaprezentowano porównanie obrazów twarzy dla tej samej i innej osoby. Jak widać, wyznaczone cechy nie zawsze są dobrymi deskryptorami.

Listing 4. Przykład programu porównującego punkty kluczowe w obrazach

import numpy as np
import cv2
from matplotlib import pyplot as plt

img1 = cv2.imread('greece.jpg',0) # queryImage
img2 = cv2.imread('greece1.jpg',0) # trainImage

orb = cv2.ORB_create()

kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

matches = bf.match(des1,des2)

matches = sorted(matches, key = lambda x:x.distance)

img3 = cv2.drawMatches(img1,kp1,img2,kp2,matches[:10] ,None, flags=2)

plt.imshow(img3),plt.show()

Rysunek 6. Wynik programu porównującego punkty charakterystyczne.

 

Rysunek 7. Porównanie punktów dla obrazu twarzy tej samej osoby [FEI Face Database].
Rysunek 8. Porównanie punktów dla obrazu różnych osób [FEI Face Database].

 

Ważnym elementem analizy obrazów jest detekcja obiektów. Celem detekcji jest wykrycie na obrazie danego obiektu oraz wskazanie miejsca wykrytego obiektu. Należy zaznaczyć, że detekcja obiektów na obrazie jest dynamicznie rozwijającą się dziedziną. W chwili obecnej rozwijane są z bardzo dobrym skutkiem techniki wykorzystujące uczenie głębokie (deep learning) a w szczególności konwolucyjne sieci nieuronowe (convolutional neural network -CNN). W bibliotece OpenCV popularną metodą detekcji jest wykorzystanie klasyfikatorów kaskadowych oraz cech Haara. Od metod detekcji wymaga się szybkiego działania oraz dobrej trafności. Umożliwia to wykrycie obiektu na obrazie wideo oraz poprawną klasyfikację obiektów. Właściwości takie posiada właśnie klasyfikator kaskadowy z cechami Haara.

Cechy Haara to nic innego jak pewne proste wzorce. Przykład takich wzorców zaprezentowano na rysunku 9. Cechy Haar’a możemy interpretować jako pewną informację o zmianie wartości kontrastu pomiędzy prostokątnymi grupami pikseli. Sąsiednie grupy o podobnej jasności tworzą cechę Haar’a. Wartość cechy dla danego szablonu to różnica sumy pikseli w miejscu białego prostokątna i sumy pikseli w miejscu czarnego prostokąta. W wyniku takiego dopasowania szablonu do fragmentu obrazu dostajemy jedną wartość skalarną. Cechy są skalowane i przesuwane w każdym poszukiwanym fragmencie obrazu. Uwzględniając wszystkie typy cech Haar’a oraz ich położenia i skale, dla pewnego fragmentu obrazu obliczanych jest około kilkaset tysięcy cech. Jest to zbyt wiele cech i nie każda z nich jest użyteczna. Dlatego stosujemy technikę Adaboost. Polega ona na tym, że stosujemy wiele słabych klasyfikatorów ułożonych w kaskadzie. W końcowym wyniku otrzymujemy bardzo dobry klasyfikator, który umożliwia skuteczną detekcję obiektu.

 

Rysunek 9. Cechy Haara.

Ważnym elementem wpływającym na skuteczność wykrywania obiektów jest trenowanie klasyfikatora. W praktyce, należy przygotować różnorodny zestaw obrazów przykładowych zawierających obiekty, które chcemy wykryć oraz zestaw obrazów, które nie zawierają obiektów. Im liczniejsza liczba przykładów do trenowania tym lepiej, jednak szacuje się, że dla niektórych zastosowań wystarczą setki a w niektórych tysiące przykładów trenujących. Trenowanie klasyfikatora do dość długi proces. W wyniku wytrenowania powstaje reguła decyzyjna (klasyfikator) który zostaje zapisany w postaci pliku .xml. W internecie można znaleźć wytrenowane klasyfikatory wykrywające obiekty takie jak: twarz, oczy, usta, samochody itp. Należy jednak zwrócić szczególną uwagę i sprawdzić w praktyce działanie detektora. Chodzi tu o liczbę fałszywych detekcji oraz liczbę poprawnych detekcji.

Na listingu 5 zaprezentowano przykład programu wykrywającego twarz oraz oczy użytkownika. Klasyfikator załadowany jest w postaci pliku xml, służy do tego funkcja CascadeClassifier(). Następnie funkcja detectMultiScale(), wykrywa na obrazie twarz oraz zwraca współrzędne wykrytego obiektu. Funkcja wymaga podania obrazu w odcieniach szarości, na którym chcemy wykryć obiekt. Następnie należy zadeklarować parametr scaleFactor. Ustalenie tego parametru na wartość scaleFactor = 1.07 oznacza zmniejszenie rozmiaru wejściowego o 7%, co zwiększa szansę na wykrycie twarzy przez model. Im większa wartość tym jakość wykrytych obiektów jest wyższa. Kolejny parametr to minNeighbors. Patametr ten deklaruje minimalną liczbę sąsiadujących obszarów, które zaklasyfikowano obiekt. Parametr wpływa na jakość wykrytych twarzy. Wyższa wartość powoduje mniej wykrywalności, ale o wyższej jakości. Możemy też zadeklarować parametr  minSize. Jest to minimalny rozmiar obszaru zawierający wykryty obiekt. Od zadeklarowanych parametrów detekcji zależy jakość działania detektora. Na rysunku 10 zaprezentowano przykład działania detektora dla twarzy na wprost kamery, zaś na rysunku 11 twarzy obróconej.

Listing 5. Przykład programu wykorzystującego cechy Haara i klasyfikator kaskadowy.


import numpy as np
import cv2

face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')

img = cv2.imread('2-05.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

faces = face_cascade.detectMultiScale(gray, 1.2, 10)
for (x,y,w,h) in faces:
   cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
   roi_gray = gray[y:y+h, x:x+w]
   roi_color = img[y:y+h, x:x+w]

   eyes = eye_cascade.detectMultiScale(roi_gray)
      for (ex,ey,ew,eh) in eyes:
          cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

cv2.imshow('img',img)
cv2.imwrite('wynikdetekcji_.jpg', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Rysunek 10. Przykład detekcji twarzy i oczu.

 

Rysunek 11. Przykład detekcji twarzy i oczu dla twarzy obróconej.

Wytrenowane klasyfikatory kaskadowe Haara możemy wytrenować samemu oraz możemy wykorzystać jeden z ogólnodostępnych klasyfikatorów. Na listingu 6 zaprezentowano przykład programu wykrywającego znak STOP na obrazie. W tym przypadku skorzystano z wytrenowanego klasyfikatora. Należy zwrócić uwagę, że dobrane parametry detekcji w funkcji detectMultiScale() mogą być dobre dla jednego zdjęcia, natomiast niepoprawnie dobrane mogą skutkować niepoprawnym działaniem detekcji. Na rysunku 12 zaprezentowano wynik detekcji znaku STOP.

 

Listing 6. Program do wykrywania znaków stop na obrazie.


import numpy as np
import cv2

stopsign_cascade = cv2.CascadeClassifier('stop_sign_classifier_2.xml')

img = cv2.imread('stop.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

faces = stopsign_cascade.detectMultiScale(gray, 1.5, 5)
for (x,y,w,h) in faces:
   cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),15)
   roi_gray = gray[y:y+h, x:x+w]
   roi_color = img[y:y+h, x:x+w]

scale_percent = 30 # percent of original size
width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100)
dim = (width, height)

img = cv2.resize(img, dim, interpolation = cv2.INTER_AREA)
cv2.imshow('img',img)

cv2.waitKey(0)
cv2.destroyAllWindows()

Rysunek 12. Przykład detekcji znaku STOP.

 

Zadanie 1.

Napisz program, wykrywający twarz na obrazie zarejestrowanym bezpośrednio z kamery. Sprawdź, czy detekcja opóźnia akwizycję i czy program pozwala na płynne działanie. Pochyl głowę, w przód tył na boki, przysłoń twarz ręką. Sprawdź jak wpływa to na detekcję twarzy.

Odpowiedź 1.

Program do wykrywania twarzy oraz oczu na obrazie wideo zaprezentowano na listingu 7. Klasyfikatory kaskadowe, umożliwiają szybką detekcję i nie wpływają na płynność działania programu w przypadku dobrania właściwych parametrów detekcji.

 

Listing 7. Program do wykrywania twarzy na obrazie z kamery.


import numpy as np
import cv2

face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')

vid = cv2.VideoCapture(0, cv2.CAP_DSHOW)

while(True):

   ret, frame = vid.read()
   img = frame

   gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

   faces = face_cascade.detectMultiScale(gray, 1.2, 6)
   if len(faces) !=0:
      for (x,y,w,h) in faces:
         cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
         roi_gray = gray[y:y+h, x:x+w]
         roi_color = img[y:y+h, x:x+w]

cv2.imshow('img',img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break

vid.release()
cv2.destroyAllWindows()

Zadanie 2.

Napisz program, wykrywający punkty charakterystyczne na obrazie zarejestrowanym bezpośrednio z kamery. Sprawdź, czy detekcja punktów opóźnia akwizycję i czy program pozwala na płynne działanie.  Poruszaj kamerą. sprawdź czy punkty się zmieniają.

Odpowiedź 2.

Program do wykrywania punktów charakterystycznych zaprezentowano na listingu 8. Funkcja goodFeaturesToTrack, umożliwiają szybką detekcję i nie wpływają na płynność działania programu.


Listing 8. Program do wykrywania punktów charakterystycznych na obrazie z kamery.

import numpy as np
import cv2

vid = cv2.VideoCapture(0, cv2.CAP_DSHOW)

while(True):

   ret, frame = vid.read()
   img = frame

   gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
   corners = cv2.goodFeaturesToTrack(gray,55,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('img',img)
if cv2.waitKey(1) & 0xFF == ord('q'):
   break

vid.release()
cv2.destroyAllWindows()

Zadanie 3.

Napisz program, wykrywający punkty charakterystyczne na obrazie wideo zarejestrowanym w trakcie przejazdu pojazdów. Zapisz plik wynikowy jako plik wideo. Zwróć uwagę na pojawiające się punkty charakterystyczne.

Odpowiedź 3.

Program do wykrywania punktów charakterystycznych w obrazie wideo zaprezentowano na listingu 9.  Do wczytania obrazu służy funkcja VideoCapture(). Do zapisania obrazu wideo wykorzystujemy funkcję VideoWriter(). Wynik działania programu można zobaczyć na Filmie 1.


Listing 9. Program do wykrywania punktów charakterystycznych na obrazie z kamery.

import cv2
import numpy as np

cap = cv2.VideoCapture('samochody.avi')

frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
size = (frame_width, frame_height)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
result = cv2.VideoWriter('wynik_detekcji.avi',fourcc,25.0,size)

while(1):

   ret, frame = cap.read()

      if ret == True:

         gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
         corners = cv2.goodFeaturesToTrack(gray,55,0.01,10)
         corners = np.int0(corners)

        for i in corners:
           x,y = i.ravel()
        cv2.circle(frame,(x,y),3,255,-1)

        cv2.imshow('res',frame)
        result.write(frame)

        k = cv2.waitKey(5) & 0xFF
           if k == 27:
              break
           else:
              break

cv2.destroyAllWindows()
cap.release();
result.release();


Film 1. Przykład detekcji punktów charakterystycznych dla ruchu drogowego.

 

Zadanie 4.

Napisz program, wykrywający punkty charakterystyczne na obrazie wideo twarzy. Zapisz plik wynikowy jako plik wideo. Zwróć uwagę na pojawiające się punkty charakterystyczne.

Odpowiedź 4.

Program do wykrywania punktów charakterystycznych w obrazie wideo zaprezentowano na listingu 9.  Wynik działania programu można zaobserwować na Filmie 2.


Film 2. Przykład detekcji punktów charakterystycznych dla twarzy.

 

Zadanie 5.

Napisz program, wykrywający twarz wideo twarzy. Zapisz plik wynikowy jako plik wideo.

Odpowiedź 5.

Program do przetwarzania obrazu wideo zaprezentowano na listingu 9.  Do detekcji twarzy należy zastosować klasyfikator kaskadowy Haara. Wynik działania programu można zaobserwować na Filmie 3.


Film 3. Przykład detekcji twarzy.

License

Projektowanie systemów wizyjnych Copyright © by Marcin Kołodziej. All Rights Reserved.

Share This Book