Sadržaj:

Prepoznavanje lica u stvarnom vremenu: projekt s kraja na kraj: 8 koraka (sa slikama)
Prepoznavanje lica u stvarnom vremenu: projekt s kraja na kraj: 8 koraka (sa slikama)

Video: Prepoznavanje lica u stvarnom vremenu: projekt s kraja na kraj: 8 koraka (sa slikama)

Video: Prepoznavanje lica u stvarnom vremenu: projekt s kraja na kraj: 8 koraka (sa slikama)
Video: Даниэл Уолперт: Для чего на самом деле нужен мозг 2024, Novembar
Anonim
Prepoznavanje lica u stvarnom vremenu: projekt s kraja na kraj
Prepoznavanje lica u stvarnom vremenu: projekt s kraja na kraj

Na mom zadnjem vodiču o istraživanju OpenCV -a naučili smo AUTOMATSKO VISION OBJEKTNO PRAĆENJE. Sada ćemo koristiti naš PiCam za prepoznavanje lica u stvarnom vremenu, kao što možete vidjeti u nastavku:

Image
Image

Ovaj projekat je urađen sa ovom fantastičnom "Open Source Computer Computer Vision Library", OpenCV. U ovom vodiču ćemo se fokusirati na Raspberry Pi (dakle, Raspbian kao OS) i Python, ali sam također testirao kod na mom Macu i također radi dobro. OpenCV je dizajniran za računarsku efikasnost i sa snažnim fokusom na aplikacije u realnom vremenu. Dakle, savršen je za prepoznavanje lica u stvarnom vremenu pomoću kamere.

Da bismo stvorili cjelovit projekt o prepoznavanju lica, moramo raditi na 3 vrlo različite faze:

  1. Prepoznavanje lica i prikupljanje podataka
  2. Obučite Prepoznavača
  3. Prepoznavanje lica

Blok dijagram u nastavku nastavlja te faze:

Image
Image

Korak 1: BoM - Predmet materijala

Glavni delovi:

  1. Raspberry Pi V3 - 32,00 US $
  2. 5 -megapikselni 1080p senzorski senzor OV5647 videokamera za mini kameru - 13,00 US $

Korak 2: Instaliranje paketa OpenCV 3

Instaliranje paketa OpenCV 3
Instaliranje paketa OpenCV 3

Koristim Raspberry Pi V3 ažuriran na posljednju verziju Raspbian -a (Stretch), pa je najbolji način za instaliranje OpenCV -a slijediti odličan vodič koji je razvio Adrian Rosebrock: Raspbian Stretch: Instalirajte OpenCV 3 + Python na svoj Raspberry Pi.

Pokušao sam nekoliko različitih vodiča za instaliranje OpenCV -a na svoj Pi. Adrianov vodič je najbolji. Savjetujem vam da učinite isto, slijedeći njegove smjernice korak po korak.

Nakon što završite Adrianov vodič, trebali biste imati otvoreno virtualno okruženje OpenCV za izvođenje naših eksperimenata na vašem Pi.

Idemo u naše virtualno okruženje i potvrdimo da je OpenCV 3 ispravno instaliran.

Adrian preporučuje pokretanje naredbe "izvor" svaki put kada otvorite novi terminal kako biste bili sigurni da su vaše sistemske varijable ispravno postavljene.

source ~/.profile

Zatim uđimo u naše virtualno okruženje:

workon cv

Ako vidite tekst (cv) ispred vašeg upita, onda ste u cv virtualnom okruženju:

(cv) pi@malina: ~ $Adrian skreće pažnju da je cv Python virtualno okruženje potpuno neovisno i izdvojeno od zadane verzije Pythona uključene u preuzimanje Raspbian Stretch -a. Dakle, svi Python paketi u globalnom direktoriju web-paketa neće biti dostupni cv virtualnom okruženju. Slično, svi Python paketi instalirani u web-paketima cv-a neće biti dostupni za globalnu instalaciju Pythona

Sada unesite u svoj Python interpreter:

python

i potvrdite da koristite 3.5 (ili noviju) verziju

Unutar tumača (pojavit će se ">>>"), uvezite biblioteku OpenCV:

import cv2

Ako se ne pojave poruke o grešci, OpenCV je ispravno instaliran NA VAŠEM PYTHON VIRTUALNOM OKRUŽENJU.

Također možete provjeriti instaliranu verziju OpenCV -a:

cv2._ verzija_

Trebalo bi se pojaviti 3.3.0 (ili superiornija verzija koja se može objaviti u budućnosti). Gornji Terminal PrintScreen prikazuje prethodne korake.

Korak 3: Testirajte kameru

Testiranje kamere
Testiranje kamere

Nakon što instalirate OpenCV u svoj RPi, hajde da testiramo da li je vaša kamera ispravna.

Pretpostavljam da već imate instaliran PiCam na svom Raspberry Pi -u.

Unesite donji Python kôd u svoj IDE:

uvoz numpy kao np

import cv2 cap = cv2. VideoCapture (0) cap.set (3, 640) # set Width cap.set (4, 480) # set Height while (True): ret, frame = cap.read () frame = cv2. flip (okvir, -1) # Okreni kameru okomito sivo = cv2.cvtBoja (okvir, cv2. COLOR_BGR2GRAY) cv2.imshow ('okvir', okvir) cv2.imshow ('sivo', sivo) k = cv2.waitKey (30) & 0xff if k == 27: # pritisnite 'ESC' da prekinete break cap.release () cv2.destroyAllWindows ()

Gornji kôd će snimiti video stream koji će generirati vaš PiCam, prikazujući oboje, u BGR boji i sivom načinu rada.

Imajte na umu da sam kameru rotirao okomito zbog načina na koji je sastavljena. Ako to nije vaš slučaj, komentirajte ili izbrišite "flip" naredbenu liniju.

Alternativno možete preuzeti kod sa mog GitHub -a: simpleCamTest.py

Da biste izvršili, unesite naredbu:

python simpleCamTest.py

Da biste dovršili program, morate pritisnuti taster [ESC] na tastaturi.

Kliknite mišem na video prozor, prije nego pritisnete [ESC]

Gornja slika prikazuje rezultat.

Neki proizvođači otkrili su probleme prilikom pokušaja otvaranja kamere (poruke o grešci "Assertion failed"). To bi se moglo dogoditi ako kamera nije bila omogućena tijekom instalacije OpenCv -a pa se upravljački programi nisu pravilno instalirali. Da biste ispravili, koristite naredbu:

sudo modprobe bcm2835-v4l2

Takođe možete dodati bcm2835-v4l2 u zadnji red datoteke /etc /modules, tako da se upravljački program učitava pri pokretanju.

Da biste saznali više o OpenCV-u, možete slijediti vodič: učitavanje -video-python-opencv-tutorial

Korak 4: Prepoznavanje lica

Prepoznavanje lica
Prepoznavanje lica
Prepoznavanje lica
Prepoznavanje lica

Najosnovniji zadatak prepoznavanja lica je, naravno, "prepoznavanje lica". Prije svega morate "snimiti" lice (faza 1) kako biste ga prepoznali u usporedbi s novim licem snimljenim u budućnosti (faza 3).

Najčešći način otkrivanja lica (ili bilo kojeg objekta) je upotreba "Haar Cascade klasifikatora"

Otkrivanje objekata pomoću Haar-ovih kaskadnih klasifikatora je efikasna metoda otkrivanja objekata koju su predložili Paul Viola i Michael Jones u svom radu "Brzo otkrivanje objekata pomoću pojačane kaskade jednostavnih značajki" iz 2001. To je pristup zasnovan na strojnom učenju gdje kaskadna funkcija je istrenirana s puno pozitivnih i negativnih slika. Zatim se koristi za otkrivanje objekata na drugim slikama.

Ovdje ćemo raditi s otkrivanjem lica. U početku, algoritmu je potrebno mnogo pozitivnih slika (slika lica) i negativnih slika (slika bez lica) za obuku klasifikatora. Zatim moramo iz njega izdvojiti značajke. Dobra vijest je da OpenCV dolazi s trenerom i detektorom. Ako želite osposobiti vlastiti klasifikator za bilo koji objekt, poput automobila, aviona itd., Možete ga koristiti za izradu istog. Njegovi potpuni detalji dati su ovdje: Cascade Classifier Training.

Ako ne želite stvoriti vlastiti klasifikator, OpenCV već sadrži mnoge unaprijed obučene klasifikatore za lice, oči, osmijeh itd. Te se XML datoteke mogu preuzeti iz direktorija haarcascades.

Dosta je bilo teorije, napravimo detektor lica s OpenCV -om!

Preuzmite datoteku: faceDetection.py sa mog GitHub -a.

uvoz numpy kao np

import cv2 faceCascade = cv2. CascadeClassifier ('Cascades/haarcascade_frontalface_default.xml') cap = cv2. VideoCapture (0) cap.set (3, 640) # set Width cap.set (4, 480) # set Height while True: ret, img = cap.read () img = cv2.flip (img, -1) siva = cv2.cvtBoja (img, cv2. COLOR_BGR2GRAY) lica = faceCascade.detectMultiScale (siva, scaleFactor = 1.2, minNeighbors = 5, minSize = (20, 20)) za (x, y, w, h) u licima: cv2.pravokutnik (img, (x, y), (x+w, y+h), (255, 0, 0), 2) roi_gray = siva [y: y+h, x: x+w] roi_color = img [y: y+h, x: x+w] cv2.imshow ('video', img) k = cv2.waitKey (30) & 0xff if k == 27: # pritisnite 'ESC' da prekinete break cap.release () cv2.destroyAllWindows ()

Vjerovali ili ne, gornjih nekoliko redaka koda je sve što vam je potrebno za otkrivanje lica pomoću Pythona i OpenCV -a.

Kada uporedite sa posljednjim kodom koji je korišten za testiranje kamere, shvatit ćete da joj je dodano nekoliko dijelova. Obratite pažnju na donju liniju:

faceCascade = cv2. CascadeClassifier ('Cascades/haarcascade_frontalface_default.xml')

Ovo je linija koja učitava "klasifikator" (koji mora biti u direktoriju pod nazivom "Cascades/", ispod direktorija vašeg projekta).

Zatim ćemo postaviti kameru i unutar petlje učitati naš ulazni video u načinu rada u sivim tonovima (isto što smo vidjeli i prije).

Sada moramo pozvati našu funkciju klasifikatora, prosljeđujući joj neke vrlo važne parametre, kao što je faktor razmjera, broj susjeda i minimalna veličina otkrivenog lica.

lica = faceCascade.detectMultiScale (siva, scaleFactor = 1,2, minSusjedi = 5, minSize = (20, 20))

Gdje,

  • siva je ulazna slika u sivim tonovima.
  • scaleFactor je parametar koji određuje koliko se veličina slike smanjuje na svakoj skali slike. Koristi se za stvaranje piramide razmjera.
  • minNeighbors je parametar koji određuje koliko susjeda svaki pravokutnik kandidata treba imati kako bi ga zadržao. Veći broj daje manje lažno pozitivnih rezultata.
  • minSize je minimalna veličina pravokutnika koja se smatra licem.

Ova funkcija će otkriti lica na slici. Zatim moramo "označiti" lica na slici, koristeći, na primjer, plavi pravokutnik. To se radi s ovim dijelom koda:

za (x, y, w, h) u licima:

cv2.rectangle (img, (x, y), (x+w, y+h), (255, 0, 0), 2) roi_gray = siva [y: y+h, x: x+w] roi_color = img [y: y+h, x: x+w]

Ako se pronađu lica, on vraća pozicije otkrivenih lica kao pravokutnik s lijevim gornjim kutom (x, y) i ima "w" kao svoju širinu i "h" kao svoju visinu ==> (x, y, w, h). Molimo pogledajte gornju sliku.

Nakon što dobijemo ove lokacije, možemo stvoriti "ROI" (nacrtani pravokutnik) za lice i prikazati rezultat s funkcijom imshow ().

Pokrenite gornji python Script na svom python okruženju, koristeći Rpi terminal:

python faceDetection.py

Rezultat:

Image
Image

Također možete uključiti klasifikatore za "otkrivanje očiju" ili čak "otkrivanje osmijeha". U tim ćete slučajevima uključiti funkciju klasifikatora i iscrtavanje pravokutnika unutar petlje lica, jer nema smisla otkriti oko ili osmijeh izvan lica.

Imajte na umu da će na Pi -u imati nekoliko klasifikatora u istom kodu usporiti obradu, nakon što ova metoda detekcije (HaarCascades) koristi veliku količinu računske snage. Na radnoj površini lakše ga je pokrenuti.

Na mom GitHubu pronaći ćete i druge primjere:

faceEyeDetection.py

faceSmileDetection.py

faceSmileEyeDetection.py

A na gornjoj slici možete vidjeti rezultat.

Također možete slijediti donji vodič za bolje razumijevanje prepoznavanja lica:

Haar Cascade Object Detection Object Face & Eye OpenCV Python Vodič

Korak 5: Prikupljanje podataka

Prikupljanje podataka
Prikupljanje podataka
Prikupljanje podataka
Prikupljanje podataka

Prije svega, moram zahvaliti Ramizu Raji za njegov sjajan rad na prepoznavanju lica na fotografijama:

PREPOZNAVANJE LICA KORIŠĆENJEM OPENCV -a I PITONA: VODIČ ZA POČETNIKE

i također Anirban Kar, koji je razvio vrlo opsežan vodič pomoću videa:

PREPOZNAVANJE LICA - 3 dijela

Zaista vam preporučujem da pogledate oba vodiča.

Rekavši to, započnimo prvu fazu našeg projekta. Ono što ćemo ovdje učiniti počinje od zadnjeg koraka (prepoznavanje lica), jednostavno ćemo stvoriti skup podataka u koji ćemo za svaki ID pohraniti grupu fotografija u sivoj boji s dijelom koji je korišten za otkrivanje lica.

Prvo stvorite direktorij u kojem razvijate svoj projekt, na primjer FacialRecognitionProject:

mkdir FacialRecognitionProject

U ovom direktoriju, pored 3 python skripte koje ćemo kreirati za naš projekat, moramo imati sačuvan Klasifikator lica. Možete ga preuzeti sa mog GitHub -a: haarcascade_frontalface_default.xml

Zatim stvorite poddirektorij u koji ćemo pohraniti uzorke lica i nazvati ga "skup podataka":

mkdir skup podataka

I preuzmite kod sa mog GitHub -a: 01_face_dataset.py

import cv2

import os cam = cv2. VideoCapture (0) cam.set (3, 640) # postavi širinu videa cam.set (4, 480) # postavi visinu videa face_detector = cv2. CascadeClassifier ('haarcascade_frontalface_default.xml') # Za svaku osobu, unesite jedan numerički identifikator lica face_id = input ('\ n unesite korisnički ID kraj pritisnite ==>') print ("\ n [INFO] Pokretanje snimanja lica. Pogledajte kameru i sačekajte …") # Pokretanje pojedinačnog broja uzoraka = 0 while (Tačno): ret, img = cam.read () img = cv2.flip (img, -1) # flip video slika okomito siva = cv2.cvtColor (img, cv2. COLOR_BGR2GRAY) lica = face_detector.detectMultiScale (siva, 1,3, 5) za (x, y, w, h) na licima: cv2.pravokutnik (img, (x, y), (x+w, y+h), (255, 0, 0), 2) count + = 1 # Spremite snimljenu sliku u mapu skupova podataka cv2.imwrite ("skup podataka/korisnik." + str (face_id) + '.' + str (broj) + ".jpg", sivo [y: y + h, x: x+w]) cv2.imshow ('image', img) k = cv2.waitKey (100) & 0xff # Pritisnite 'ESC' za izlaz iz videa ako je k == 27: break elif count> = 30: # Uzmite uzorak od 30 lica i zaustavite video pauzu # Učinite ab it of cleanup print ("\ n [INFO] Izlazak iz programa i stvari o čišćenju") cam.release () cv2.destroyAllWindows ()

Kôd je vrlo sličan kodu koji smo vidjeli za detekciju lica. Ono što smo dodali je "ulazna naredba" za hvatanje korisničkog ID -a, to bi trebao biti cijeli broj (1, 2, 3, itd.)

face_id = input ('\ n unesite korisnički ID kraj pritisnite ==>')

I za svaki od snimljenih kadrova, trebali bismo ga spremiti kao datoteku u direktoriju "nabora podataka":

cv2.imwrite ("skup podataka/korisnik." + str (face_id) + '.' + str (broj) + ".jpg", sivo [y: y + h, x: x + w])

Imajte na umu da za spremanje gornje datoteke morate uvesti biblioteku "os". Naziv svake datoteke slijedi strukturu:

User.face_id.count.jpg

Na primjer, za korisnika s face_id = 1, četvrta ogledna datoteka u skupu podataka/ direktoriju bit će nešto poput:

User.1.4.jpg

kao što je prikazano na gornjoj fotografiji sa mog Pi -a. U svom kodu hvatam 30 uzoraka sa svakog ID -a. Možete ga promijeniti na zadnjem "elifu". Broj uzoraka se koristi za prekid petlje u kojoj se uzimaju uzorci lica.

Pokrenite Python skriptu i snimite nekoliko ID -ova. Morate pokrenuti skriptu svaki put kada želite objediniti novog korisnika (ili promijeniti fotografije za već postojećeg).

Korak 6: Trener

Trener
Trener

U ovoj drugoj fazi moramo uzeti sve korisničke podatke iz našeg skupa podataka i "trenirati" OpenCV Recognizer. To radi direktno određena funkcija OpenCV. Rezultat će biti.yml datoteka koja će biti spremljena u direktorij "trainer/".

Dakle, počnimo stvarati poddirektorij u koji ćemo pohraniti obučene podatke:

mkdir trener

Preuzmite sa mog GitHub -a drugu python skriptu: 02_face_training.py

import cv2

import numpy kao np iz PIL -a import Image import os # Putanja za bazu slika slike lica = 'skup podataka' prepoznavač = cv2.face. LBPHFaceRecognizer_create () detektor = cv2. CascadeClassifier ("haarcascade_frontalface_default.xml"); # funkcija za dobivanje slika i podataka o oznakama def getImagesAndLabels (path): imagePaths = [os.path.join (path, f) for f in os.listdir (path)] faceSamples = ids = za imagePath u imagePaths: PIL_img = Image.open (imagePath).convert ('L') # pretvori u sivu skalu img_numpy = np.array (PIL_img, 'uint8') id = int (os.path.split (imagePath) [-1]. split (".") [1]) lica = detektor.detectMultiScale (img_numpy) za (x, y, w, h) u licima: faceSamples.append (img_numpy [y: y+h, x: x+w]) ids.append (id) return faceSamples, ids print ("\ n [INFO] Obuka lica. Trajat će nekoliko sekundi. Pričekajte …") lica, ids = getImagesAndLabels (path) prepoznavač.train (lica, np.array (ids)) # Sačuvajte model u trainer/trainer.yml Reconizer.write ('trainer/trainer.yml') # prepoznavač.save () je radilo na Mac -u, ali ne i na Pi # Ispišite broj lica obučenih i završite ispis programa ("\ n [INFO] {0} lica obučena. Izlazak iz programa".format (len (np.unique (ids))))

Potvrdite da li je na vašem Rpi instalirana PIL biblioteka. Ako ne, pokrenite donju naredbu u terminalu:

pip install jastuk

Kao prepoznavač koristit ćemo LBPH (LISTALNE BINARNE UZORKE HISTOGRAMA) Prepoznavač lica, uključen u OpenCV paket. To radimo u sljedećoj liniji:

prepoznavač = cv2.face. LBPHFaceRecognizer_create ()

Funkcija "getImagesAndLabels (path)", snimit će sve fotografije u direktoriju: "set/", vraćajući 2 niza: "Ids" i "lica". S tim nizovima kao ulazom, "obučit ćemo našeg prepoznavača":

prepoznavač.train (lica, identifikatori)

Kao rezultat toga, datoteka pod nazivom "trainer.yml" bit će spremljena u direktorij trenera koji smo prethodno stvorili.

To je to! Uključio sam posljednju izjavu za štampanje u kojoj sam prikazao potvrdu, broj lica korisnika koje smo obučili.

Svaki put kada izvodite fazu 1, fazu 2 također morate pokrenuti

Korak 7: Prepoznavač

Prepoznavač
Prepoznavač
Prepoznavač
Prepoznavač

Sada smo došli do završne faze našeg projekta. Ovdje ćemo snimiti svježe lice na našoj kameri i ako je ovoj osobi prije snimljeno i obučeno lice, naš prepoznavač će napraviti "predviđanje" vraćajući svoj ID i indeks, pokazujući koliko je prepoznatljiv siguran u ovu utakmicu.

Hajde da preuzmemo python skriptu treće faze sa mog GitHub -a: 03_face_recognition.py.

import cv2

uvoz numpy kao np uvoz os prepoznavač = cv2.face. LBPHFaceRecognizer_create () prepoznavač.read ('trener/trener.yml') cascadePath = "haarcascade_frontalface_default.xml" faceCascade = cv2. CascadeClassifier (cascadeClassifier); font = cv2. FONT_HERSHEY_SIMPLEX #inicijski brojač id id = 0 # imena u vezi s id -ovima: primjer ==> Marcelo: id = 1, itd names = ['None', 'Marcelo', 'Paula', 'Ilza', 'Z ',' W '] # Inicirajte i pokrenite kameru za snimanje video zapisa u stvarnom vremenu = cv2. VideoCapture (0) cam.set (3, 640) # postavite video widht cam.set (4, 480) # postavite visinu videa # Definirajte minimalnu veličinu prozora biti prepoznato kao lice minW = 0,1*cam.get (3) minH = 0,1*cam.get (4) dok je True: ret, img = cam.read () img = cv2.flip (img, -1) # Okrenite okomito sivo = cv2.cvtColor (img, cv2. COLOR_BGR2GRAY) lica = faceCascade.detectMultiScale (sivo, scaleFactor = 1,2, minNeighbors = 5, minSize = (int (minW), int (minH)),) za (x, y, w, h) u licima: cv2.pravokutnik (img, (x, y), (x+w, y+h), (0, 255, 0), 2) id, pouzdanost = prepoznavač.predvidi (sivo [y: y+h, x: x+w]) # Provjerite je li povjerenje manje od njih 100 ==> "0" savršeno odgovara ako (povjerenje <100): id = names [id] trust = "{0}% ".format (okrugli (100 - povjerenje)) else: id =" nepoznato "povjerenje =" {0}%". format (okrugli (100 - konf. idence)) cv2.putText (img, str (id), (x+5, y-5), font, 1, (255, 255, 255), 2) cv2.putText (img, str (povjerenje), (x+5, y+h-5), font, 1, (255, 255, 0), 1) cv2.imshow ('kamera', img) k = cv2.waitKey (10) & 0xff # Pritisnite 'ESC' za izlaz iz videa ako je k == 27: break # Učinite malo čišćenja ispisa ("\ n [INFO] Izlazak iz programa i stvari o čišćenju") cam.release () cv2.destroyAllWindows ()

Ovdje dodajemo novi niz, pa ćemo prikazati "imena", umjesto numeriranih ID -ova:

names = ['None', 'Marcelo', 'Paula', 'Ilza', 'Z', 'W']

Tako, na primjer: Marcelo će korisnika s id = 1; Paula: id = 2 itd.

Zatim ćemo otkriti lice, isto što smo radili i ranije sa klasifikatorom haasCascade. Imajući otkriveno lice možemo nazvati najvažniju funkciju u gornjem kodu:

id, pouzdanje = prepoznavač.predvidi (sivi dio lica)

Prepoznavač.predict () će uzeti kao parametar snimljeni dio lica za analizu i vratit će svog vjerovatnog vlasnika, navodeći njegov ID i koliko je prepoznatljivost pouzdana u odnosu na ovo podudaranje.

Imajte na umu da će se indeks povjerenja vratiti na "nulu" ako se savršeno podudara

I na kraju, ako prepoznavač može predvidjeti lice, stavljamo tekst preko slike s vjerojatnim ID -om i kolikom je "vjerovatnoćom" u % da je podudaranje točno ("vjerovatnoća" = 100 - indeks pouzdanosti). Ako nije, na lice se stavlja oznaka "nepoznato".

Ispod gifa sa rezultatom:

Image
Image

Na gornjoj slici prikazujem neke testove urađene sa ovim projektom, gdje sam također koristio fotografije da provjerim radi li prepoznavač.

Korak 8: Zaključak

Zaključak
Zaključak

Kao i uvijek, nadam se da će ovaj projekt pomoći drugima da pronađu svoj put u uzbudljivi svijet elektronike!

Za detalje i konačni kod posjetite moje skladište GitHub-a: OpenCV-Face-Recognition

Za više projekata posjetite moj blog: MJRoBot.org

Ispod pogleda na budući vodič, gdje ćemo istražiti "automatsko praćenje lica i druge metode za otkrivanje lica":

Image
Image

Saludos sa juga svijeta!

Vidimo se u mom sljedećem uputstvu!

Hvala ti, Marcelo

Preporučuje se: