Kazalo:

Prepoznavanje obrazov v realnem času: projekt od konca do konca: 8 korakov (s slikami)
Prepoznavanje obrazov v realnem času: projekt od konca do konca: 8 korakov (s slikami)

Video: Prepoznavanje obrazov v realnem času: projekt od konca do konca: 8 korakov (s slikami)

Video: Prepoznavanje obrazov v realnem času: projekt od konca do konca: 8 korakov (s slikami)
Video: Дэниел Шмахтенбергер: Уничтожат ли нас технологии? 2024, Julij
Anonim
Prepoznavanje obrazov v realnem času: projekt od konca do konca
Prepoznavanje obrazov v realnem času: projekt od konca do konca

Na moji zadnji vadnici, ki je raziskovala OpenCV, smo se naučili AUTOMATIC VISION OBJECT TRACKING. Zdaj bomo uporabili naš PiCam za prepoznavanje obrazov v realnem času, kot lahko vidite spodaj:

Slika
Slika

Ta projekt je bil narejen s to fantastično "odprtokodno knjižnico računalniškega vida", OpenCV. V tej vadnici se bomo osredotočili na Raspberry Pi (torej Raspbian kot OS) in Python, vendar sem kodo preizkusil tudi na svojem Macu in deluje tudi v redu. OpenCV je bil zasnovan za računalniško učinkovitost in se močno osredotoča na aplikacije v realnem času. Torej je kot nalašč za prepoznavanje obrazov v realnem času s kamero.

Če želimo ustvariti celoten projekt prepoznavanja obrazov, moramo delati na treh zelo različnih fazah:

  1. Odkrivanje obrazov in zbiranje podatkov
  2. Trenirajte prepoznavalca
  3. Prepoznavanje obrazov

Spodnji blokovni diagram nadaljuje te faze:

Slika
Slika

1. korak: BoM - materialni material

Glavni deli:

  1. Raspberry Pi V3 - 32,00 USD
  2. 5 -megapikselni senzor 1080p senzor OV5647 videokamera z mini kamero - 13,00 USD

2. korak: Namestitev paketa OpenCV 3

Namestitev paketa OpenCV 3
Namestitev paketa OpenCV 3

Uporabljam Raspberry Pi V3, posodobljen na zadnjo različico Raspbian (Stretch), zato je najboljši način, da namestite OpenCV, slediti odlični vadnici, ki jo je razvil Adrian Rosebrock: Raspbian Stretch: Namestite OpenCV 3 + Python na svoj Raspberry Pi.

Poskusil sem več različnih vodnikov za namestitev OpenCV na moj Pi. Adrianova vadnica je najboljša. Svetujem vam, da storite enako, po korakih po njegovih smernicah.

Ko končate Adrianovo vadnico, morate imeti na voljo virtualno okolje OpenCV za izvajanje naših poskusov na vašem Pi.

Pojdimo v naše virtualno okolje in potrdimo, da je OpenCV 3 pravilno nameščen.

Adrian priporoča, da vsakič, ko odprete nov terminal, zaženete ukaz "source", da zagotovite, da so sistemske spremenljivke pravilno nastavljene.

source ~/.profile

Nato vstopimo v naše virtualno okolje:

workon cv

Če pred pozivom vidite besedilo (cv), ste v virtualnem okolju cv:

(cv) pi@malina: ~ $Adrian opozarja, da je virtualno okolje cv Python popolnoma neodvisno in zajeto od privzete različice Pythona, vključene v prenos Raspbian Stretch. Torej, vsi paketi Python v globalnem imeniku paketov spletnih mest ne bodo na voljo virtualnemu okolju cv. Podobno vsi paketi Python, nameščeni v paketih spletnih mest cv, ne bodo na voljo za globalno namestitev Pythona

Zdaj vnesite svoj tolmač Python:

python

in potrdite, da uporabljate različico 3.5 (ali novejšo)

Znotraj tolmača (prikazalo se bo ">>>") uvozite knjižnico OpenCV:

uvoz cv2

Če se ne prikažejo sporočila o napakah, je OpenCV pravilno nameščen V VAŠEM VIRTUALNEM OKOLJU PYTHON.

Preverite lahko tudi nameščeno različico OpenCV:

cv2._ različica_

Pojaviti se mora 3.3.0 (ali nadrejena različica, ki bo v prihodnosti na voljo). Zgornji zaslon Terminal PrintScreen prikazuje prejšnje korake.

3. korak: Preizkusite kamero

Testiranje fotoaparata
Testiranje fotoaparata

Ko namestite OpenCV v RPi, poskusimo preveriti, ali kamera deluje pravilno.

Predvidevam, da imate PiCam že nameščen na vašem Raspberry Pi.

Vnesite spodnjo kodo Python v svoj IDE:

uvoz numpy kot 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 (frame, -1) # Flip camera vertikalno siva = cv2.cvtColor (okvir, cv2. COLOR_BGR2GRAY) cv2.imshow ('okvir', okvir) cv2.imshow ('siva', siva) k = cv2.waitKey (30) & 0xff če je k == 27: # pritisnite 'ESC', da zaprete prekinitev cap.release () cv2.destroyAllWindows ()

Zgornja koda bo zajela video tok, ki ga bo ustvaril vaš PiCam, in prikazal oboje v barvnem načinu BGR in načinu sive barve.

Upoštevajte, da sem fotoaparat obrnil navpično zaradi načina sestavljanja. Če ni vaš primer, komentirajte ali izbrišite ukazno vrstico "flip".

Kodo lahko prenesete tudi z mojega GitHub -a: simpleCamTest.py

Za izvedbo vnesite ukaz:

python simpleCamTest.py

Za dokončanje programa pritisnite tipko [ESC] na tipkovnici.

Preden pritisnete [ESC], kliknite miško na video oknu

Zgornja slika prikazuje rezultat.

Nekateri izdelovalci so odkrili težave pri poskusu odpiranja kamere (sporočila o napaki »Assertion failed«). To bi se lahko zgodilo, če kamera med namestitvijo OpenCv ni bila omogočena, zato se gonilniki fotoaparatov niso pravilno namestili. Če želite popraviti, uporabite ukaz:

sudo modprobe bcm2835-v4l2

Bcm2835-v4l2 lahko dodate tudi v zadnjo vrstico datoteke /etc /modules, da se gonilnik naloži ob zagonu.

Če želite izvedeti več o OpenCV, sledite vadnici: loading -video-python-opencv-tutorial

4. korak: Zaznavanje obrazov

Zaznavanje obrazov
Zaznavanje obrazov
Zaznavanje obrazov
Zaznavanje obrazov

Najosnovnejša naloga pri prepoznavanju obrazov je seveda "zaznavanje obrazov". Pred vsem morate "ujeti" obraz (faza 1), da ga prepoznate v primerjavi z novim obrazom, posnetim v prihodnosti (faza 3).

Najpogostejši način odkrivanja obraza (ali katerega koli predmeta) je "klasifikator Haar Cascade"

Odkrivanje objektov z uporabo Haarjevih kaskadnih klasifikatorjev, ki temeljijo na lastnostih, je učinkovita metoda odkrivanja objektov, ki sta jo predlagala Paul Viola in Michael Jones v svojem prispevku "Hitro odkrivanje predmetov z okrepljeno kaskado enostavnih funkcij" leta 2001. Gre za pristop, ki temelji na strojnem učenju, kjer kaskadna funkcija je izučena iz številnih pozitivnih in negativnih slik. Nato se uporablja za zaznavanje predmetov na drugih slikah.

Tu bomo delali z zaznavanjem obrazov. Sprva algoritem potrebuje veliko pozitivnih slik (slik obrazov) in negativnih slik (slik brez obrazov) za usposabljanje klasifikatorja. Nato moramo iz njega izvleči funkcije. Dobra novica je, da je OpenCV opremljen s trenerjem in detektorjem. Če želite usposobiti svoj klasifikator za kateri koli predmet, kot so avto, letala itd., Ga lahko ustvarite z OpenCV. Vse njegove podrobnosti so navedene tukaj: Cascade Classifier Training.

Če ne želite ustvariti svojega klasifikatorja, OpenCV že vsebuje veliko vnaprej usposobljenih klasifikatorjev za obraz, oči, nasmeh itd. Te datoteke XML lahko prenesete iz imenika haarcascades.

Dovolj teorije, ustvarimo detektor obrazov z OpenCV!

Prenesite datoteko: faceDetection.py z mojega GitHub -a.

uvoz numpy kot 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.cvtColor (img, cv2. COLOR_BGR2GRAY) obrazov = faceCascade.detectMultiScale (siva, scaleFactor = 1,2, minNeighbors = 5, minSize = (min 20, 20)) za (x, y, w, h) v obrazih: cv2.pravokotnik (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 če je k == 27: # pritisnite 'ESC', da zaprete prekinitev cap.release () cv2.destroyAllWindows ()

Verjemite ali ne, zgoraj navedenih vrstic kode je vse, kar potrebujete za zaznavanje obraza z uporabo Pythona in OpenCV.

Ko primerjate z zadnjo kodo, uporabljeno za testiranje kamere, boste ugotovili, da ji je bilo dodanih le nekaj delov. Upoštevajte spodnjo vrstico:

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

To je vrstica, ki naloži "klasifikator" (ki mora biti v imeniku z imenom "Cascades/" v imeniku vašega projekta).

Nato bomo nastavili kamero in znotraj zanke naložili vhodni video v načinu sivine (enako smo videli prej).

Zdaj moramo poklicati funkcijo klasifikatorja in ji posredovati nekaj zelo pomembnih parametrov, kot so faktor lestvice, število sosedov in najmanjša velikost zaznanega obraza.

obrazov = faceCascade.detectMultiScale (siva, scaleFactor = 1,2, minSosedje = 5, minSize = (20, 20))

Kje,

  • siva je vhodna slika v sivinah.
  • scaleFactor je parameter, ki določa, koliko se velikost slike zmanjša na vsaki lestvici slike. Uporablja se za ustvarjanje piramide merila.
  • minNeighbors je parameter, ki določa, koliko sosedov pravokotnika mora imeti sosede, da ga obdrži. Večje število daje manj lažno pozitivnih rezultatov.
  • minSize je najmanjša velikost pravokotnika, ki velja za obraz.

Funkcija zazna obraze na sliki. Nato moramo "označiti" obraze na sliki, na primer z uporabo modrega pravokotnika. To se naredi s tem delom kode:

za (x, y, w, h) v obrazih:

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]

Če najdemo obraze, vrne položaje zaznanih obrazov kot pravokotnik z levim gornjim kotom (x, y) in ima "w" kot širino in "h" kot višino ==> (x, y, w, h). Oglejte si zgornjo sliko.

Ko dobimo te lokacije, lahko za obraz ustvarimo "ROI" (narisan pravokotnik) in rezultat predstavimo s funkcijo imshow ().

Zgornji python Script zaženite v svojem okolju python z uporabo terminala Rpi:

python faceDetection.py

Rezultat:

Slika
Slika

Vključite lahko tudi klasifikatorje za "zaznavanje oči" ali celo "zaznavanje nasmeha". V teh primerih boste vključili funkcijo klasifikatorja in risbo pravokotnika znotraj obrazne zanke, ker ne bi bilo smiselno zaznati očesa ali nasmeha zunaj obraza.

Upoštevajte, da bo pri Pi -ju več klasifikatorjev z isto kodo upočasnilo obdelavo, potem ko ta metoda odkrivanja (HaarCascades) uporabi veliko količino računalniške moči. Na namizju ga je lažje zagnati.

Na mojem GitHubu boste našli še druge primere:

faceEyeDetection.py

faceSmileDetection.py

faceSmileEyeDetection.py

In na zgornji sliki lahko vidite rezultat.

Za boljše razumevanje zaznavanja obrazov lahko sledite tudi spodnji vadnici:

Haar Cascade Object Detection Face & Eye OpenCV Python Vadnica

5. korak: Zbiranje podatkov

Zbiranje podatkov
Zbiranje podatkov
Zbiranje podatkov
Zbiranje podatkov

Najprej se moram zahvaliti Ramizu Raji za njegovo odlično delo pri prepoznavanju obrazov na fotografijah:

PREPOZNAVANJE LICA Z UPORABO OPENCV IN PYTHON: VODIČ ZA ZAČETNIKA

in tudi Anirban Kar, ki je z videoposnetkom razvil zelo obsežno vadnico:

PREPOZNAVANJE LICA - 3 deli

Res priporočam, da si ogledate obe vadnici.

Ob tem začnimo prvo fazo našega projekta. Kar bomo naredili tukaj, se začne od zadnjega koraka (zaznavanje obrazov), preprosto bomo ustvarili nabor podatkov, kjer bomo za vsak ID shranili skupino fotografij v sivi barvi z delom, ki je bil uporabljen za zaznavanje obrazov.

Najprej ustvarite imenik, v katerem razvijate svoj projekt, na primer FacialRecognitionProject:

mkdir FacialRecognitionProject

V tem imeniku moramo poleg treh skriptov python, ki jih bomo ustvarili za naš projekt, vanj shraniti tudi klasifikator obraza. Prenesete ga lahko z mojega GitHub -a: haarcascade_frontalface_default.xml

Nato ustvarite podimenik, v katerega bomo shranili vzorce obraza in ga poimenovali "nabor podatkov":

mkdir nabor podatkov

In kodo prenesite z mojega GitHub -a: 01_face_dataset.py

uvoz cv2

import os cam = cv2. VideoCapture (0) cam.set (3, 640) # nastavi video širino cam.set (4, 480) # nastavi višino videa face_detector = cv2. CascadeClassifier ('haarcascade_frontalface_default.xml') # Za vsako osebo, vnesite en številski id obraza face_id = input ('\ n vnesite ID uporabnika konec pritisnite ==>') print ("\ n [INFO] Začetek zajemanja obrazov. Poglejte kamero in počakajte …") # Inicializirajte posamezno število vzorcev = 0 while (True): ret, img = cam.read () img = cv2.flip (img, -1) # flip video slika navpično siva = cv2.cvtColor (img, cv2. COLOR_BGR2GRAY) obrazi = face_detector.detectMultiScale (siva, 1,3, 5) za (x, y, w, h) v obrazih: cv2. pravokotnik (img, (x, y), (x+w, y+h), (255, 0, 0), 2) count + = 1 # Posneto sliko shranite v mapo naborov podatkov cv2.imwrite ("nabor podatkov/uporabnik." + str (id_ obraza) + '.' + str (število) + ".jpg", sivo [y: y + h, x: x+w]) cv2.imshow ('image', img) k = cv2.waitKey (100) & 0xff # Pritisnite 'ESC' za izhod iz videa, če je k == 27: break elif count> = 30: # Vzemite 30 vzorcev obraza in ustavite video premor # Naredite ab it of cleanup print ("\ n [INFO] Izhod iz programa in čiščenje stvari") cam.release () cv2.destroyAllWindows ()

Koda je zelo podobna kodi, ki smo jo videli za zaznavanje obrazov. Dodali smo "vnosni ukaz" za zajem ID -ja uporabnika, ki bi moral biti celo število (1, 2, 3 itd.)

face_id = input ('\ n vnesite ID uporabnika konec pritisnite ==>')

In za vsakega od zajetih okvirjev ga moramo shraniti kot datoteko v imeniku "nabor podatkov":

cv2.imwrite ("nabor podatkov/uporabnik." + str (face_id) + '.' + str (število) + ".jpg", sivo [y: y + h, x: x + w])

Upoštevajte, da morate za shranjevanje zgornje datoteke uvoziti knjižnico "os". Ime vsake datoteke bo po strukturi:

User.face_id.count.jpg

Na primer, za uporabnika z face_id = 1 bo 4. vzorčna datoteka v naboru podatkov/ imeniku nekaj takega:

Uporabnik.1.4.jpg

kot je prikazano na zgornji fotografiji iz mojega Pi. V svoji kodi zajemam 30 vzorcev iz vsakega ID -ja. Lahko ga spremenite na zadnjem "elifu". Število vzorcev se uporabi za prekinitev zanke, kjer se zajamejo vzorci obraza.

Zaženite skript Python in zajemite nekaj ID -jev. Skript morate zagnati vsakič, ko želite združiti novega uporabnika (ali spremeniti fotografije za tistega, ki že obstaja).

6. korak: Trener

Trener
Trener

V tej drugi fazi moramo vzeti vse uporabniške podatke iz našega nabora podatkov in "trenirati" OpenCV Recognizer. To naredi neposredno posebna funkcija OpenCV. Rezultat bo datoteka.yml, ki bo shranjena v imeniku "trainer/".

Torej, začnimo ustvarjati podimenik, kamor bomo shranili izurjene podatke:

trener mkdir

Prenesite z mojega GitHub -a drugi skript python: 02_face_training.py

uvoz cv2

import numpy as np from PIL import Image import os # Pot za bazo podatkov o sliki poti = 'niz podatkov' prepoznavalec = cv2.face. LBPHFaceRecognizer_create () detektor = cv2. CascadeClassifier ("haarcascade_frontalface_default.xml"); # funkcija, da dobite slike in podatke o oznakah def getImagesAndLabels (pot): imagePaths = [os.path.join (pot, f) za f v os.listdir (pot)] faceSamples = ids = za imagePath v imagePaths: PIL_img = Image.open (imagePath).convert ('L') # pretvori v sivino img_numpy = np.array (PIL_img, 'uint8') id = int (os.path.split (imagePath) [-1]. split (".") [1]) obrazov = detektor.detectMultiScale (img_numpy) za (x, y, w, h) v obrazih: faceSamples.append (img_numpy [y: y+h, x: x+w]) ids.append (id) return faceSamples, ids print ("\ n [INFO] Obrazi za usposabljanje. Trajalo bo nekaj sekund. Počakajte …") obrazi, ids = getImagesAndLabels (pot) prepoznaval.train (obrazovi, np.array (ids)) # Shranite model v trainer/trainer.yml Reconizer.write ('trainer/trainer.yml') # Reconizer.save () je delal na Macu, ne pa na Pi # Natisnite število obrazovanih obrazov in natisnite končni program ("\ n [INFO] {0} obrazovani obrazi. Zapustitev programa".format (len (np.unique (ids))))

Potrdite, ali imate na svojem Rpi knjižnico PIL. Če ne, zaženite spodnji ukaz v terminalu:

pip namestite vzglavnik

Kot prepoznavalnik bomo uporabili LBPH (LOCAL BINARY PATTERNS HISTOGRAMS) prepoznavalnik obrazov, vključen v paket OpenCV. To naredimo v naslednji vrstici:

prepoznavalnik = cv2.face. LBPHFaceRecognizer_create ()

Funkcija "getImagesAndLabels (pot)" bo posnela vse fotografije v imeniku: "niz podatkov/" in vrnila 2 niza: "ID -ji" in "obrazi". S temi matrikami kot vhodnimi podatki bomo "usposobili našega prepoznavalca":

Prepoznavalnik. vlak (obrazi, ID -ji)

Posledično bo datoteka z imenom "trainer.yml" shranjena v imeniku trenerja, ki smo ga prej ustvarili.

To je to! Vključil sem zadnjo izjavo o tiskanju, kjer sem za potrditev prikazal število uporabnikovih obrazov, ki smo jih trenirali.

Vsakič, ko izvedete 1. fazo, morate zagnati tudi 2. fazo

7. korak: Prepoznavalnik

Prepoznavalnik
Prepoznavalnik
Prepoznavalnik
Prepoznavalnik

Zdaj smo prišli do zadnje faze našega projekta. Tukaj bomo na našo kamero posneli svež obraz in če bi imel ta oseba svoj obraz že posnet in usposobljen, bo naš prepoznavalec naredil "napoved", ki bo vrnila njegov ID in indeks, ki bo pokazal, kako samozavesten je prepoznavalec s to tekmo.

Prenesite 3. fazni python skript z mojega GitHub -a: 03_face_recognition.py.

uvoz cv2

uvoz numpy kot np uvoz os prepoznavalnik = cv2.face. LBPHFaceRecognizer_create () prepoznavnik.read ('trener/trener.yml') cascadePath = "haarcascade_frontalface_default.xml" faceCascade = cv2. CascadeClassifier (cascadeClassifier); font = cv2. FONT_HERSHEY_SIMPLEX #iniciativni števec id id = 0 # imena, povezana z id -ji: primer ==> Marcelo: id = 1, itd names = ['Brez', 'Marcelo', 'Paula', 'Ilza', 'Z ',' W '] # Inicializirajte in zaženite kamero za zajem videa v realnem času = cv2. VideoCapture (0) cam.set (3, 640) # nastavite video widht cam.set (4, 480) # nastavite višino videa # Določite najmanjšo velikost okna prepoznati kot obraz minW = 0,1*cam.get (3) minH = 0,1*cam.get (4) medtem ko je True: ret, img = cam.read () img = cv2.flip (img, -1) # Obrni navpično sivo = cv2.cvtColor (img, cv2. COLOR_BGR2GRAY) obrazov = faceCascade.detectMultiScale (siva, scaleFactor = 1,2, minNeighbors = 5, minSize = (int (minW), int (minH)),) za (x, y, w, h) v obrazih: cv2.rectangle (img, (x, y), (x+w, y+h), (0, 255, 0), 2) id, zaupanje = prepoznavalec.predict (siva [y: y+h, x: x+w]) # Preverite, ali je zaupanje manj 100 ==> "0" se popolnoma ujema, če (zaupanje <100): id = names [id] trust = "{0}% ".format (krog (100 - zaupanje)) else: id =" neznano "zaupanje =" {0}%". format (krog (100 - konf. idence)) cv2.putText (img, str (id), (x+5, y-5), font, 1, (255, 255, 255), 2) cv2.putText (img, str (zaupanje), (x+5, y+h-5), pisava, 1, (255, 255, 0), 1) cv2.imshow ('kamera', img) k = cv2.waitKey (10) & 0xff # Pritisnite 'ESC' za izhod iz videa, če je k == 27: break # Naredite nekaj čistilnega tiskanja ("\ n [INFO] Izhod iz programa in čiščenje") cam.release () cv2.destroyAllWindows ()

Vključujemo novo matriko, zato bomo namesto oštevilčenih id prikazali "imena":

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

Tako na primer: Marcelo bo uporabnik z id = 1; Paula: id = 2 itd.

Nato bomo zaznali obraz, enako kot prej s klasifikatorjem haasCascade. Ob zaznanem obrazu lahko pokličemo najpomembnejšo funkcijo v zgornji kodi:

id, zaupanje = prepoznavalec.predict (siv del obraza)

Prepoznavalnik.predict () bo za parameter vzel zajeti del obraza, ki ga je treba analizirati, in vrnil svojega verjetnega lastnika, pri čemer bo navedel njegov ID in koliko zaupanja prepoznavalec ima v zvezi s tem ujemanjem.

Upoštevajte, da se bo indeks zaupanja vrnil na "nič", če se bo popolnoma ujemal

In končno, če bi prepoznavec lahko napovedal obraz, nad sliko postavimo besedilo z verjetnim ID -jem in koliko je "verjetnost" v %, da je ujemanje pravilno ("verjetnost" = 100 - indeks zaupanja). V nasprotnem primeru se na obraz nalepi oznaka "neznano".

Spodaj-g.webp

Slika
Slika

Na zgornji sliki prikazujem nekaj testov, opravljenih s tem projektom, kjer sem s fotografijami preveril tudi, ali prepoznavalnik deluje.

8. korak: Zaključek

Zaključek
Zaključek

Kot vedno upam, da lahko ta projekt pomaga drugim najti pot v razburljiv svet elektronike!

Za podrobnosti in končno kodo obiščite moj depozitar GitHub: OpenCV-Face-Recognition

Za več projektov obiščite moj blog: MJRoBot.org

Spodaj na kratko o prihodnji vadnici, kjer bomo raziskali "samodejno sledenje obrazu in druge metode za zaznavanje obrazov":

Slika
Slika

Saludos z juga sveta!

Se vidimo v mojem naslednjem navodilu!

Hvala vam, Marcelo

Priporočena: