Main Body
Przykłady wykorzystania systemów wizyjnych
W rozdziale tym zostaną zaprezentowane przykłady wykorzystania systemów wizyjnych. Wszystkie potrzebne elementy związane z przetwarzaniem i analizą obrazów zostały zaprezentowane w poprzednich rozdziałach podręcznika.
Przykład pierwszy, dotyczy próby zaprojektowania systemu, który w sposób automatyczny zlicza powierzchnię zabudowań oraz powierzchnię zieloną na dostarczonych zdjęciach lotniczych/satelitarnych. Ważnym aspektem projektowania jest sposób rejestracji i normalizacji zgromadzonych zdjęć. W wielu zastosowaniach, mamy wpływ na te aspekty. Możemy zmieniać odległość i ułożenie kamery względem rejestrowanego obiektu. W wielu zastosowaniach możemy doświetlić rejestrowane obiekty. W przypadku zdjęć lotniczych lub satelitarnych, jesteśmy ograniczeni w tym zakresie. Musimy wziąć pod uwagę nasłonecznienie w trakcie rejestracji, przejrzystość atmosfery związaną z zachmurzeniem oraz zanieczyszczeniami powietrza. Na różnorodność rejestracji, wpływ może mieć pora dnia, zmienny kąt padania promieni słonecznych i w rezultacie cień obiektów. To tylko niektóre aspekty, które powodują, że każde zdjęcie lotnicze może być unikatowe. Dla takiego szerokiego spektrum możliwych rejestracji wyzwaniem staje się znalezienie pewnego uniwersalnego algorytmu.
Przykład zdjęć lotniczych prezentujących wybrane obszary zaprezentowano na rysunkach 1-3. Proszę zwrócić uwagę, na zaprezentowaną szczegółowość zdjęć oraz na skalę. Warto przyjrzeć się zdjęciom i zastanowić się, czy jesteśmy w stanie ocenić, czy każdy z fragmentów obrazu możemy jednoznacznie przypisać do terenów zabudowy czy terenów zieleni. Czy wykorzystujemy do tego, sam rozkład kolorów, jasność obiektów a może sami nie jesteśmy w stanie ocenić czy jest to fragment terenu zielonego czy zabudowania.
Rysunek 1. Zdjęcie lotnicze A, teren parku Pola Mokotowskie. Źródło Ortomapa https://mapa.um.warszawa.pl/.
Rysunek 2. Zdjęcie lotnicze B, teren parku Pola Mokotowskie oraz zabudowań wokół Metra Politechnika. Źródło Ortomapa https://mapa.um.warszawa.pl/.
Rysunek 3. Zdjęcie lotnicze C, teren Kampusu Politechniki Warszawskiej. Źródło Ortomapa https://mapa.um.warszawa.pl/.
Jedną z metod rozwiązania, może być próba wyodrębnienia zakresów kolorów a następnie zliczenie poszczególnych pikseli. Przy odpowiednim doborze zakresów jesteśmy w stanie wyodrębnić powierzchnię terenów zielonych oraz zabudowań. Przykład programu zaprezentowano na listingu 1. Ważnym elementem jest skalowanie obliczonych wartości pikseli na rzeczywistą powierzchnię. W tym celu, bazując na dołączonej skali jesteśmy w stanie obliczyć powierzchnię przypadająca na dany piksel. W przykładzie, za tą wartość odpowiada zmienna mSq. Wartość ta jest inna dla zdjęć A, B, C. W przykładzie wykorzystano konwersje obrazu na składowe HSV. Eksperymentalnie dobrano progi dla terenów zielonych oraz zabudowań. Na rysunku 4 zaprezentowano piksele wyodrębnione dla zabudowań. Na rysunku 5 zaprezentowano piksele wyodrębnione dla terenów zielonych. Proszę zwrócić uwagę, dla jakich fragmentów obrazu dokonano poprawnej i błędnej segmentacji. W wyniku obliczeń, oszacowano powierzchnię obszaru zielonego na 0.046 km2, obszaru zabudowań na 0.064km2.
Listing 1. Program do zliczania powierzchni zabudowań oraz terenów zielonych.
import cv2 import numpy as np mPerPixel = 0.3571428571428571 mSq = mPerPixel**2 frame = cv2.imread('C.jpg') hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) height, width = hsv.shape[:2] height = height*mPerPixel width = width*mPerPixel lower_blue = np.array([80,20,10]) upper_blue = np.array([130,80,255]) lower_green = np.array([10,20,0]) upper_green = np.array([80,255,255]) maskBlue = cv2.inRange(hsv, lower_blue, upper_blue) resBlue = cv2.bitwise_and(frame,frame, mask= maskBlue) maskGreen = cv2.inRange(hsv, lower_green, upper_green) maskGreen = cv2.subtract(maskGreen, maskBlue) resGreen = cv2.bitwise_and(frame,frame, mask= maskGreen) numGreen = cv2.countNonZero(maskGreen) mGreen = numGreen*mSq numBlue = cv2.countNonZero(maskBlue) mBlue = numBlue*mSq print('Obszar zielony: ',mGreen/1000000,'km2, obszar budynków: ',mBlue/1000000,'km2') cv2.imshow('Oryginal',frame) cv2.imshow('Budynki',resBlue) cv2.imshow('Tereny zielone',resGreen) cv2.imwrite('Budynki.jpg',resBlue); cv2.imwrite('Zielen.jpg',resGreen); #cv2.imshow('Zakres szarosci',resGrey) print('Obszar całego obrazu: ',height*width/1000000,'km2') cv2.waitKey(0) cv2.destroyAllWindows()
Rysunek 4. Piksele wyodrębnione dla zabudowań.
Rysunek 5. Piksele wyodrębnione dla terenów zielonych.
Kolejny przykład wykorzystania systemów wizyjnych, może dotyczyć wspomagania zliczania monet. Na rysunku 6 zaprezentowano zdjęcie z kilkoma losowo ułożonymi monetami. Proszę zwrócić uwagę, na nierówne doświetlenie i dobicie światła. Warto zauważyć, że znajdują się tam monety o różnej wielkości. Problem detekcji jest nieco trudniejszy bo występuje tu niejednorodne tło.
Rysunek 6. Zdjęcie monet.
Przykład programu do zliczania, może obejmować przetworzenie wstępne oraz zastosowanie transformaty Hough’a do wykrycia okręgów. Na listingu 2 zaprezentowano program do zliczania monet. W proponowanym systemie, wykorzystujemy obraz o ocienianiach szarości. Obraz jest skalowany oraz dokonywana jest operacja wyrównania histogramu. W kolejnym kroku wejściowy obraz poddawany jest operacji rozmycia z wykorzystaniem filtru medianowego. Do detekcji monet wykorzystano transformatę Hough’a z odpowiednio dobranymi parametrami. W konsoli program wyświetla liczbę wykrytych okręgów (monet).
Listing 2. Program do zliczania monet.
import cv2 import numpy as np img = cv2.imread('11.jpg',0) scale = 0.2 width = int(img.shape[1] * scale) height = int(img.shape[0] * scale) dim = (width, height) img = cv2.resize(img, dim, interpolation = cv2.INTER_AREA) cv2.imshow('org',img) img = cv2.equalizeHist(img) cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR) img = cv2.medianBlur(img, 5) circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,30, param1=50,param2=30,minRadius=20,maxRadius=35) circles = np.uint16(np.around(circles)) for i in circles[0,:]: cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2) cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3) print(len(circles[0,:])) cv2.imshow('detected circles',cimg) cv2.imwrite('liczba_monet.jpg',cimg) cv2.waitKey(0) cv2.destroyAllWindows()
Rysunek 7. Wynik detekcji z wykorzystaniem zaproponowanego algorytmu.
Kolejnym przykładem systemu będzie detekcja koloru na prezentowanej planszy. Zadaniem programu będzie ciągła akwizycja obrazu z kamery oraz analiza obrazu i zliczenie poszczególnych składowych kolorów R, G, B. Wizualizacja zawartości kolorów dla poszczególnych kolorów będzie wizualizowana z wykorzystaniem wysokości słupków: czerwonego, niebieskiego, zielonego. Na listingu 3 zaprezentowano listing programu do detekcji prezentowanego koloru. Zarejestrowana klatka obrazu jest poddawana prostym operacjom a w efekcie, następuje zliczenie poszczególnych elementów macierzy. Z wykorzystaniem funkcji split() następuje rozłożenie macierzy na poszczególne składowe R, B, G obrazu. Ważnym elementem jest normalizacja zliczonych pikseli. W tym celu, suma dla poszczególnych składowych pikselu R, G, B jest dzielona przez sumę dla wszystkich składowych. Dla każdej analizowanej klatki wyświetlany jest prostokąt, który reprezentuje sumę pikseli dla poszczególnych kolorów. Przykład działania programu zaprezentowano na filmie 1. Proszę zwrócić uwagę, na jakość wykrycia koloru oraz zaprezentowany kolor w trakcie zmiany ułożenia planszy z kolorem. Proszę się zastanowić jakie czynniki mogą mieć wpływ na działanie systemu. Proszę uwzględnić, oświetlenie, odległość, kąt względem kamery i oświetlenia.
Listing 3. Program do wykrywania koloru.
import cv2 labels = ('Blue', 'Green', 'Red') vid = cv2.VideoCapture(0) while(True): ret, frame = vid.read() b,g,r = cv2.split(frame); print(b.sum(), g.sum(), r.sum()) suma = b.sum()+g.sum()+r.sum() bsuma = (b.sum()*100) gsuma = (g.sum()*100) rsuma = (r.sum()*100) bsuma = (bsuma/suma) gsuma = (gsuma/suma) rsuma = (rsuma/suma) frame = cv2.rectangle(frame, (5,100), (205,100), (0, 0, 0), 1) frame = cv2.rectangle(frame, (5,100), (55,(100-int(bsuma))), (255, 0, 0), -1) frame = cv2.rectangle(frame, (105,100), (155,(100-int(gsuma))), (0, 255, 0), -1) frame = cv2.rectangle(frame, (205,100), (255,(100-int(rsuma))), (0, 0, 255), -1) cv2.imshow('frame', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break vid.release() cv2.destroyAllWindows()
Film 1. Przykład działania systemu do detekcji kolorów.
Przykładem systemu, który w sposób automatyczny wykrywa użytkownika przed komputerem może być zastosowanie detekcji twarzy. Oprócz wykrycia i wskazania wykrytej twarzy na obrazie, program wzbogacono o informację o czasie wykrycia lub braku wykrycia użytkownika. Po prostej modyfikacji program, może pełnić rolę „liczenia” czasu uwagi użytkownika. Każde odchylenie głowy, może oznaczać mniejszą uwagę użytkownika. Na listingu 4 zaprezentowano program do detekcji użytkownika przed ekranem komputera. Do wykrycia twarzy zastosowano klasyfikator Haara’a. Natomiast najważniejszym elementem programu jest warunek wypisania na ekranie godziny oraz informacji o braku lub pojawieniu się użytkownika. Przykład działania programu zaprezentowano na filmie 2.
Listing 4. Program do detekcji użytkownika.
import cv2 from datetime import datetime vid = cv2.VideoCapture(0,cv2.CAP_DSHOW) font = cv2.FONT_HERSHEY_SIMPLEX face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') while(True): ret, frame = vid.read() gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.13, 20) for (x,y,w,h) in faces: cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2) roi_gray = gray[y:y+h, x:x+w] roi_color = frame[y:y+h, x:x+w] if not any(map(len, faces)): text = 'Brak uzytkownika, '+datetime.now().strftime("%H:%M:%S") cv2.putText(frame,text,(30,30), font, 0.6, (0, 0, 255), 1, cv2.LINE_AA) else: text = 'Uzytkownik wykryty, '+datetime.now().strftime("%H:%M:%S") cv2.putText(frame,text,(30,30), font, 0.7, (0, 255, 0), 1, cv2.LINE_AA) cv2.imshow('frame', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break vid.release() cv2.destroyAllWindows()
Film 2. Przykład działania systemu do detekcji użytkownika.
Ważnym elementem systemu, może być wykrycie pewnych punktów charakterystycznych. W przykładzie posłużono się detekcją punktów na obrazie wideo. Proszę zwrócić uwagę na płynność detekcji punktów charakterystycznych oraz skuteczność dopasowania punktów. W szczególności istotny jest sposób działania wykrycia/dopasowania punktów w przypadku występowania obiektu oraz wtedy, gdy obiekt nie występuje. Program do detekcji punktów kluczowych dla płyty czołowej multimetru zaprezentowano na listingu 5.
Listing 5. Program do detekcji punktów charakterystycznych.
import cv2 vid = cv2.VideoCapture(0,cv2.CAP_DSHOW) maxH = 100 img2 = cv2.imread('multi2.jpg') scale = 0.2 width = int(img2.shape[1] * scale) height = int(img2.shape[0] * scale) dim = (width, height) img2 = cv2.resize(img2, dim, interpolation = cv2.INTER_AREA) while(True): ret, frame = vid.read() orb = cv2.ORB_create() kp1, des1 = orb.detectAndCompute(frame,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(frame,kp1,img2,kp2,matches[:5] ,None, flags=2) cv2.imshow('frame', img3) if cv2.waitKey(1) & 0xFF == ord('q'): break vid.release() cv2.destroyAllWindows()
Film 3. Przykład wykrycia punktów charakterystycznych.
Na początku działania programu, wczytywany jest obraz prezentujący multimetr. Następnie, dla każdej klatki filmu dokonywane jest porównanie punktów kluczowych dla zarejestrowanego przez kamerę obrazu oraz obrazu zawierającego multimetr. W zadaniu detekcji punktów zastosowano metodę ORB. W zadaniu dopasowania 10 najlepszych punktów zastosowano funkcję BFMatcher(). Proszę zwrócić uwagę, na brak poprawnych dopasowań dla początku zarejestrowanego obrazu oraz na końcu zarejestrowanego obrazu.