INHOUDSOPGAWE:

Intydse gesigsherkenning: 'n einde-tot-einde-projek: 8 stappe (met foto's)
Intydse gesigsherkenning: 'n einde-tot-einde-projek: 8 stappe (met foto's)

Video: Intydse gesigsherkenning: 'n einde-tot-einde-projek: 8 stappe (met foto's)

Video: Intydse gesigsherkenning: 'n einde-tot-einde-projek: 8 stappe (met foto's)
Video: Jonathan Blow: bewustzijn, gameontwerp en vrije wil 2024, Julie
Anonim
Intydse gesigherkenning: 'n Eind-tot-einde-projek
Intydse gesigherkenning: 'n Eind-tot-einde-projek

In my laaste tutoriaal wat OpenCV ondersoek het, het ons geleer AUTOMATIC VISION OBJECT TRACKING. Nou sal ons ons PiCam gebruik om gesigte in reële tyd te herken, soos u hieronder kan sien:

Beeld
Beeld

Hierdie projek is gedoen met hierdie fantastiese "Open Source Computer Vision Library", die OpenCV. In hierdie tutoriaal fokus ons op Raspberry Pi (dus Raspbian as OS) en Python, maar ek het ook die kode op My Mac getoets en dit werk ook goed. OpenCV is ontwerp vir rekenkundige doeltreffendheid en met 'n sterk fokus op intydse toepassings. Dit is dus perfek vir gesigsherkenning in real-time met behulp van 'n kamera.

Om 'n volledige projek oor gesigherkenning te skep, moet ons aan drie baie verskillende fases werk:

  1. Gesigsopsporing en data -insameling
  2. Leer die herkener op
  3. Gesigsherkenning

Die onderstaande blokdiagram hervat die fases:

Beeld
Beeld

Stap 1: BoM - Staatsbrief

Belangrikste dele:

  1. Framboos Pi V3 - US $ 32,00
  2. 5 megapixels 1080p sensor OV5647 mini kamera videomodule - US $ 13,00

Stap 2: Installeer OpenCV 3 -pakket

Installeer OpenCV 3 -pakket
Installeer OpenCV 3 -pakket

Ek gebruik 'n Raspberry Pi V3 wat bygewerk is na die laaste weergawe van Raspbian (Stretch), dus die beste manier om OpenCV geïnstalleer te hê, is om die uitstekende tutoriaal te volg wat deur Adrian Rosebrock ontwikkel is: Raspbian Stretch: Installeer OpenCV 3 + Python op jou Raspberry Pi.

Ek het verskillende gidse probeer om OpenCV op my Pi te installeer. Adrian se tutoriaal is die beste. Ek raai u aan om dieselfde te doen, stap-vir-stap sy riglyn volg.

Nadat u die tutoriaal van Adrian voltooi het, behoort u 'n virtuele OpenCV -omgewing te hê wat gereed is om ons eksperimente op u Pi uit te voer.

Kom ons gaan na ons virtuele omgewing en bevestig dat OpenCV 3 korrek geïnstalleer is.

Adrian beveel aan dat u die opdrag "bron" gebruik elke keer as u 'n nuwe terminaal oopmaak om te verseker dat u stelselveranderlikes korrek opgestel is.

bron ~/.profiel

Laat ons dan ons virtuele omgewing betree:

werk cv

As u die teks (cv) voor u opdrag sien, is u in die virtuele cv -omgewing:

(cv) pi@framboos: ~ $Adrian vestig die aandag dat die cv Python -virtuele omgewing heeltemal onafhanklik is en geskei word van die standaard Python -weergawe wat by die aflaai van Raspbian Stretch ingesluit is. Dus, enige Python-pakkette in die globale webwerf-pakketgids is nie beskikbaar vir die cv-virtuele omgewing nie. Net so sal enige Python-pakkette wat in cv-pakkette geïnstalleer is, nie beskikbaar wees vir die wêreldwye installering van Python nie

Voer nou u Python -tolk in:

luislang

en bevestig dat u die weergawe 3.5 (of hoër) gebruik

In die tolk (die ">>>" sal verskyn), voer die OpenCV -biblioteek in:

voer cv2 in

As daar geen foutboodskappe verskyn nie, is die OpenCV korrek geïnstalleer OP U PYTHON VIRTUAL OMGEWING.

U kan ook die geïnstalleerde OpenCV -weergawe nagaan:

cv2._ weergawe_

Die 3.3.0 moet verskyn (of 'n beter weergawe wat in die toekoms vrygestel kan word). Bogenoemde Terminal PrintScreen toon die vorige stappe.

Stap 3: Toets u kamera

Toets u kamera
Toets u kamera

Sodra u OpenCV in u RPi geïnstalleer het, laat ons toets of u kamera behoorlik werk.

Ek neem aan dat u reeds 'n PiCam op u Raspberry Pi geïnstalleer het.

Voer die onderstaande Python -kode op u IDE in:

invoer numpy as np

invoer 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 (raam, -1) # Draai kamera vertikaal grys = cv2.cvtColor (raam, cv2. COLOR_BGR2GRAY) cv2.imshow ('raam', raam) cv2.imshow ('grys', grys) k = cv2.waitKey (30) & 0xff as k == 27: # druk op 'ESC' om af te sluit break cap.release () cv2.destroyAllWindows ()

Bogenoemde kode vang die videostroom op wat deur u PiCam gegenereer sal word, wat beide in BGR -kleur en grys modus vertoon.

Let daarop dat ek my kamera vertikaal gedraai het vanweë die manier waarop dit gemonteer is. As dit nie u geval is nie, lewer 'n opmerking of verwyder die opdragreël "flip".

U kan ook die kode aflaai van my GitHub: simpleCamTest.py

Voer die opdrag in om uit te voer:

python simpleCamTest.py

Om die program te voltooi, moet u op die sleutel [ESC] op u sleutelbord druk.

Klik met u muis op die video -venster voordat u op [ESC] druk

Die foto hierbo toon die resultaat.

Sommige vervaardigers het probleme ondervind wanneer hulle probeer om die kamera oop te maak (foutboodskappe "Bewering misluk"). Dit kan gebeur as die kamera nie tydens OpenCv -installasie geaktiveer is nie, en kamera bestuurders nie korrek geïnstalleer is nie. Gebruik die opdrag om dit reg te stel:

sudo modprobe bcm2835-v4l2

U kan ook bcm2835-v4l2 by die laaste reël van die /etc /modules-lêer voeg sodat die bestuurder laai.

Om meer te wete te kom oor OpenCV, kan u die tutoriaal volg: laai -video-python-opencv-tutoriaal

Stap 4: Gesigsopsporing

Gesigsopsporing
Gesigsopsporing
Gesigsopsporing
Gesigsopsporing

Die mees basiese taak vir gesigherkenning is natuurlik "Gesigsopsporing". Voordat u iets kan, moet u 'n gesig (fase 1) "vasvang" om dit te herken, in vergelyking met 'n nuwe gesig wat in die toekoms vasgelê is (fase 3).

Die mees algemene manier om 'n gesig (of enige voorwerp) op te spoor, is deur die 'Haar Cascade classifier' te gebruik

Objekopsporing met behulp van Haar-funksie-gebaseerde kaskade-klassifiseerders is 'n effektiewe voorwerpopsporingsmetode wat deur Paul Viola en Michael Jones voorgestel is in hul referaat, "Rapid Object Detection using a Boosted Cascade of Simple Features" in 2001. Dit is 'n masjienleer-gebaseerde benadering waar 'n kaskade funksie word opgelei uit baie positiewe en negatiewe beelde. Dit word dan gebruik om voorwerpe in ander beelde op te spoor.

Hier werk ons met gesigsopsporing. Aanvanklik benodig die algoritme baie positiewe beelde (beelde van gesigte) en negatiewe beelde (beelde sonder gesigte) om die klassifiseerder op te lei. Dan moet ons funksies daaruit haal. Die goeie nuus is dat OpenCV sowel 'n afrigter as 'n detektor bevat. As u u eie klassifiseerder wil oplei vir enige voorwerp soos motor, vliegtuie, ens., Kan u OpenCV gebruik om een te skep. Die volledige besonderhede word hier gegee: Cascade Classifier Training.

As u nie u eie klassifiseerder wil skep nie, bevat OpenCV reeds baie vooraf opgeleide klassifiseerders vir gesig, oë, glimlag, ens. Die XML-lêers kan van haarcascades-gids afgelaai word.

Genoeg teorie, laat ons 'n gesigmelder met OpenCV skep!

Laai die lêer: faceDetection.py af van my GitHub.

invoer numpy as np

invoer cv2 faceCascade = cv2. CascadeClassifier ('Cascades/haarcascade_frontalface_default.xml') cap = cv2. VideoCapture (0) cap.set (3, 640) # set Width cap.set (4, 480) # set Hoogte terwyl True: ret, img = cap.read () img = cv2.flip (img, -1) grey = cv2.cvtColor (img, cv2. COLOR_BGR2GRAY) gesigte = faceCascade.detectMultiScale (grys, scaleFactor = 1.2, minNeighbors = 5, minSize = (20, 20)) vir (x, y, w, h) in vlakke: cv2.reghoek (img, (x, y), (x+w, y+h), (255, 0, 0), 2) roi_gray = grys [y: y+h, x: x+w] roi_color = img [y: y+h, x: x+w] cv2.imshow ('video', img) k = cv2.waitKey (30) & 0xff as k == 27: # druk op 'ESC' om af te sluit break cap.release () cv2.destroyAllWindows ()

Glo dit of nie, die bogenoemde paar reëls kode is alles wat u nodig het om 'n gesig op te spoor met behulp van Python en OpenCV.

As u vergelyk met die laaste kode wat gebruik is om die kamera te toets, sal u besef dat daar min dele bygevoeg is. Let op die onderstaande reël:

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

Dit is die reël wat die 'klassifiseerder' laai (dit moet in 'n gids met die naam 'Cascades/', onder u projekgids wees).

Dan stel ons ons kamera in en laai ons invoervideo in grysskaalmodus (dieselfde as wat ons voorheen gesien het).

Nou moet ons ons klassifiseringsfunksie noem, en dit gee 'n paar baie belangrike parameters, soos skaalfaktor, aantal bure en minimum grootte van die bespeurde gesig.

gesigte = faceCascade.detectMultiScale (grys, skaalFaktor = 1.2, minBure = 5, minGrootte = (20, 20))

Waar,

  • grys is die invoergrysbeeld.
  • scaleFactor is die parameter wat spesifiseer hoeveel die beeldgrootte by elke beeldskaal verminder word. Dit word gebruik om die skaalpiramide te skep.
  • minNeighbors is 'n parameter wat spesifiseer hoeveel bure elke kandidaat -reghoek moet hê om dit te behou. 'N Hoër getal gee laer vals positiewe.
  • minSize is die minimum reghoekgrootte wat as 'n gesig beskou moet word.

Die funksie sal gesigte op die beeld opspoor. Vervolgens moet ons die gesigte in die prentjie "merk" deur byvoorbeeld 'n blou reghoek te gebruik. Dit word gedoen met hierdie gedeelte van die kode:

vir (x, y, w, h) in gesigte:

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

As gesigte gevind word, gee dit die posisies van bespeurde gesigte terug as 'n reghoek met die linkerhoek (x, y) en met "w" as sy breedte en "h" as die hoogte ==> (x, y, w, h). Sien die prent hierbo.

Sodra ons hierdie liggings kry, kan ons 'n "ROI" (getekende reghoek) vir die gesig skep en die resultaat met imshow () -funksie voorstel.

Begin die bogenoemde python -script op u python -omgewing met behulp van die Rpi Terminal:

python faceDetection.py

Die resultaat:

Beeld
Beeld

U kan ook klassifiseerders insluit vir 'oogopsporing' of selfs 'glimlagopsporing'. In hierdie gevalle sluit u die klassifiseringsfunksie en die reghoektekening in die gesiglus in, want dit is nie sinvol om 'n oog of 'n glimlag buite 'n gesig op te spoor nie.

Let daarop dat die verwerking op 'n Pi, met verskeie klassifiseerders met dieselfde kode, die verwerking sal vertraag, sodra hierdie opsporingsmetode (HaarCascades) 'n groot hoeveelheid rekenkrag gebruik. Op 'n lessenaar is dit makliker om dit uit te voer.

Op my GitHub vind u ander voorbeelde:

faceEyeDetection.py

faceSmileDetection.py

faceSmileEyeDetection.py

En op die foto hierbo kan u die resultaat sien.

U kan ook die onderstaande handleiding volg om gesigdeteksie beter te verstaan:

Haar Cascade Object Detection Face & Eye OpenCV Python -tutoriaal

Stap 5: Data -insameling

Data-insameling
Data-insameling
Data-insameling
Data-insameling

Eerstens moet ek Ramiz Raja bedank vir sy wonderlike werk oor gesigherkenning op foto's:

GESIGTE ERKENNING MET OPENCV EN PYTHON: 'N BEGINNERSGIDS

en ook Anirban Kar, wat 'n baie uitgebreide handleiding met behulp van video ontwikkel het:

GESIGTE ERKENNING - 3 dele

Ek beveel regtig aan dat u na albei tutoriale kyk.

As ons dit sê, begin ons met die eerste fase van ons projek. Wat ons hier gaan doen, begin by die laaste stap (Gesigsopsporing); ons sal eenvoudig 'n datastel skep, waar ons vir elke ID 'n groep grys foto's met die gedeelte wat vir gesigopsporing gebruik is, sal stoor.

Skep eers 'n gids waar u u projek ontwikkel, byvoorbeeld FacialRecognitionProject:

mkdir FacialRecognitionProject

In hierdie gids, behalwe die 3 python -skrifte wat ons vir ons projek gaan skep, moes ons die Facial Classifier daarop gestoor het. U kan dit aflaai van my GitHub: haarcascade_frontalface_default.xml

Maak dan 'n subgids waar ons ons gesigmonsters sal stoor en dit 'dataset' noem:

mkdir -datastel

En laai die kode af van my GitHub: 01_face_dataset.py

voer cv2 in

invoer os cam = cv2. VideoCapture (0) cam.set (3, 640) # stel video breedte cam.set (4, 480) # stel video hoogte face_detector = cv2. CascadeClassifier ('haarcascade_frontalface_default.xml') # Vir elke persoon, voer een numeriese gesig -ID in face_id = input ('\ n enter user id end press ==>') print ("\ n [INFO] Initialiseer gesigopname. Kyk na die kamera en wag …") # Initialiseer individuele monsterneming van gesigstelling = 0 terwyl (Waar): ret, img = cam.read () img = cv2.flip (img, -1) # draai videobeeld vertikaal grys = cv2.cvtColor (img, cv2. COLOR_BGR2GRAY) gesigte = face_detector.detectMultiScale (grys, 1,3, 5) vir (x, y, w, h) in vlakke: cv2.reghoek (img, (x, y), (x+w, y+h), (255, 0, 0), 2) count + = 1 # Stoor die vasgelegde prent in die datastelle -gids cv2.imwrite ("dataset/User." + str (face_id) + '.' + str (count) + ".jpg", grys [y: y + h, x: x+w]) cv2.imshow ('image', img) k = cv2.waitKey (100) & 0xff # Druk op 'ESC' om die video te verlaat as k == 27: breek eliftelling> = 30: # Neem 30 gesigmonsters en stop die video breek # Do ab dit van opruimingsafdruk ("\ n [INFO] Program verlaat en dinge wat opruim") cam.release () cv2.destroyAllWindows ()

Die kode is baie soortgelyk aan die kode wat ons gesien het vir gesigopsporing. Wat ons bygevoeg het, was 'n 'invoeropdrag' om 'n gebruikers -ID op te neem, wat 'n heelgetal moet wees (1, 2, 3, ens)

face_id = input ('\ n enter user id end press ==>')

En vir elkeen van die vasgelegde rame moet ons dit as 'n lêer stoor in 'n "dataset" -gids:

cv2.imwrite ("dataset/User." + str (face_id) + '.' + str (count) + ".jpg", grys [y: y + h, x: x + w])

Let daarop dat u die biblioteek "os" ingevoer het om die bogenoemde lêer te stoor. Elke lêer se naam sal die struktuur volg:

User.face_id.count.jpg

Byvoorbeeld, vir 'n gebruiker met 'n face_id = 1, sal die vierde voorbeeldlêer op datastel/ gids iets wees soos:

Gebruiker.1.4.jpg

soos getoon in die foto hierbo van my Pi. Op my kode neem ek 30 monsters van elke ID op. U kan dit verander met die laaste 'elif'. Die aantal monsters word gebruik om die lus te breek waar die gesigmonsters vasgelê word.

Begin die Python -script en neem 'n paar ID's vas. U moet die script elke keer as u 'n nuwe gebruiker wil saamvoeg, uitvoer (of die foto's verander vir een wat reeds bestaan).

Stap 6: afrigter

Afrigter
Afrigter

In hierdie tweede fase moet ons alle gebruikersdata uit ons dataset neem en die OpenCV Recognizer "oplei". Dit word direk gedoen deur 'n spesifieke OpenCV -funksie. Die resultaat sal 'n.yml lêer wees wat in 'n "trainer/" gids gestoor word.

Laat ons dus begin met die skep van 'n subgids waar ons die opgeleide data sal stoor:

mkdir afrigter

Laai die tweede python -script van my GitHub af: 02_face_training.py

voer cv2 in

invoer numpy as np van PIL invoer Beeld invoer os # Pad vir gesig beeld databasis pad = 'dataset' herkenner = cv2.face. LBPHFaceRecognizer_create () detector = cv2. CascadeClassifier ("haarcascade_frontalface_default.xml"); # funksie om die beelde te kry en data te benoem def getImagesAndLabels (pad): imagePaths = [os.path.join (pad, f) vir f in os.listdir (pad)] faceSamples = ids = vir imagePath in imagePaths: PIL_img = Image.open (imagePath).convert ('L') # omskep dit in grysskaal img_numpy = np.array (PIL_img, 'uint8') id = int (os.path.split (imagePath) [-1]. split (".") [1]) gesigte = detector.detectMultiScale (img_numpy) vir (x, y, w, h) in gesigte: faceSamples.append (img_numpy [y: y+h, x: x+w]) ids.append (id) return faceSamples, ids print ("\ n [INFO] Opleidingsgesigte. Dit sal 'n paar sekondes neem. Wag …") gesigte, ids = getImagesAndLabels (pad) identifier.train (gesigte, np.array (ids)) # Stoor die model in trainer/trainer.yml werkenaar.skryf ('trainer/trainer.yml') # herkenner.save () het op Mac gewerk, maar nie op Pi nie # Druk die aantal gesigte wat opgelei is af en druk die program af ("\ n [INFO] {0} opgeleide gesigte. Verlaat program".format (len (np.unique (ids))))

Bevestig of u die PIL -biblioteek op u Rpi geïnstalleer het. Indien nie, voer die onderstaande opdrag in Terminal uit:

pip installeer kussing

Ons gebruik die LBPH (LOCAL BINARY PATTERNS HISTOGRAMS) as 'n herkener, ingesluit in OpenCV -pakket. Ons doen dit in die volgende reël:

herkener = cv2.face. LBPHFaceRecognizer_create ()

Die funksie "getImagesAndLabels (pad)" neem alle foto's in die gids: "dataset/" en gee 2 skikkings: "Ids" en "gesigte". Met die skikkings as invoer, sal ons 'ons herkener' oplei:

herkener.opleiding (gesigte, ID's)

As gevolg hiervan, sal 'n lêer met die naam "trainer.yml" gestoor word in die opleidergids wat voorheen deur ons geskep is.

Dis dit! Ek het die laaste afdrukverklaring ingesluit waar ek vir bevestiging vertoon het, die aantal gebruikers se gesigte wat ons opgelei het.

Elke keer dat u Fase 1 uitvoer, moet Fase 2 ook uitgevoer word

Stap 7: Herkener

Herkener
Herkener
Herkener
Herkener

Nou het ons die laaste fase van ons projek bereik. Hier sal ons 'n vars gesig op ons kamera vaslê, en as hierdie persoon sy gesig voorheen vasgelê en opgelei het, sal ons herkener 'n 'voorspelling' maak wat sy ID en 'n indeks terugbring, wat wys hoe selfversekerd die herkener is met hierdie wedstryd.

Laai die python -script van die derde fase af van my GitHub: 03_face_recognition.py.

voer cv2 in

invoer numpy as np invoer os werkener = cv2.face. LBPHFaceRecognizer_create () herkenner.read ('trainer/trainer.yml') cascadePath = "haarcascade_frontalface_default.xml" faceCascade = cv2. CascadeClassifier (cascadePath); font = cv2. FONT_HERSHEY_SIMPLEX #iniciate id counter id = 0 # name related to ids: example ==> Marcelo: id = 1, etc names = ['None', 'Marcelo', 'Paula', 'Ilza', 'Z ',' W '] # Initialiseer en begin intydse video -opname cam = cv2. VideoCapture (0) cam.set (3, 640) # stel video widht cam.set (4, 480) # stel videohoogte in # Definieer min venster grootte om erken te word as 'n gesig minW = 0.1*cam.get (3) minH = 0.1*cam.get (4) terwyl True: ret, img = cam.read () img = cv2.flip (img, -1) # Draai vertikaal grys = cv2.cvtColor (img, cv2. COLOR_BGR2GRAY) gesigte = faceCascade.detectMultiScale (grys, scaleFactor = 1.2, minNeighbors = 5, minSize = (int (minW), int (minH)),) vir (x, y, w, h) in vlakke: cv2.reghoek (img, (x, y), (x+w, y+h), (0, 255, 0), 2) id, vertroue = herkener.voorspelling (grys [y: y+h, x: x+w]) # Kontroleer of vertroue minder is as 100 ==> "0" pas by as (vertroue <100): id = name [id] vertroue = "{0}% ".format (rondte (100 - vertroue)) anders: id =" onbekend "vertroue =" {0}%". formaat (rond (100 - konf. idence)) cv2.putText (img, str (id), (x+5, y-5), font, 1, (255, 255, 255), 2) cv2.putText (img, str (vertroue), (x+5, y+h-5), lettertipe, 1, (255, 255, 0), 1) cv2.imshow ('kamera', img) k = cv2.waitKey (10) & 0xff # Druk 'ESC' vir die afsluiting van video as k == 27: breek # Maak 'n bietjie skoonmaakafdruk ("\ n [INFO] Verlaat program en opruim dinge") cam.release () cv2.destroyAllWindows ()

Ons sluit hier 'n nuwe skikking in, so ons sal "name" in plaas van genommerde ID's vertoon:

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

So, byvoorbeeld: Marcelo sal die gebruiker met id = 1; Paula: id = 2, ens.

Vervolgens sal ons 'n gesig opspoor, dieselfde as voorheen met die haasCascade -klassifiseerder. As ons 'n gesig het, kan ons die belangrikste funksie in die kode hierbo noem:

id, vertroue = herkener.voorspelling (grys deel van die gesig)

Die identifier.predict (), neem as 'n parameter 'n vasgevang gedeelte van die gesig wat geanaliseer moet word, en gee sy waarskynlike eienaar terug, wat sy ID aandui en hoeveel vertroue die herkener in hierdie wedstryd het.

Let daarop dat die vertrouensindeks 'nul' sal terugkeer as dit as 'n perfekte pasmaat beskou word

En uiteindelik, as die herkener 'n gesig kan voorspel, plaas ons 'n teks oor die beeld met die waarskynlike id en hoeveel is die "waarskynlikheid" in % dat die pasmaat korrek is ("waarskynlikheid" = 100 - vertrouensindeks). Indien nie, word 'n "onwetende" etiket op die gesig gesit.

Hieronder 'n-g.webp

Beeld
Beeld

Op die foto hierbo toon ek 'n paar toetse wat met hierdie projek gedoen is, waar ek ook foto's gebruik het om te kontroleer of die herkenning werk.

Stap 8: Gevolgtrekking

Afsluiting
Afsluiting

Soos altyd, hoop ek dat hierdie projek ander kan help om die opwindende wêreld van elektronika te vind!

Besoek my GitHub-bewaarplek: OpenCV-Face-Recognition vir besonderhede en finale kode

Besoek my blog vir meer projekte: MJRoBot.org

Hieronder 'n blik op 'n toekomstige tutoriaal, waar ons 'outomatiese gesigspoor en ander metodes vir gesigopsporing' sal ondersoek:

Beeld
Beeld

Groete uit die suide van die wêreld!

Sien jou in my volgende instruksies!

Dankie, Marcelo

Aanbeveel: