Automatische detectie van verkeersborden. - Departement ...
Automatische detectie van verkeersborden. - Departement ...
Automatische detectie van verkeersborden. - Departement ...
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
HOGESCHOOL GENT<br />
Academiejaar 2003 – 2004 <strong>Departement</strong> Industriële Wetenschappen<br />
BME - CTL<br />
Schoonmeersstraat 52 - 9000 Gent<br />
<strong>Automatische</strong> <strong>detectie</strong> <strong>van</strong><br />
<strong>verkeersborden</strong><br />
Eindwerk voorgedragen tot het behalen <strong>van</strong> het diploma <strong>van</strong><br />
INDUSTRIEEL INGENIEUR IN ELEKTROMECHANICA OPTIE AUTOMATISERING door :<br />
Francis DECRAEMER, Jelle PROOT<br />
Promotor Hogeschool : Prof. ir. dr. Peter Veelaert<br />
1
Woord vooraf<br />
Onze dank gaat uit naar prof. dr. ir. Peter Veelaert, die ons heeft bijgestaan bij de realisatie<br />
<strong>van</strong> ons eindwerk. Zijn technische kennis en vele raadgevingen hebben ons op de goede<br />
weg gezet.<br />
Ook aan onze ouders die ons de mogelijkheid hebben gegeven om verder te studeren en ons<br />
te steunen in de keuzes die we hebben gemaakt, een woord <strong>van</strong> dank.<br />
We danken ook iedereen die ons gesteund heeft tijdens onze studies voor industrieel<br />
ingenieur: de professoren en assistenten die ons zeer veel technische kennis hebben<br />
bijgebracht.<br />
Francis Decraemer, Jelle Proot<br />
Gent, mei 2004<br />
2
Abstract<br />
Doelstelling voor ons onderzoek is het vinden <strong>van</strong> een oplossing die <strong>verkeersborden</strong><br />
automatisch kan detecteren. Het herkenningssysteem dat we hiervoor ontwikkelden,<br />
kunnen we in twee grote delen opsplitsen. In het eerste deel lokaliseren we het<br />
verkeersbord op een globaal beeld/foto door middel <strong>van</strong> verschillende algoritmes. We<br />
maken gebruik <strong>van</strong> twee eigenschappen <strong>van</strong> <strong>verkeersborden</strong>: de specifieke kleur en de<br />
vorm.<br />
In het tweede deel classificeren we de <strong>verkeersborden</strong> via een neuraal net. We gaan na of<br />
de lokalisatie <strong>van</strong> het verkeersbord goed is verlopen en bepalen vervolgens welk type<br />
verkeersbord er op de foto staat.<br />
We hebben het herkenningssysteem op een driehonderdtal beelden getest en in 73% <strong>van</strong> de<br />
gevallen waren de resultaten perfect.<br />
3
Woord vooraf<br />
Abstract<br />
Inhoudstafel<br />
Inleiding 7<br />
Hoofdstuk 1: Kleurfilter 10<br />
RGB-kleurmodel 10<br />
HSV-kleurmodel 11<br />
HSV-kleurfilter 12<br />
a. Principe 13<br />
b. Implementatie 13<br />
c. Voorbeelden 14<br />
d. Conclusie 15<br />
Roodfilter 16<br />
a. Principe 16<br />
b. Implementatie 17<br />
c. Voorbeelden 18<br />
d. Conclusie 19<br />
Blauwfilter 19<br />
a. Principe 19<br />
b. Implementatie 20<br />
c. Voorbeelden 20<br />
d. Conclusie 22<br />
Witfilter 22<br />
a. Principe 22<br />
b. Voorbeelden 24<br />
Zwartfilter 25<br />
a. Principe 25<br />
b. Voorbeelden 26<br />
Hoofdstuk 2: Edge <strong>detectie</strong> 27<br />
Algemeen 27<br />
Sobel 27<br />
Canny 29<br />
Canny of Sobel 31<br />
Morfologische bewerkingen 31<br />
a. ‘skel’ 31<br />
b. ‘bwareaopen’ 32<br />
c. ‘clean’ 32<br />
d. ‘fill’ 32<br />
Voorbeelden 33<br />
Conclusie 41<br />
4
Hoofdstuk 3: Cirkel<strong>detectie</strong> 42<br />
Wat is een goede cirkel? 42<br />
Random 44<br />
Problemen 44<br />
Oplossingen 44<br />
Extraheren <strong>van</strong> de cirkel 45<br />
Voorbeelden 46<br />
Conclusie 49<br />
Hoofdstuk 4: Lijn<strong>detectie</strong> 50<br />
Algemeen 50<br />
Wat zijn poolcoördinaten? 50<br />
Ransac 51<br />
Radon 51<br />
Keuze 52<br />
Problemen 52<br />
Oplossing 53<br />
Hoofdstuk 5: Driehoek<strong>detectie</strong> 54<br />
Wat is een driehoek? 54<br />
Implementatie 54<br />
Bepalen <strong>van</strong> de snijpunten 57<br />
Problemen 57<br />
Oplossingen 58<br />
Extraheren <strong>van</strong> de driehoek 59<br />
Voorbeelden 59<br />
Conclusie 69<br />
Hoofdstuk 6: Rechthoek<strong>detectie</strong> 70<br />
Wat is een rechthoek? 70<br />
Implementatie 70<br />
Problemen 71<br />
Oplossingen 71<br />
Extraheren 71<br />
Voorbeeld 72<br />
Hoofdstuk 7: Classificatie <strong>van</strong> <strong>verkeersborden</strong> 73<br />
Wat is een neuraal net? 73<br />
Driehoeken 75<br />
a. Wat is een Fourier transformatie? 75<br />
b. Implementatie 76<br />
Cirkels 77<br />
a. Algemeen 78<br />
b. Implementatie 79<br />
Voorbeelden 80<br />
Conclusie 81<br />
5
Hoofdstuk 8: Testen <strong>van</strong> het herkenningssysteem 82<br />
Gaussian Noise 82<br />
Wazig maken <strong>van</strong> het beeld 84<br />
Allerlei bewerkingen 85<br />
Rotaties 88<br />
a. Cirkelvormige <strong>verkeersborden</strong> 88<br />
b. Driehoekige <strong>verkeersborden</strong> 89<br />
Conclusie 90<br />
Hoofdstuk 9: Conclusie 91<br />
Opbouw <strong>van</strong> het volledige herkenningssysteem 91<br />
Voorbeelden 92<br />
Conclusie 97<br />
Appendix A: Thumbnails 98<br />
Appendix B: Code <strong>van</strong> het herkenningssysteem 107<br />
Literatuurlijst 143<br />
6
Inleiding<br />
De originele bedoeling <strong>van</strong> ons eindwerk bestond erin via een camera in een auto<br />
<strong>verkeersborden</strong> langs de kant <strong>van</strong> de weg te detecteren en te classificeren. Hoewel er over<br />
de jaren heen al veel onderzoek werd gedaan om zo’n systeem te ontwikkelen, is er nog<br />
geen in de praktijk toepasbare oplossing voorgesteld.<br />
Het eerste systeem werd al in 1984 in Japan ontwikkeld. Bedoeling was een computer<br />
visiesysteem te realiseren dat <strong>detectie</strong> <strong>van</strong> objecten buitenshuis mogelijk moest maken.<br />
Begin de jaren ‘90 hebben verschillende onderzoeksgroepen verdere research gedaan om<br />
een herkenningsysteem te maken. Hun focus was gericht op <strong>verkeersborden</strong>.<br />
Zo werden twee systemen ontwikkeld die het mogelijk maakten randen (edges) te<br />
herkennen en kleuren af te zonderen. Voor de classificatie werd gebruikt gemaakt <strong>van</strong> een<br />
neuraal net [1].<br />
Een <strong>van</strong> de wellicht betere systemen voor het herkennen <strong>van</strong> <strong>verkeersborden</strong> werd in Israël<br />
gebouwd, waar een groot onderzoek rond dit thema werd opgezet. Voor de classificatie <strong>van</strong><br />
<strong>verkeersborden</strong> werd gebruik gemaakt <strong>van</strong> een support vector machine, een type <strong>van</strong> een<br />
neuraal net [2].<br />
Ons eindwerk is de eerste fase <strong>van</strong> een project dat over verschillende jaren zal lopen. Het<br />
doel <strong>van</strong> het project is in hardware een herkenningssysteem te maken dat real time<br />
<strong>verkeersborden</strong> kan herkennen en classificeren.<br />
Wij startten ons onderzoek met het gebruiken <strong>van</strong> LabVIEW teneinde onze beelden in real<br />
time te verwerken. Maar de verwerkingsmogelijkheden <strong>van</strong> LabVIEW zijn te beperkt en<br />
noodzaakten ons op MATLAB over te schakelen.<br />
We hebben ons toegelegd op het verwerken <strong>van</strong> digitale foto’s die langs de Belgische<br />
wegen genomen zijn.<br />
Op die foto’s, beelden genoemd, voeren we allerlei bewerkingen uit. Eerst proberen we<br />
zoveel mogelijk de rode en blauwe vlakken uit ons beeld te filteren. Daarna zoeken we naar<br />
de randen. Wanneer we die randen hebben gevonden, zoeken we naar geometrische<br />
figuren, die kunnen voldoen aan de eisen die de Belgische regering aan een verkeersbord<br />
oplegt. Die geometrische figuren – rechthoek, cirkel of driehoek – extraheren we uit ons<br />
beeld zodat we een nieuw beeld verkrijgen waar alleen nog maar het vermoedelijke<br />
verkeersbord op aanwezig is.<br />
De laatste stap in het proces is de classificatie <strong>van</strong> de <strong>verkeersborden</strong>. Aangezien het<br />
helemaal niet zeker is dat het geëxtraheerde beeld een verkeersbord is, bestaat de eerste<br />
stap bij de classificatie erin na te gaan of we al dan niet met een verkeersbord te maken<br />
hebben. Is het een verkeersbord, dan gaan we nog een stap verder en onderzoeken we om<br />
welk type het gaat. We zijn in staat verschillende types <strong>verkeersborden</strong> te classificeren:<br />
gebodsborden, verbodsborden en gevarendriehoeken.<br />
Stel dat we een driehoek als gevarendriehoek classificeren, dan weten we niet precies<br />
welke gevarendriehoek het is, enkel dat het over een gevarendriehoek gaat. Voor de<br />
gebodsborden en verbodsborden is dat net zo.<br />
7
Toch wilden we er in slagen enkele borden volledig te classificeren. We hebben ons<br />
gefocust op de borden B06 en C02. B06 is het verleen voorrang bord: een driehoek met de<br />
top naar beneden, een rode band en enkel wit tussen de band. C02 is het eenrichtingsweg<br />
bord. Een rode cirkel met een witte streep. Die twee borden kunnen we herkennen.<br />
Wanneer we een digitale foto in ons programma inladen, geeft het met 73% zekerheid<br />
correct de informatie weer die op het beeld staat.<br />
De tijd die het volledige herkenningssysteem nodig heeft, hangt af <strong>van</strong> de hoeveelheid ruis<br />
op het beeld en <strong>van</strong> de computersnelheid. Bij weinig ruis ligt de tijd rond de 40 à 50<br />
seconden. Als er veel ruis aanwezig is, stijgt de tijd naar een 3-tal minuten. De gemiddelde<br />
tijd bedraagt 1 minuut en 34 seconden.<br />
8
Beeld filteren met<br />
rood filter<br />
Hoofdstuk 1<br />
Randen zoeken op<br />
het beeld<br />
Hoofdstuk 2<br />
Lijnen zoeken op<br />
het beeld<br />
Hoofdstuk 4<br />
Driehoek zoeken<br />
via de gevonden<br />
lijnen<br />
Hoofdstuk 5<br />
Stroomdiagram herkenningssysteem<br />
Rechthoeken<br />
zoeken via de<br />
gevonden lijnen<br />
Hoofdstuk 6<br />
Classificatie <strong>van</strong> de Driehoek<br />
RoodFilter<br />
toepassen<br />
Fourier analyse<br />
Neuraal net<br />
Perceptron<br />
Hoofdstuk 7<br />
Inlezen Beeld<br />
Inleiding<br />
Cirkels zoeken<br />
Hoofdstuk 3<br />
Classificatie <strong>van</strong> de Cirkel<br />
Kleuren bepalen<br />
<strong>van</strong> de cirkel<br />
Neuraal net<br />
Perceptron<br />
Beeld filteren met<br />
blauw filter<br />
Hoofdstuk 1<br />
Randen zoeken op<br />
het beeld<br />
Hoofdstuk 2<br />
Hoofdstuk 7<br />
9
Hoofdstuk 1: Kleurfilter<br />
In dit hoofdstuk zullen we het belang aantonen <strong>van</strong> het ‘filteren’ <strong>van</strong> een foto. Met<br />
filteren bedoelen we: zoveel mogelijk achtergrondinformatie uit het beeld<br />
verwijderen, zonder de eventuele <strong>verkeersborden</strong> op de foto te beschadigen. Bij een<br />
perfect gefilterd beeld zouden we alleen maar een wit verkeersbord op een zwarte<br />
achtergrond mogen zien. Dat werkt natuurlijk niet perfect, er blijft altijd ‘ruis’ op het<br />
beeld aanwezig. Met ruis bedoelen we dat er na het filteren nog informatie <strong>van</strong> de<br />
achtergrond op het beeld is te zien.<br />
Er zijn verschillende methodes, die we ook hebben uitgetest, om een beeld te filteren.<br />
Elke methode heeft zijn voordelen en beperkingen, maar heeft wel tot het<br />
uiteindelijke resultaat bijgedragen.<br />
We hebben ervaren dat het in het geval <strong>van</strong> <strong>verkeersborden</strong> onmogelijk is om een<br />
beeld te filteren zonder rekening te houden met de kleur. Daarom zullen we eerst wat<br />
dieper ingaan op RGB en HSV, twee zeer bekende methodes om kleuren weer te<br />
geven. Vervolgens bespreken we de methodes die tot het uiteindelijke resultaat<br />
hebben geleid.<br />
RGB-kleurenmodel<br />
RGB, de afkorting <strong>van</strong> Rood, Groen en Blauw, is een kleurenschema dat standaard wordt<br />
gebruikt voor de kleurweergave in videosystemen, filmapparatuur en computerschermen.<br />
RGB vertegenwoordigt alle kleuren die door de combinatie <strong>van</strong> rood, groen en blauw<br />
kunnen ontstaan.<br />
De beelden of foto’s in RGB zien er uit als een driedimensionale matrix. De matrix bestaat<br />
uit 3 lagen, die Rood, Groen en Blauw voorstellen. Elk <strong>van</strong> die lagen bevat een aantal rijen<br />
en kolommen. Als er bijvoorbeeld wordt gezegd: “de foto is 480 op 640”, dan wil dat<br />
zeggen dat er 3 tabellen op elkaar liggen met een grootte <strong>van</strong> 480 rijen en 640 kolommen.<br />
Elke positie heeft een waarde die dan wordt samengeteld om de exacte kleur te berekenen.<br />
Die waarden zijn meestal 8-bit zodat er een waarde tussen 0 en 255 kan worden gegeven.<br />
Het is uiteraard mogelijk om dat uit te breiden naar bijvoorbeeld 16 bits of meer. Maar hoe<br />
hoger het aantal bits wordt, hoe meer geheugen dat zal vragen voor de verwerking.<br />
Standaard wordt er met 8 bits gewerkt. Het aantal kleuren dat zo kan worden gevormd, is:<br />
256*256*256 = 16.777.216.<br />
De verhouding <strong>van</strong> de kleuren ten opzichte <strong>van</strong> elkaar kan het best worden aangetoond aan<br />
de hand <strong>van</strong> een kubus. In figuur 1 is de kubus weergegeven.<br />
Figuur 1 – Weergave verhouding kleuren t.o.v. elkaar (RGB)<br />
10
De kleuren hebben hier een maximale waarde <strong>van</strong> 1, maar dat kan gemakkelijk worden<br />
omgezet naar 255. De 6 vlakken <strong>van</strong> de kubus stellen alle kleuren voor die tussen de 8<br />
hoekpunten liggen.<br />
In figuur 2 zien we ook de kleuren die geen extreme waarden bezitten.<br />
Figuur 2 – Weergave kleurenpalet RGB<br />
Het RGB-model is het meest gebruikte kleurenschema voor het bekijken <strong>van</strong> en werken<br />
met digitale beelden op een scherm.<br />
HSV-kleurenmodel<br />
Het HSV-model is een veel gebruikt model om kleuren te definiëren. Net zoals bij het<br />
RGB-kleurenmodel hebben we hier een driedimensionele matrix, zodat we er niet verder<br />
op in zullen gaan. HSV, Hue, Saturation en Value zijn hier de drie waarden waarmee we<br />
kleuren definiëren.<br />
Hue, de kleurtint, heeft waarden <strong>van</strong> 0° tot 360°. De kleuren die voor ons belangrijk<br />
zijn: rood (0°) en blauw (240°) kunnen we hier gemakkelijk terugvinden. In<br />
MATLAB zijn die waarden tussen 0 en 1 gelegen.<br />
Saturation, verzadiging, heeft waarden tussen 0 en 1 (ook in MATLAB). Is die<br />
waarde 1, dan heb je de zuivere kleur. Naarmate we 0 naderen, krijgen we meer en<br />
meer grijs in onze kleur. Wanneer het S-vlak volledig 0 is, zien we geen verschil<br />
meer tussen rood en blauw.<br />
Value, brightness of kleursterkte, heeft waarden tussen 0 tot 1 (ook in MATLAB).<br />
Als de waarde dichter bij 1 komt, wordt de kleur lichter.<br />
De onderlinge relatie <strong>van</strong> de drie vlakken is visueel voorgesteld in figuur 3 en figuur 4.<br />
11
Figuur 3 – Kleurencirkel toont relatie tussen Hue, Saturation en Value (HSV)<br />
Figuur 3, de kleurencirkel, geeft de relatie weer <strong>van</strong> de 3 afzonderlijke vlakken.<br />
Een andere, veel gebruikte, manier om het HSV-kleurvlak visueel voor te stellen zien we in<br />
Figuur 4. Het geeft een conisch beeld. De Hue-waarde is de cirkel, wat verklaart waarom<br />
de Hue-waarde tussen 0° en 360° ligt. De Saturatie-waarde ligt <strong>van</strong> het middelpunt tot aan<br />
de rand <strong>van</strong> de cirkel. De Value-waarde wordt bepaald door de lengte ten opzichte <strong>van</strong> het<br />
onderste punt <strong>van</strong> de kegel.<br />
Als de Value-waarde 0 nadert, kunnen we duidelijk zien dat de andere 2 vlakken nog<br />
weinig invloed op de kleur hebben.<br />
Figuur 4 – Conische weergave <strong>van</strong> relatie tussen Hue, Saturation en Value (HSV)<br />
HSV-kleurfilter<br />
De eerste filter die we geprogrammeerd hebben, werd niet weerhouden in ons uiteindelijke<br />
herkenningssysteem. Toch willen we hem <strong>van</strong> naderbij voorstellen omdat de filter in<br />
bepaalde omstandigheden bijna perfect werkt.<br />
Bij de eerste filter hebben we geprobeerd rode en blauwe <strong>verkeersborden</strong> tegelijkertijd te<br />
herkennen. Later zijn we <strong>van</strong> dat principe afgestapt omdat de resultaten niet voldoende<br />
waren voor de eisen die we aan een kleurfilter stellen. De eerste filter is gebaseerd op het<br />
12
HSV-kleurenvlak. Aangezien het beeld dat we uit de camera ont<strong>van</strong>gen in RGB is, moeten<br />
we het beeld eerst naar het HSV-vlak converteren.<br />
a) Principe<br />
Verkeersborden hebben bijna altijd heldere kleuren. Als we dat naar het HSV-vlak<br />
vertalen, wil dat zeggen dat de waarden in het Saturation- en Value-vlak vrij hoog zijn.<br />
Wanneer we die twee vlakken optellen, verkrijgen we meestal een waarde die boven de 1,2<br />
ligt. We tellen dan nog het Hue-vlak bij de verkregen waarde op. Proefondervindelijk<br />
hebben we vastgesteld dat <strong>verkeersborden</strong> in bijna alle gevallen een samengetelde waarde<br />
hebben die groter is dan 1,6. Dat is de basis <strong>van</strong> onze eerste filter.<br />
De tabellen hebben we opgesteld aan de hand <strong>van</strong> de foto’s die we gebruiken om het<br />
programma te testen. Die foto’s staan ook op de bijgeleverde cd en ook op Appendix A.<br />
Tabel 1 geeft de HSV-waarden <strong>van</strong> verschillende <strong>verkeersborden</strong>, zowel rode als blauwe,<br />
weer.<br />
De kolom ‘Totaal’ is de som <strong>van</strong> de waarden <strong>van</strong> de eerste 3 kolommen. Teneinde de<br />
getallen te kunnen optellen, zetten we ze op schaal tussen 0 en 1. De Totaal kolom is <strong>van</strong><br />
hoog naar laag gesorteerd.<br />
Uit Tabel 1 kunnen we duidelijk afleiden dat de totale HSV-waarde in 29 <strong>van</strong> de 40<br />
gevallen (72,5%) boven de 1,6 uitkomt.<br />
BLAUWWAARDEN ROODWAARDEN<br />
H, in ° S, in % V, in % Totaal H, in ° S, in % V, in % Totaal<br />
202 100 96 2,521111 351 59 99 2,555<br />
197 95 99 2,487222 355 99 49 2,466111<br />
195 94 99 2,471666 342 70 54 2,19<br />
185 85 100 2,363888 357 68 51 2,181666<br />
207 86 91 2,345 347 54 62 2,123888<br />
189 82 100 2,345 20 99 100 2,045555<br />
198 93 59 2,07 350 59 45 2,012222<br />
203 94 53 2,033888 354 48 33 1,793333<br />
220 83 55 1,991111 8 91 82 1,752222<br />
210 84 55 1,973333 1 77 90 1,672777<br />
206 81 57 1,952222 1 64 99 1,632777<br />
210 80 53 1,913333 15 70 85 1,591666<br />
208 80 51 1,887777 6 79 77 1,576666<br />
222 90 36 1,876666 0 85 71 1,56<br />
219 64 62 1,868333 11 50 100 1,530555<br />
209 84 44 1,860555 6 56 81 1,386666<br />
222 73 50 1,846666 12 36 99 1,383333<br />
217 79 32 1,712777 4 66 49 1,161111<br />
231 68 22 1,541666 1 70 32 1,022777<br />
222 15 69 1,456666 1 61 33 0,942777<br />
Tabel 1 – HSV-waarden <strong>van</strong> verschillende <strong>verkeersborden</strong> (rood en blauw)<br />
b) Implementatie<br />
De filter is zo opgebouwd dat hij de waarde <strong>van</strong> elke pixel <strong>van</strong> de originele foto overloopt.<br />
Wanneer de opgetelde HSV-waarde <strong>van</strong> de pixel meer dan 1,6 bedraagt, krijgt de pixel op<br />
die plaats waarde 1. Is de waarde kleiner, dan wordt de waarde voor die pixel 0. De<br />
omzetting <strong>van</strong> de pixelwaarde doen we enkel op het H-vlak.<br />
13
We creëren zo een binair beeld: 1 is wit en 0 is zwart. Dat doen we om twee redenen:<br />
zichtbaarheid en snelheid.<br />
De zichtbaarheid is <strong>van</strong> minder belang. In onderstaande voorbeelden zien we duidelijk<br />
welke pixels een waarde boven de 1,6 hebben.<br />
Een belangrijker voordeel is de snelheid. Als we zelf een binair beeld aanmaken, hoeven<br />
we immers geen MATLAB-functie op te roepen om dat te doen. Het programma werkt<br />
sneller wanneer de waarden <strong>van</strong> de pixels uit zo weinig mogelijk bits bestaan. Door zelf het<br />
binair beeld aan te maken werden de 8 bits/pixel nu 1 bit/pixel. Zo bereiken we het<br />
minimumaantal bits per pixel.<br />
Dat betekent dat in 72,5% <strong>van</strong> de gevallen het verkeersbord niet door de filter wordt<br />
verwijderd, wat een foutenpercentage <strong>van</strong> 27,5% geeft. Het verkeersbord wordt, zoals we<br />
afleiden uit de Tabel 1, meestal verwijderd wanneer de roodwaarde erg laag is. Tabel 1<br />
toont ook aan dat dit een zeer geschikte filter voor de blauwwaarden is. Er zijn slechts 2<br />
gevallen die uit de boot vallen. Dat wil zeggen dat voor 90% de filter uitstekend werkt voor<br />
blauwe <strong>verkeersborden</strong>.<br />
c) Voorbeelden<br />
Voorbeeld 1<br />
Beeld 1 – Origineel beeld Beeld 2 – Beeld na HSV-kleurfilter<br />
Beeld 1 is genomen op een zonnige dag met een mooie blauwe lucht. Er is dus nog vrij veel<br />
wit op Beeld 2 te zien. Of de juiste figuren zullen worden gevonden, is nog maar de vraag.<br />
14
Voorbeeld 2<br />
Beeld 3 – Origineel beeld Beeld 4 – Beeld na HSV-kleurfilter<br />
Voor voorbeeld 2 werd het beeld bij valavond genomen (Beeld 3). We zien duidelijk dat<br />
de filter bijna perfect werkt om de blauwe en rode borden uit het beeld te isoleren (Beeld<br />
4). Zelfs enkele <strong>van</strong> de zeer kleine <strong>verkeersborden</strong> op de achtergrond worden door de filter<br />
gevonden. Er is ook weinig ruis op de achtergrond zodat Beeld 4 een perfect begin zou zijn<br />
om cirkels en driehoeken te detecteren.<br />
Voorbeeld 3<br />
Beeld 5 – Origineel beeld Beeld 6 – Beeld na HSV-kleurfilter<br />
Beeld 5 en Beeld 6 tonen aan dat het geen problemen zal opleveren om de driehoek in<br />
Beeld 5 te vinden.<br />
d) Conclusie<br />
Een pluspunt <strong>van</strong> deze methode is dat we met één filteractie zowel blauw als rood filteren.<br />
Daar tegenover staat dat deze filtermethode onvoldoende betrouwbaar is.<br />
15
Bij pakweg een mooie, zonnige dag liggen de Saturation- en Value-waarden <strong>van</strong> de<br />
omgeving vrij hoog. Het gevolg is dat er veel ruis op het beeld achterblijft. Denk ook aan<br />
een blauwe lucht die door de filter wordt gedetecteerd en in een wit vlak wordt omgezet.<br />
Is het een bewolkte dag of loopt het tegen valavond, dan kan de filter ook problemen<br />
opleveren. De Saturation- en Value-waarden <strong>van</strong> het verkeersbord zullen dan zo sterk<br />
gedaald zijn dat er wellicht weinig waarden boven de 1,6 uitkomen.<br />
Goede resultaten krijgen we bij een reflecterend verkeersbord tegen een donkere omgeving.<br />
Door de weerkaatsing zal de pixelwaarde <strong>van</strong> het verkeersbord namelijk ver boven de 1,6<br />
liggen. De donkere omgeving zal vooral waarden bevatten lager dan 1,6. Het<br />
foutenpercentage neemt dan snel af.<br />
Dus bij <strong>verkeersborden</strong> die door lichten worden beschenen en zodoende reflecteren, krijgen<br />
we zeer goede resultaten. Bij dergelijke omstandigheden werken andere filtermethodes dan<br />
weer minder goed. Toch hebben we er niet voor gekozen deze filter verder te gebruiken<br />
omdat de hierna volgende methodes over het algemeen beter scoren.<br />
Roodfilter<br />
Deze filter zal alleen de rode <strong>verkeersborden</strong> uit het beeld herkennen. Hij zal natuurlijk ook<br />
het rood dat op de achtergrond aanwezig is detecteren. Dit is de filter die we in ons<br />
uiteindelijke programma gebruiken. Met deze filter behaalden we bij zo’n 75% <strong>van</strong> de<br />
foto’s perfecte resultaten.<br />
Zoals bij de HSV-kleurfilter creëren we een binair beeld. De rode waarden worden in wit<br />
omgezet.<br />
a) Principe<br />
Na onderzoek op de rode kleur in <strong>verkeersborden</strong>, onder allerlei omstandigheden, is<br />
gebleken dat we dat vrij goed konden omlijnen. Zoals Tabel 2 aangeeft, liggen alle<br />
waarden tussen 340 en 360 of tussen 0 en 20. Als we dat naar MATLAB vertalen, krijgen<br />
we de waarden 0,944 en 1 of 0 en 0,055. Die waarden komen weinig op de achtergrond<br />
voor. Toch was het resultaat nog niet bevredigend genoeg, zodat we verder zijn blijven<br />
zoeken om de filter te perfectioneren.<br />
Als we dan ook nog eens het S-vlak <strong>van</strong> dichterbij bekijken, zien we dat er maar drie<br />
waarden onder 50 zitten. We hebben dan ook die parameter in de voorwaarde gestopt. De<br />
S-parameter is <strong>van</strong> groot belang om rood uit de achtergrond weg te filteren.<br />
Verkeersborden zijn reflecterend en zullen dan ook altijd een bepaalde hoeveelheid licht<br />
reflecteren. Bij bomen of rode huizen is die kans veel kleiner. Maar zoals we in Voorbeeld<br />
1 waarnemen, kunnen we natuurlijk nooit met 100% zekerheid voorspellen dat die<br />
parameter de omgeving volledig zal negeren. We kunnen die parameter ook niet verhogen,<br />
want dan is de kans te groot dat we ook ons verkeersbord niet meer detecteren.<br />
16
H, in ° S, in % V, in % H, in ° S, in % V, in %<br />
359 86 98 343 82 42<br />
358 87 61 342 70 54<br />
358 82 62 342 69 37<br />
357 68 51 340 47 90<br />
357 58 100 20 99 100<br />
356 74 92 18 81 100<br />
356 58 31 15 76 93<br />
356 90 68 14 83 100<br />
355 89 98 14 79 100<br />
355 81 27 12 36 99<br />
355 99 49 11 65 100<br />
355 81 38 10 100 44<br />
354 66 98 9 73 96<br />
354 48 33 8 85 99<br />
352 78 94 8 91 82<br />
352 93 60 6 56 81<br />
352 57 91 6 79 77<br />
351 59 99 5 96 78<br />
350 59 45 4 66 49<br />
350 94 53 4 100 77<br />
349 74 48 1 64 99<br />
349 90 55 1 77 90<br />
347 54 62 1 70 32<br />
347 75 43 1 61 33<br />
345 78 26 1 71 29<br />
344 69 39 1 93 38<br />
344 58 49 0 85 71<br />
343 58 61 0 83 80<br />
Tabel 2 – HSV-waarden voor rode <strong>verkeersborden</strong><br />
b) Implementatie<br />
Het programma werkt ongeveer analoog zoals bij de HSV-kleurfilter beschreven staat. We<br />
bekijken alle pixels apart en voldoen ze aan de twee voorwaarden zoals hierboven<br />
beschreven, dan zetten we die positie op 1. Voldoen ze er niet aan, dan zetten we die<br />
positie op 0. Zo krijgen we een binair beeld waar de witte velden het rood voorstellen.<br />
17
c) Voorbeelden<br />
Voorbeeld 1<br />
Beeld 7 – Origineel beeld Beeld 8 – Beeld na roodfilter<br />
In dit voorbeeld zien we duidelijk waar de meeste problemen kunnen voorkomen met een<br />
filter die zich op de rode kleur concentreert. Aan de rechterkant <strong>van</strong> Beeld 7 staat een rood<br />
huis dat door de filter wordt gedetecteerd. Bij Beeld 8 zien we duidelijk de contouren <strong>van</strong><br />
het huis. Bij de verdere verwerking kan dat problemen opleveren: er zullen meerdere<br />
virtuele driehoeken en cirkels worden gevonden in de muur, wat een vertraging <strong>van</strong> het<br />
programma zal veroorzaken.<br />
Voorbeeld 2<br />
Beeld 3 – Origineel beeld Beeld 9 – Beeld na roodfilter<br />
Beeld 3 is hetzelfde als bij de HSV-kleurfilter. We zien duidelijk het verschil tussen Beeld<br />
4 (bij HSV-kleurfilter) en dit Beeld 9. De blauwe <strong>verkeersborden</strong> komen totaal niet terug in<br />
Beeld 9. Alle rode driehoeken, inclusief de zeer kleine borden worden nu wel duidelijk<br />
gevonden, wat in Beeld 4 niet het geval was.<br />
18
Voorbeeld 3<br />
Beeld 10 – Origineel beeld Beeld 11 – Beeld na roodfilter<br />
Bij Beeld 10 zien we duidelijk dat wanneer er geen rode omgevingsinvloeden zijn en het<br />
verkeersbord groot is, de filter de perfectie benaderd.<br />
d) Conclusie<br />
Deze methode geeft zeer bevredigende resultaten in bijna alle weersomstandigheden. Er<br />
kunnen natuurlijk ook problemen voorkomen wanneer de <strong>verkeersborden</strong> verwaarloosd<br />
zijn en er bijvoorbeeld mos op groeit of er een grote deuk in zit. Die deuk geeft dan een<br />
schaduw, wat voor de filter zwart is, en zal dan niet als een stuk <strong>van</strong> het verkeersbord<br />
worden gedetecteerd.<br />
Deze filter gebruiken we in ons uiteindelijke programma en geeft in 75% <strong>van</strong> de gevallen<br />
een bevredigend resultaat.<br />
Blauwfilter<br />
Omdat we de rode borden apart detecteren, is het noodzakelijk dat ook voor de blauwe<br />
<strong>verkeersborden</strong> te doen. De blauwfilter werkt op dezelfde manier als de roodfilter en haalt<br />
ook zeer goede resultaten.<br />
a) Principe<br />
Tabel 3 bevat de waarden <strong>van</strong> HSV voor de blauwe <strong>verkeersborden</strong>. De foto’s die we<br />
gebruiken om de tabel op te stellen zijn in allerlei weersomstandigheden genomen. We<br />
hebben er ook op gelet om de verschillende schakeringen <strong>van</strong> blauw te testen.<br />
De waarden liggen in 100% <strong>van</strong> de gevallen tussen de 185 en de 240. Als we dat naar<br />
MATLAB-waarden omzetten, verkrijgen we 0,514 en 0,667.<br />
We kiezen hier voor 100% omdat de kleuren in de omgeving zelden tussen de<br />
vooropgestelde waarden liggen.<br />
Verder hebben we ook nog een restrictie op het S-vlak doorgevoerd. De waarde moet<br />
boven de 0,5 liggen. In ons geval wil dat zeggen dat twee borden hier niet aan de<br />
voorwaarden voldoen.<br />
19
H, in ° S, in % V, in % H, in ° S, in % V, in %<br />
240 54 26 209 84 44<br />
231 68 22 207 86 91<br />
224 95 45 206 81 57<br />
222 15 69 206 91 80<br />
222 73 50 203 94 53<br />
222 90 36 202 100 96<br />
220 83 55 198 93 59<br />
219 64 62 197 95 99<br />
217 79 32 195 94 99<br />
216 36 66 189 82 100<br />
210 84 55 185 85 100<br />
210 80 53<br />
Tabel 3 – HSV-waarden voor blauwe <strong>verkeersborden</strong><br />
b) Implementatie<br />
We gaan niet verder op de implementatie in, want die is dezelfde als bij de roodfilter. We<br />
hoeven enkel de voorwaarden aan te passen.<br />
c) Voorbeelden<br />
Voorbeeld 1:<br />
Beeld 3 – Origineel beeld Beeld 12 – Beeld na blauwfilter<br />
We bekijken het filterresultaat (Beeld 12) <strong>van</strong> het bekende Beeld 3 en stellen vast dat het<br />
rode bord niet meer wordt gedetecteerd. Ook de blauwe borden worden door de felle<br />
verlichting niet erg goed gedetecteerd. We merken eveneens dat de kleine <strong>verkeersborden</strong>,<br />
linksonder op de foto, volledig wit worden weergegeven. De grote borden zullen echter<br />
probleemloos worden gedetecteerd.<br />
20
Voorbeeld 2<br />
Beeld 13 – Origineel beeld Beeld 14 – Beeld na blauwfilter<br />
Beeld 13 en Beeld 14 illustreren een perfect gedetecteerd bord.<br />
Voorbeeld 3<br />
Beeld 15 – Origineel beeld Beeld 16– Beeld na blauwfilter<br />
Ook hier zien we dat alle blauwe borden, hoe klein ook, perfect worden gedetecteerd.<br />
21
Voorbeeld 4<br />
Beeld 17 – Origineel beeld Beeld 18 – Beeld na blauwfilter<br />
Speciale aandacht hadden we ook voor de invloed <strong>van</strong> een blauwe lucht op de <strong>detectie</strong>.<br />
Beeld 17 heeft zo’n lucht. We hebben kunnen vaststellen dat de filter daar geen problemen<br />
mee heeft.<br />
d) Conclusie<br />
De filter werkt zeer goed onder alle omstandigheden. Dit is dan ook de filter die we in ons<br />
uiteindelijke programma gebruiken. We hebben ons hoofdprogramma in twee delen<br />
opgesplitst. Eerst filteren we het originele beeld met de roodfilter en zoeken we naar de<br />
rode <strong>verkeersborden</strong>, vervolgens herhalen we hetzelfde proces met de blauwfilter.<br />
De blauwfilter werkt zeer goed in 81% <strong>van</strong> de geteste gevallen.<br />
Witfilter<br />
De witfilter gebruiken we enkel bij de classificatie <strong>van</strong> <strong>verkeersborden</strong> (zie hoofdstuk 7:<br />
classificatie). We gebruiken het daar niet in de term <strong>van</strong> filteren, maar we tellen de pixels<br />
die voldoen aan de eisen om wit te zijn teneinde meer informatie over de binnenkant <strong>van</strong><br />
het verkeersbord te verkrijgen. We zullen kort bespreken hoe we de witte vlakken in ons<br />
beeld terugvinden. Daarna bekijken we nog enkele voorbeelden.<br />
a) Principe<br />
Voor de classificatie <strong>van</strong> de borden is het belangrijk dat we de witte kleur kunnen<br />
terugvinden. Bij het zoeken naar wit kunnen we geen gebruik maken <strong>van</strong> het Hue-vlak<br />
zoals we hiervoor wel hebben gedaan, dus drong een andere oplossing zich op: het RGBkleurschema.<br />
Tabel 4 bestaat uit de R-, G- en B-waarden <strong>van</strong> <strong>verkeersborden</strong> die wit bevatten. Daarmee<br />
bedoelen we binnen de rode of blauwe rand. De kolom ‘Gemiddeld’ bevat de gemiddelde<br />
waarden <strong>van</strong> de eerste drie kolommen. De laatste kolom is het Saturation-vlak <strong>van</strong> HSV.<br />
We hebben verschillende <strong>verkeersborden</strong> getest en Tabel 4 toont enkele verkregen<br />
22
waarden. De geteste <strong>verkeersborden</strong> bevinden zich op de bijgeleverde cd en ook op<br />
Appendix A.<br />
Als we Tabel 4 <strong>van</strong> naderbij bekijken, kunnen we vaststellen dat de waarden voor de aparte<br />
vlakken, R, G en B, zeer dicht bij elkaar liggen. In eerste instantie kijken we of de<br />
gemiddelde waarde hoger is dan 100. Voor de geregistreerde waarden, weergegeven in<br />
Tabel 4 is dat altijd zo, met een enkele verwaarloosbare uitzondering.<br />
De volgende stap bestaat erin de gemiddelde waarde naast de aparte RGB-waarden te<br />
leggen. De afzonderlijke RGB-waarden mogen niet meer dan 10 verschillen met de<br />
gemiddelde waarde. Uit Tabel 4 kunnen we afleiden dat dit in 90% (29 <strong>van</strong> de 32) <strong>van</strong> de<br />
resultaten zo is.<br />
De laatste voorwaarde die we stellen, is dat de Saturation-waarde kleiner moet zijn dan 15.<br />
Dat is niet zo in twee resultaten <strong>van</strong> Tabel 4, maar bij één <strong>van</strong> die twee werd ook de eerste<br />
voorwaarde niet vervuld.<br />
De resultaten in Tabel 4 geven 5 beelden <strong>van</strong> de 32 die niet aan de voorwaarden voldoen,<br />
wat neerkomt op een positief resultaat waarbij wit wordt gevonden <strong>van</strong> 87,5%.<br />
R G B Gemiddeld S<br />
100 104 115 106 31<br />
182 188 184 185 27<br />
185 194 191 190 19<br />
240 240 242 241 19<br />
127 143 156 142 15<br />
233 234 226 231 13<br />
190 188 191 190 12<br />
162 161 156 160 11<br />
166 169 178 171 8<br />
151 151 143 148 7<br />
139 136 131 135 7<br />
204 201 192 199 7<br />
254 253 248 252 7<br />
243 239 236 239 6<br />
255 255 255 255 6<br />
255 255 253 254 6<br />
100 107 117 108 6<br />
127 123 120 123 6<br />
128 137 136 134 5<br />
255 254 253 254 5<br />
107 111 114 111 5<br />
251 255 255 254 5<br />
117 119 114 117 5<br />
111 116 112 113 5<br />
86 92 82 87 4<br />
165 163 164 164 4<br />
220 230 231 227 4<br />
159 157 162 159 4<br />
144 154 163 154 3<br />
248 248 248 248 3<br />
152 186 221 186 3<br />
248 247 245 247 3<br />
165 167 153 162 3<br />
247 247 247 247 2<br />
247 247 247 247 2<br />
23
103 124 141 123 2<br />
102 107 110 106 1<br />
220 226 226 224 1<br />
131 141 133 135 1<br />
114 120 116 117 1<br />
120 125 121 122 1<br />
109 114 108 110 1<br />
255 255 255 255 0<br />
255 255 255 255 0<br />
255 254 255 255 0<br />
128 129 123 127 0<br />
159 154 150 154 0<br />
Tabel 4 – Witwaarden in het RGB- en S-vlak<br />
b) Voorbeelden<br />
We tonen hier enkele voorbeelden die we op geëxtraheerde beelden toepassen. We nemen<br />
niet de originele foto’s omdat we deze filter in ons programma enkel op geëxtraheerde<br />
beelden gebruiken. Hoe we beelden precies uit ons beeld extraheren, verklaren we in de<br />
komende hoofdstukken.<br />
Voorbeeld 1<br />
Beeld 19 – Geëxtraheerd beeld Beeld 20 – Na toepassing witfilter<br />
We zien in voorbeeld 1 dat enkel de witte vlakken wit blijven. De rest wordt zwart.<br />
Voorbeeld 2<br />
Beeld 21 – Geëxtraheerd beeld Beeld 22 – Na toepassing witfilter<br />
Voorbeeld 2 toont ook duidelijk aan dat alleen de witte vlakken nog wit zijn.<br />
24
Zwartfilter<br />
Net als bij de witfilter hebben we deze filter alleen nodig voor de classificatie <strong>van</strong> de<br />
<strong>verkeersborden</strong>. Hoe we deze filter toepassen, bespreken we in het hoofdstuk classificatie.<br />
Wij gaan dieper in op hoe we zwarte vlakken in ons beeld terugvinden. Daarna bekijken we<br />
nog enkele voorbeelden.<br />
a) Principe<br />
In tegenstelling tot de vorige filters veranderen we de kleur die we zoeken niet in wit, maar<br />
in zwart. Dat doen we enkel om het zo visueel mogelijk te maken.<br />
Net zoals bij de witfilter gebruiken we het RGB-kleurschema.<br />
We hebben opnieuw een tabel gemaakt (Tabel 5) <strong>van</strong> verschillende zwarte waarden die we<br />
in het verkeersbord zijn tegengekomen. De <strong>verkeersborden</strong> waarop we hebben getest,<br />
bevinden zich op de bijgevoegde cd en ook op Appendix A.<br />
In Tabel 5 kunnen we makkelijk vaststellen dat bijna alle waarden <strong>van</strong> de drie aparte<br />
vlakken lager zijn dan 100. Dat is dan ook de eerste voorwaarde die we stellen. Er is slechts<br />
één resultaat dat niet aan deze voorwaarde beantwoordt.<br />
In tegenstelling tot de witfilter kunnen we deze waarden niet met de gemiddelde waarde<br />
vergelijken. Te veel zwarte stukken zouden wit worden en bijgevolg zouden we te veel<br />
informatie verliezen.<br />
Toch kunnen we nog een restrictie op het S-vlak invoeren. Zoals Tabel 5 aantoont, zijn er<br />
slecht twee borden waar<strong>van</strong> de S-waarde boven de 50 ligt.<br />
Wanneer we beide beperkingen doorvoeren, verliezen we volgens Tabel 5 bij twee <strong>van</strong> de<br />
21 resultaten informatie over het aanwezig zijn <strong>van</strong> zwart in een verkeersbord. Dat wil<br />
zeggen dat we in 90% de juiste vlakken zwart maken<br />
R G B S<br />
32 36 39 56<br />
0 4 0 48<br />
19 21 18 46<br />
91 94 87 43<br />
59 25 31 38<br />
60 51 56 36<br />
100 107 136 26<br />
15 17 16 25<br />
84 82 85 25<br />
33 29 17 18<br />
58 58 68 15<br />
82 87 83 15<br />
44 43 48 14<br />
12 14 9 12<br />
25 26 46 12<br />
43 56 75 11<br />
56 55 61 10<br />
45 24 12 10<br />
18 24 24 7<br />
36 32 33 6<br />
0 2 8 4 Tabel 5 – Zwartwaarden in het RGB- en S-vlak<br />
25
) Voorbeelden<br />
Voorbeeld 1<br />
Beeld 23 – Geëxtraheerd beeld Beeld 24 – Na toepassing zwartfilter<br />
In voorbeeld 1 zien we duidelijk dat alleen de vrachtwagen in het midden <strong>van</strong> het beeld nog<br />
zwart is. De rest is wit gemaakt door de zwartfilter.<br />
Voorbeeld 2<br />
Beeld 25 – Geëxtraheerd beeld Beeld 26 – Na toepassing zwartfilter<br />
In dit tweede voorbeeld zien we ook duidelijk dat er nog weinig zwarte vlakken<br />
overblijven. De pijl in het midden <strong>van</strong> het verkeersbord is zeer duidelijk zichtbaar.<br />
26
Hoofdstuk 2: Edge <strong>detectie</strong><br />
Edge <strong>detectie</strong> is de tweede stap in ons <strong>detectie</strong>proces waarbij we de randen <strong>van</strong> ons<br />
verkeersbord willen herkennen. Hiervoor bestaan verschillende methodes, denk aan<br />
Prewitt, Robert, Sobel, Canny, enz. Na uitvoerige tests zijn we tot de conclusie<br />
gekomen dat Sobel en Canny de twee meest geschikte methodes zijn voor onze<br />
toepassing.<br />
Beide methodes hebben we nog dieper onderzocht en tegenover elkaar geplaatst<br />
teneinde een gefundeerde beste keuze te kunnen maken.<br />
Algemeen<br />
Het eerste wat we ons moeten afvragen is: wat is een rand? Een rand is in feite niets anders<br />
dan een verandering <strong>van</strong> kleur of intensiteit tussen twee vlakken. Het menselijk oog is zeer<br />
bedreven in het herkennen <strong>van</strong> randen en figuren, zo bedreven dat er nog niemand in<br />
geslaagd is te begrijpen hoe we dat doen. Er bestaan twee hoofdredenen waarom de mens<br />
zo goed randen kan zien. Ten eerste is er het stereoscopisch beeld [3]. We hebben twee<br />
ogen, waardoor we een goed dieptezicht verkrijgen en gemakkelijk afstanden kunnen<br />
inschatten bij driedimensionale beelden. Ten tweede, we hebben ook de kwaliteit om<br />
randen te zien die er niet zijn. Als een rond verkeersbord bijvoorbeeld maar voor de helft te<br />
zien is omdat er een boom voor staat, zullen wij aan die ene helft genoeg hebben om te<br />
weten dat het om een cirkel gaat.<br />
Voor de computer is dat een zeer delicaat probleem. De computer heeft geen<br />
stereoscopisch beeld, alles is één matrix en de technologie staat nog niet zo ver dat de<br />
computer al vergevorderde conclusies kan trekken. De bestaande edge detectoren hebben<br />
een wiskundige basis en werken voor de meeste toepassingen naar behoren. Na een eerste<br />
onderzoek hebben we besloten dat Sobel en Canny voor onze toepassing de meest<br />
aangewezen keuze is. We bespreken ze hierna beknopt.<br />
Sobel<br />
Sobel is een vrij eenvoudige, maar zeer goed werkende randdetector. Hij wordt in vele<br />
toepassingen gebruikt.<br />
Sobel gebruikt twee convolutiekernen, die identiek zijn, maar 90° gedraaid zijn ten<br />
opzichte <strong>van</strong> elkaar. Figuur 1 toont de kernen.<br />
Figuur 1 – Voorstelling convolutiekernen bij Sobel<br />
27
Gx zal de verticale contrasten detecteren, Gy de horizontale. De kernen worden over het<br />
beeld geschoven en bekijken pixel per pixel. Aan de hand <strong>van</strong> deze twee kernen creëren we<br />
een gradiënt vector: g.<br />
De waarde g is de magnitude <strong>van</strong> de gradiënt. g wordt in de meest gevallen berekend uit de<br />
absolute waarden <strong>van</strong> Gx en Gy. Die bewerking is veel sneller dan de vierkantswortel te<br />
nemen <strong>van</strong> beide kwadraten. g is meestal het enige resultaat dat de gebruiker te zien krijgt.<br />
Het belang <strong>van</strong> θ is de oriëntatie <strong>van</strong> de kleurverandering. Wanneer θ = 0 wil dat zeggen<br />
dat het maximale contrast (zwart naar wit) <strong>van</strong> links naar rechts over het beeld loopt. Alle<br />
andere contrasten hebben een hoek die tegen wijzerzin is gedefinieerd.<br />
De Sobel edge detector werkt zeer goed, maar er zijn ook nadelen aan het gebruik <strong>van</strong><br />
Sobel verbonden.<br />
In MATLAB heeft de Sobel edge detector enkele parameters die we zelf kunnen instellen.<br />
De belangrijkste is de threshold. Randen die niet groter zijn dan de threshold, de gradiënt is<br />
niet groot genoeg, worden genegeerd en niet als rand gedetecteerd. Als we de threshold niet<br />
parametriseren, wordt die door MATLAB zelf gekozen.<br />
De richting <strong>van</strong> het zoeken naar randen, horizontaal of verticaal, kan ook worden gekozen.<br />
Die parameter hebben we niet ingevuld want de defaultwaarde is beide richtingen, wat<br />
nodig is voor onze toepassing.<br />
De thresholdwaarde hebben we experimenteel vastgelegd. De waarden kunnen tussen 0 en<br />
1 liggen. Na enkele oppervlakkige testen hebben we vastgesteld dat de defaultwaarde, 0,1<br />
en 0,05 voor onze toepassing de beste resultaten gaven.<br />
In Tabel 1 vergelijken we de drie eerder genoemde waarden met elkaar. We hebben de<br />
grafieken opgesteld aan de hand <strong>van</strong> de foto’s waar we ons herkenningssysteem op getest<br />
hebben. Die foto’s staan op de bijgeleverde cd en ook op Appendix A.<br />
Alle drie de waarden hadden bevredigende resultaten, maar om het systeem te<br />
optimaliseren hebben we ze grondig met elkaar vergeleken. Alleen de beste waarden<br />
hebben we onthouden en weergegeven in de tabel. Met de beste waarde bedoelen we de<br />
waarde waar het verkeersbord het best zichtbaar is en waar er het minst ruis op het<br />
verkregen beeld aanwezig is. De verschillen zijn soms minimaal.<br />
Wanneer we de threshold parameter op 0,1 instellen is dat in 90% <strong>van</strong> de geteste gevallen<br />
voor Sobel de beste waarde. Het spreekt voor zich dat we die waarde kiezen.<br />
default 0.1 0.05<br />
6% 90% 4%<br />
Tabel 1 – Vergelijken <strong>van</strong> de thresholdwaarde voor Sobel.<br />
28
Sobel is zeer gevoelig voor ruis in het beeld. Alle ruis wordt door Sobel als een rand<br />
herkend zodat we vele randen detecteren die voor onze toepassing overbodig zijn. Wij<br />
werken altijd met beelden die onderhevig zijn aan ruis zodat dit een groot probleem kan<br />
vormen.<br />
Canny<br />
De Canny edge detector staat bekend als de meest optimale onder de edge detectors. Hij<br />
werd ontworpen door John Canny die vond dat de bestaande randdetectoren niet goed<br />
genoeg waren voor de eisen die hij stelde. Zijn edge detector voldoet aan drie criteria.<br />
Het eerste criterium is voor de hand liggend: zo weinig mogelijk fouten maken, slechts een<br />
rand detecteren wanneer er een is.<br />
Volgens het tweede criterium moeten de randpunten goed worden gevonden, wat neerkomt<br />
op een minimale afstand tussen de gedetecteerde rand met de Canny detector en de<br />
werkelijke rand.<br />
Het derde criterium stelt dat er alleen een rand mag worden gedetecteerd wanneer er een<br />
alleenstaande rand is. Met alleenstaande rand bedoelen we een rand die niet omgeven is<br />
door andere randen.<br />
De Canny edge <strong>detectie</strong> bestaat uit 6 stappen. We zullen de stappen overlopen om een beter<br />
inzicht te krijgen hoe Canny precies werkt.<br />
Stap 1<br />
In de eerste stap wordt er zoveel mogelijk ruis <strong>van</strong> het originele beeld verwijderd<br />
door een masker over het beeld te laten lopen. Het masker is een Gaussian filter, die<br />
wordt bepaald door de parameter σ. De werking <strong>van</strong> dit masker is vergelijkbaar met<br />
de werking <strong>van</strong> de twee convolutiekernen <strong>van</strong> Sobel. Figuur 2 geeft een voorbeeld<br />
<strong>van</strong> zo’n Gaussian filter die werd berekend met σ=1,4. Als we de parameter<br />
aanpassen, zal dzt een andere Gauss matrix tot gevolg hebben.<br />
Hoe groter de breedte <strong>van</strong> het masker, hoe minder gevoelig de Gaussian detector is<br />
voor ruis.<br />
Figuur 2 – Gaussian convolutiekernen<br />
29
Stap 2 en 3<br />
Deze stappen zijn dezelfde als bij Sobel. Dezelfde convolutiekernen worden<br />
gebruikt en dezelfde berekeningen worden gemaakt. De magnitude en θ worden<br />
berekend.<br />
Stap 4<br />
De θ waarde aanpassen tot een waarde waar we goed mee kunnen werken. Een<br />
pixel omgeven door andere pixels kan maar vier richtingen hebben: 0°, 45°, 90° en<br />
135°. Nu gaan we kijken bij welke <strong>van</strong> die vier hoeken de originele θ waarde ligt<br />
om die dan gelijk te stellen aan een <strong>van</strong> de vier vooropgestelde waarden.<br />
Stap 5<br />
In de vijfde stap onderdrukken we alle randen die niet aan de eisen voldoen. Anders<br />
gezegd, we stellen ze gelijk aan 0.<br />
Stap 6<br />
In de laatste stap proberen we aan de hand <strong>van</strong> twee thresholdwaarden het beeld te<br />
verbeteren. Wanneer de waarde <strong>van</strong> de gradiënt boven T2 komt, de grootste<br />
thresholdwaarde, wordt dat als een rand gezien. De detector loopt nu verder over het<br />
beeld en zal alles als een rand detecteren totdat de gradiëntwaarde beneden T1<br />
komt. Om een lijn te vormen, hebben we dus een waarde nodig die boven T2 komt<br />
om te starten. De rand loopt door tot we een waarde beneden T1 bekomen. Zo komt<br />
het dat een lijn die bij Sobel uit puntjes bestaat een volle lijn wordt bij Canny.<br />
Dat zijn de 6 stappen die de Canny edge detector gebruikt, wat heel wat uitgebreider is dan<br />
bij Sobel.<br />
Er zijn drie parameters die we in MATLAB kunnen instellen: σ en de twee thresholds. De<br />
sigmawaarde laten we op 1 staan, dat had de beste resultaten tijdens de tests. De T1-waarde<br />
wordt door MATLAB op 0,4 gekozen, wat tijdens de tests zeer goede resultaten opleverde.<br />
De T2-waarde kiezen we zelf. In Tabel 2 kunnen we de resultaten <strong>van</strong> een uitgebreide test<br />
zien.<br />
Eerst bepaalden we na een oppervlakkige test de waarden waarbij 0,9, 0,95 en 0,99 de beste<br />
resultaten gaven. Vervolgens hadden we nood aan een dieper onderzoek om de allerbeste<br />
waarde te vinden teneinde de meest perfecte waarde voor onze toepassing te bepalen. De<br />
criteria waarop we testen, zijn dezelfde als bij Sobel: zichtbaarheid <strong>van</strong> het verkeersbord en<br />
de hoeveelheid ruis die nog op de foto overblijft.<br />
0.9 0.95 0.99<br />
10% 16% 74%<br />
Tabel 2 – Vergelijken <strong>van</strong> de thresholdwaarde voor Canny<br />
Onze uiteindelijke keuze is op 0,95 gevallen. Dat kan misschien verassend lijken, want<br />
0,95 is in 16% <strong>van</strong> de gevallen de beste keuze, maar het verschil tussen 0,95 en 0,99 was<br />
minimaal. Bij 0,99 hadden we minder ruis, maar het verkeersbord werd soms minder goed<br />
gedetecteerd. We verkiezen de zekerheid om geen informatie te verliezen boven iets<br />
minder ruis in ons beeld.<br />
30
Canny of Sobel<br />
De keuze tussen Canny of Sobel hebben we niet alleen op de theoretische achtergrond <strong>van</strong><br />
beide methodes gebaseerd. Theoretisch zou de keuze op Canny vallen. Canny heeft een<br />
veel betere ruisonderdrukking door eerst het beeld ‘gladder’ te maken. De bewerkingen die<br />
na de randherkenning komen, zijn ook meer uitgewerkt.<br />
We hebben dat uitgebreid getest omdat we 100% zekerheid willen over de juiste keuze. De<br />
keuze <strong>van</strong> filter en edge <strong>detectie</strong> is immers cruciaal voor het verdere verloop <strong>van</strong> ons<br />
herkenningssysteem.<br />
Tabel 3 toont de vergelijking tussen Sobel en Canny. Beide beelden worden op basis <strong>van</strong><br />
de eerder vermelde eisen vergeleken. We gebruiken voor beide methodes de parameters die<br />
we verkregen hebben.<br />
Canny Sobel<br />
74% 26%<br />
Tabel 3 – Vergelijking tussen Canny en Sobel<br />
Uit Tabel 3 blijkt dat Canny de beste resultaten biedt voor 74% <strong>van</strong> de onderzochte<br />
beelden. Er is veel minder ruis aanwezig op het beeld, maar soms vinden we het bord<br />
minder goed terug. We hebben ons in het begin dan ook op de Canny edgde detector<br />
gebaseerd.<br />
Morfologische bewerkingen<br />
Ondanks de theoretische onderbouw en de positieve praktische testen waaruit Canny als<br />
beste keuze naar voren kwam, zijn we verschillende problemen met Canny tegengekomen.<br />
Zo verloren de geometrische figuren soms iets te veel informatie. Bij Sobel ondervonden<br />
we dat probleem niet. Ook bij rand<strong>detectie</strong> <strong>van</strong> driehoekige <strong>verkeersborden</strong> kwamen we<br />
dezelfde problemen tegen: soms verdween een volledige lijn <strong>van</strong> de driehoek.<br />
Daarom waren we genoodzaakt terug te grijpen naar Sobel. Natuurlijk moesten we een<br />
oplossing vinden voor de ruis die bij Sobel nog aanwezig was. Een voor de hand liggende<br />
oplossing is de ruis onderdrukken na de rand<strong>detectie</strong>. De toolbox <strong>van</strong> MATLAB biedt een<br />
groot aantal mogelijkheden om morfologische bewerkingen uit te voeren op het beeld. Dat<br />
zijn bewerkingen die het beeld op pixelniveau aanpassen.<br />
Uit de vele mogelijkheden hebben we experimenteel vastgesteld welke combinatie <strong>van</strong><br />
bewerkingen naar onze mening de beste resultaten oplevert. Hierna bespreken we de<br />
weerhouden morfologische bewerkingen.<br />
a) ‘skel’<br />
Deze operatie verwijdert pixels die aan de grens <strong>van</strong> een object liggen. Een object is<br />
een groep <strong>van</strong> pixels die samenhoren, bijvoorbeeld een lijn, een cirkel. Skel zorgt<br />
ervoor dat het object niet kan uiteenvallen. Voor onze toepassing is het belangrijk<br />
dat de objecten een geheel blijven vormen.<br />
Het voordeel is dat de randen minder ruis bevatten en dat er globaal gezien minder<br />
pixels op het beeld staan. Het is belangrijk het aantal pixels te verminderen met het<br />
oog op het vinden <strong>van</strong> geometrische figuren in onze volgende stappen.<br />
31
) ‘bwareaopen’<br />
Dit is een zeer belangrijke functie. Deze functie verwijdert objecten die minder dan<br />
een bepaald aantal pixels bevatten. Het aantal pixels is een parameter die we zelf<br />
kunnen kiezen. Wij hebben dat op 50 gezet. Vijftig pixels gaf volgens ons de beste<br />
resultaten. Uiteraard hebben we uitvoerig onderzoek gedaan naar dat aantal.<br />
Dankzij deze functie worden een groot aantal pixels verwijderd die niets met<br />
<strong>verkeersborden</strong> te maken hebben. De <strong>verkeersborden</strong> die wij in het verdere<br />
programma kunnen detecteren, moeten groter zijn dan 50 pixels. Immers, wanneer<br />
het bord te klein is, kunnen we er in een verder stadium onvoldoende gegevens uit<br />
distilleren om tot de uiteindelijke classificatie te komen.<br />
c) ‘clean’<br />
Deze functie verwijdert pixels die alleen staan. Figuur 4 geeft een voorbeeld. De 1<br />
zal na afloop een 0 geworden zijn. Een 1 pixel is wit, een 0 zwart. De witte pixels<br />
hebben we later nodig om de geometrische figuren te zoeken.<br />
0 0 0 0 0 0<br />
0 1 0 0 0 0<br />
0 0 0 0 0 0<br />
Figuur 4 – Voorbeeld ‘clean’<br />
Deze functie is belangrijk omdat er geregeld alleenstaande pixels opduiken. Zoals<br />
eerder vermeld is het de bedoeling zoveel mogelijk niet rele<strong>van</strong>te pixels uit ons<br />
beeld te verwijderen.<br />
d) ‘fill’<br />
Deze functie maakt <strong>van</strong> een 0 pixel die omgeven is door een 1 pixel een 1. Figuur 5<br />
illustreert dat.<br />
1 1 1 1 1 1<br />
1 0 1 1 1 1<br />
1 1 1 1 1 1<br />
Figuur 5 – Voorbeeld ‘fill’<br />
Deze bewerking lijkt eerder vreemd omdat we een 1 pixel toevoegen. We doen deze<br />
operatie omdat wanneer een 0 pixel door een 1 omgeven is, dat meestal in een rand<br />
is. Dan hebben we een pixel meer in de rand en zo kunnen we later makkelijker<br />
lijnen vinden, maar daarover meer in de volgende hoofdstukken.<br />
Na deze bewerkingen verkrijgen we zeer goede resultaten met Sobel. Aan de hand<br />
<strong>van</strong> enkele voorbeelden zullen we dieper op de verschillen tussen beide ingaan en<br />
de definitieve keuze voorstellen.<br />
32
Voorbeelden<br />
Voorbeeld 1<br />
Beeld 1 – Origineel beeld<br />
Beeld 1 is het originele beeld. Daarop passen we de roodfilter toe. Daarna zien we de vier<br />
keuzes die we hebben: Sobel, Canny of een <strong>van</strong> beide met de hierboven opgesomde<br />
morfologische operaties.<br />
Beeld 2 – Edge <strong>detectie</strong> met Sobel (threshold = 0,1)<br />
Op Beeld 2 hebben we alleen Sobel (threshold = 0,1) toegepast. De twee <strong>verkeersborden</strong><br />
zijn vrij goed te onderscheiden, maar er is wel wat ruis op het beeld aanwezig. Het<br />
33
driehoekige verkeersbord bestaat niet uit lijnen, maar wel uit afzonderlijke groepjes pixels<br />
die kleine cirkels vormen. Dat zal later voor problemen zorgen.<br />
Beeld 3 – Edge <strong>detectie</strong> met Canny<br />
Op Beeld 3 hebben we Canny toegepast. De driehoek is bijna volledig uit het beeld<br />
verdwenen en de cirkel verliest ook een stuk. Het zal echter geen probleem opleveren om<br />
de cirkel nog te herkennen. De ruis op het beeld is veel lager en zal daarom voor minder<br />
problemen zorgen.<br />
Beeld 4 – Edge <strong>detectie</strong> met Sobel en morfologische operaties<br />
Op Beeld 4 hebben we Sobel toegepast met de hierboven opgesomde morfologische<br />
operaties. De driehoek is bijna volledig verdwenen. We zien dat de cirkel beter gevormd is,<br />
waardoor hij veel beter kan worden gedetecteerd. Als we goed kijken, stellen we vast dat er<br />
34
iets minder ruis op het beeld is, in vergelijking met Canny, waardoor de <strong>detectie</strong> <strong>van</strong> de<br />
figuren zal vereenvoudigen.<br />
Beeld 5 – Edge <strong>detectie</strong> met Canny en morfologische operaties<br />
Op Beeld 5 is Canny toegepast met de morfologische operaties. We stellen vast dat de filter<br />
veel te veel pixels heeft verwijderd zodat zelfs de cirkel niet meer herkenbaar is.<br />
Soms is het bijna onmogelijk alle <strong>verkeersborden</strong> in het beeld te behouden. Het is erg<br />
jammer dat we de driehoek hier verliezen, maar we moeten een keuze maken. We zien dat<br />
de driehoek in Beeld 2 niet gevormd is door lijnen, maar door kleine segmenten die geen<br />
lijn vormen. Dat is dan ook de reden waarom we de driehoek in ons beeld verliezen.<br />
Hoewel we een figuur niet vinden, blijven de morfologische bewerkingen noodzakelijk<br />
omdat ze er in de meeste gevallen voor zorgen dat we de <strong>verkeersborden</strong> beter terugvinden.<br />
35
Voorbeeld 2<br />
Beeld 6 – Origineel beeld<br />
Bij Beeld 6 voeren we dezelfde bewerkingen uit als in het voorgaande voorbeeld.<br />
Beeld 7 – Edge <strong>detectie</strong> met Sobel filter<br />
Op Beeld 7 is enkel de Sobel filter toegepast. Het verkeersbord is goed te zien, maar er is<br />
erg veel ruis op het beeld aanwezig.<br />
36
Beeld 8 – Edge <strong>detectie</strong> met Canny<br />
Op Beeld 8 is Canny toegepast. De ruis is verdwenen, maar er ontbreekt ook een stuk <strong>van</strong><br />
de cirkel.<br />
Beeld 9 – Edge <strong>detectie</strong> met Sobel en morfologische operaties<br />
Op Beeld 9 hebben we Sobel en de morfologische operaties toegepast. De cirkel is<br />
duidelijk en nog volledig rond. Dat levert meer pixels op die later beter kunnen worden<br />
gedetecteerd. Er is ook bijna geen ruis op het beeld aanwezig.<br />
37
Beeld 10 – Edge <strong>detectie</strong> met Canny en morfologische operaties<br />
Op Beeld 10 zijn Canny en de morfologische operaties toegepast. Zoals in het voorgaande<br />
geval blijft er bijna niets meer <strong>van</strong> ons beeld over.<br />
De vorige vijf beelden tonen duidelijk aan dat Sobel, met morfologische operaties, net iets<br />
beter werkt dan Canny.<br />
Voorbeeld 3<br />
Beeld 11 – Origineel beeld<br />
38
Beeld 11 is de originele foto. Na de roodfilter zullen we dezelfde vier operaties uitvoeren<br />
zoals bij de vorige twee voorbeelden.<br />
Beeld 12 – Edge <strong>detectie</strong> met Sobel<br />
Beeld 12 heeft enkel de Sobel operatie ondergaan. Zoals in de vorige voorbeelden is het<br />
verkeersbord hier zeer goed te zien, maar is er redelijk veel ruis op het beeld aanwezig.<br />
Beeld 13 – Edge <strong>detectie</strong> met Canny<br />
Op Beeld 13 hebben we enkel Canny toegepast. We zien dat het bovenste gedeelte <strong>van</strong> het<br />
verkeersbord bijna volledig verdwenen is. De buitenste driehoek zal zeer moeilijk worden<br />
gedetecteerd. Er is wel bijna geen ruis meer aanwezig.<br />
39
Beeld 14 – Edge <strong>detectie</strong> met Sobel en morfologische operaties<br />
Op Beeld 14 hebben we Sobel en morfologische operaties uitgevoerd. We zien zeer<br />
duidelijk dat er veel ruis is verdwenen. Het verkeersbord staat er volledig op zodat het geen<br />
probleem zal zijn om het in een later stadium te detecteren.<br />
Beeld 15 – Edge <strong>detectie</strong> met Canny en morfologische operaties<br />
Beeld 15 heeft Canny en morfologische operatoren ondergaan. We zien dat er geen ruis<br />
meer aanwezig is. De bovenste lijn <strong>van</strong> het verkeersbord is echter volledig verdwenen<br />
zodat het onmogelijk is die te detecteren. De binnenste driehoek zal wel gedetecteerd<br />
worden.<br />
Voorbeeld 3 toont aan dat Sobel meer zekerheid biedt bij het vinden <strong>van</strong> het verkeersbord.<br />
40
Conclusie<br />
Wij hebben ervoor gekozen Sobel met de morfologische operatoren verder te gebruiken.<br />
Het is de methode die het meeste zekerheid biedt om het verkeersbord na de edge <strong>detectie</strong><br />
nog te behouden.<br />
Canny alleen zal sneller werken aangezien er minder bewerkingen moeten worden<br />
uitgevoerd. Het nadeel is wel dat we soms een deel <strong>van</strong> het verkeersbord verliezen. Wij<br />
verkiezen de zekerheid <strong>van</strong> Sobel boven de snelheid <strong>van</strong> Canny.<br />
Als we Canny met de morfologische operaties toepassen, verliezen we de genoemde<br />
snelheid en lopen we meer kans dat het verkeersbord onleesbaar wordt, met alle gevolgen<br />
<strong>van</strong> dien voor het verdere verloop <strong>van</strong> het programma.<br />
41
Hoofdstuk 3: Cirkel<strong>detectie</strong><br />
Wanneer we alle mogelijke <strong>verkeersborden</strong> naast elkaar plaatsen, stellen we vast dat<br />
de meest voorkomende borden cirkelvormig dan wel driehoekig zijn. Het komt er dus<br />
op aan die vormen onmiddellijk te kunnen detecteren. In dit hoofdstuk gaan we<br />
dieper in op de <strong>detectie</strong> <strong>van</strong> cirkels. De <strong>detectie</strong> <strong>van</strong> driehoeken en rechthoeken komt<br />
in de volgende hoofdstukken aan bod.<br />
De <strong>detectie</strong> <strong>van</strong> de vorm is een eerste stap voor het herkennen <strong>van</strong> <strong>verkeersborden</strong>.<br />
Daarbij moeten we er wel rekening mee houden dat we bij onderzoek <strong>van</strong> ons beeld<br />
naar de vorm, niet weten op welke coördinaten de – in dit geval – cirkel zich bevindt.<br />
Bovendien is de opnamehoek steeds verschillend waardoor de cirkel niet perfect<br />
wiskundig is.<br />
Hoe we bepalen wanneer een cirkel als cirkelvormig verkeersbord mag worden<br />
weerhouden, en op welke problemen we tijdens deze definiëring hebben gestoten,<br />
leggen we hierna verder uit. Tot slot verklaren we hoe we de borden uit het beeld<br />
extraheren en tonen we nog enkele voorbeelden.<br />
Wat is een goede cirkel?<br />
Wiskundig gezien kan je door drie punten die niet collineair zijn een cirkel bepalen.<br />
Gebruik makend <strong>van</strong> de formules en na het oplossen <strong>van</strong> het stelsel:<br />
(x1-a)² + (y1-b)² = R²<br />
(x2-a)² + (y2-b)² = R²<br />
(x3-a)² + (y3-b)² = R²<br />
krijgen we middelpunt (a,b) en straal R.<br />
Zoals aangehaald zijn er geen perfect wiskundige cirkels in ons beeld aanwezig. Immers,<br />
bij het klassieke wiskundige model liggen alle punten op exact dezelfde afstand <strong>van</strong> het<br />
middelpunt en vormt de omtrek een gesloten geheel. Wanneer we tijdens het rijden een<br />
opname maken, bekijken we de cirkel onder een wisselende hoek. Daarenboven is de hoek<br />
<strong>van</strong> het bord ten opzichte <strong>van</strong> de rijweg zelden gelijk.<br />
Het verkeersbord op ons beeld zal dus niet altijd aan het wiskundige model voldoen.<br />
Andere moeilijkheden zijn <strong>verkeersborden</strong> die gedeukt kunnen zijn of gedeeltelijk<br />
verscholen achter takken en bladeren of een andere situatie waardoor het verkeersbord niet<br />
perfect zichtbaar is. Wanneer we bij een dergelijk bord de rand detecteren, zal een stuk uit<br />
de cirkel ontbreken.<br />
Ook zien we na het toepassen <strong>van</strong> de kleurfilter en de edge detector dat we geen perfect<br />
ronde cirkel vinden, maar een cirkel waar<strong>van</strong> de rand is gekarteld. Die karteling, beter<br />
gekend onder de naam ‘aliasing’, komt doordat we met een digitaal beeld werken en dat is<br />
een tweedimensionale tabel. In die tabel kunnen we natuurlijk nooit perfect een cirkel<br />
tekenen. Hoe groter onze tabel, hoe meer cellen hij bevat en hoe beter we een cirkel kunnen<br />
maken. Maar hij zal nooit perfect zijn. De volgende Figuur 1 illustreert dat.<br />
42
30<br />
25<br />
Figuur 1 – Voorbeeld aliasing<br />
Hoe kunnen we die problemen oplossen?<br />
Een oplossing bestaat erin twee extra parameters te hanteren: de marge en het aantal pixels<br />
die op onze cirkel liggen.<br />
Door de marge in te voeren, kunnen we bepalen hoeveel een pixel <strong>van</strong> de ideale cirkel mag<br />
afwijken opdat hij toch nog in rekening wordt gebracht. Hoe groter we dus de marge<br />
nemen hoe meer cirkels we kunnen vinden, al zullen ze eerder op ellipsen lijken. Toch<br />
moeten we oppassen de marge niet te groot te nemen, want dan brengen we misschien ook<br />
pixels in rekening die helemaal niet bij de cirkel behoren. Dat zien we in Figuur 2. De<br />
zwarte cirkel is de cirkel die we willen detecteren. De twee rode cirkels duiden de marge<br />
aan. Alle pixels die tussen die twee cirkels liggen, behoren volgens onze definitie tot de<br />
cirkel. De blauwe ellips toont aan dat er tussen de marges ook een ellips kan worden<br />
gevonden. Dat is een groot voordeel, want als we onder een bepaalde hoek een foto <strong>van</strong> een<br />
cirkel nemen, zal die cirkel op een ellips lijken. De situatie is in Figuur 2 uitvergroot<br />
weergegeven.<br />
Figuur 2 – De marge<br />
Het komt er dus op aan een goede marge te kiezen zodat we niet alleen het verkeersbord<br />
kunnen vinden, maar ook zo weinig mogelijk andere cirkels detecteren. Die andere cirkels<br />
treffen we aan in de ruis die na het toepassen <strong>van</strong> de kleurfilter en edge <strong>detectie</strong> eventueel<br />
nog op ons beeld aanwezig is.<br />
43
Het tellen <strong>van</strong> het aantal pixels en het vergelijken met een vooraf ingestelde waarde laten<br />
ons toe een cirkel te bepalen die niet gesloten is.<br />
We kunnen dus perfect een cirkel terugvinden waaruit er pakweg een kwart ontbreekt.<br />
Zolang het aantal pixels maar aan onze voorwaarde voldoet. Het nadeel <strong>van</strong> deze<br />
benadering is dat we een halve cirkel ruis ook terug zullen vinden zolang er maar genoeg<br />
pixels op liggen.<br />
We beschouwen elke cirkel in ons beeld waar we minstens x aantal pixels op vinden,<br />
rekening houdend met de marge, als goede cirkel.<br />
Random<br />
Zoals we weten is een beeld uit pixels opgebouwd. Wij maken <strong>van</strong> ons RGB-beeld een<br />
binair beeld via de eerder besproken kleurfilter (zie hoofdstuk 1). We bespreken hierna de<br />
werking <strong>van</strong> het herkenningssysteem, dat gebruik maakt <strong>van</strong> het gecreëerde binaire beeld.<br />
We nemen drie willekeurige pixels in ons beeld en gaan na of ze collineair zijn. Wanneer<br />
dat niet zo is, bepalen we het middelpunt en de straal en tellen vervolgens hoeveel pixels er<br />
op dezelfde afstand <strong>van</strong> het middelpunt liggen, rekening houdend met de marge. Wanneer<br />
het aantal pixels groot genoeg is, definiëren we de figuur als een cirkel, slaan middelpunt<br />
en straal op in een tabel en verwijderen vervolgens al die pixels uit ons beeld. Zo<br />
voorkomen we dat we tweemaal dezelfde cirkel zouden vinden.<br />
Vervolgens onderzoeken we of er nog pixels in ons beeld aanwezig zijn. Zo ja, herhalen we<br />
het programma. Het spreekt voor zich dat we het aantal herhalingen zullen beperken, want<br />
er zullen waarschijnlijk altijd pixels in ons beeld aanwezig blijven die niet bij een cirkel<br />
horen. We stellen dus vooraf in hoeveel keer het programma moet worden herhaald, dus<br />
eigenlijk hoeveel keer we ons beeld moeten scannen om een cirkel te vinden.<br />
Aangezien we random drie pixels uit ons beeld nemen en hebben vastgelegd hoeveel keer<br />
we naar een cirkel zullen zoeken, behoort het tot de mogelijkheden dat we nooit bij de<br />
juiste cirkel terechtkomen. Zeker bij beelden met veel ruis is het risico dat we niet de juiste<br />
cirkel vinden zeer reël.<br />
Een mogelijke, hoewel gedeeltelijke oplossing voor dit probleem is het aantal herhalingen<br />
te verhogen, wat natuurlijk ten koste is <strong>van</strong> de snelheid <strong>van</strong> het herkenningssysteem. We<br />
hebben het aantal herhalingen op tien vastgelegd, waardoor we tien cirkels kunnen vinden.<br />
Onderzoek heeft uitgewezen dat dit meestal voldoende is.<br />
Problemen<br />
Met het vinden <strong>van</strong> de goede cirkels is de kous nog niet af. Er zijn nog een aantal<br />
problemen waarmee we kampen. Zo vinden we bijvoorbeeld meerdere cirkels ineen, een<br />
cirkel die volledig omsloten is door een andere cirkel – zeker bij een rond verkeersbord is<br />
dat vaak het geval –, de cirkel is veel te klein of veel te groot, een gedeelte <strong>van</strong> de cirkel<br />
bevindt zich buiten ons beeld en we detecteren cirkels in de ruis.<br />
Oplossingen<br />
Cirkels binnen andere cirkels is een probleem dat we kunnen oplossen. We overlopen de<br />
tabel en vergelijken middelpunt en straal met elkaar. Daarvoor gaan we als volgt te werk:<br />
44
we nemen middelpunt en straal <strong>van</strong> beide cirkels en trekken eerst de straal af <strong>van</strong> het<br />
middelpunt, dit zowel in de x-richting als in de y-richting. Wanneer het resultaat <strong>van</strong> die<br />
aftrekking bij de kleinste cirkel in beide richtingen het grootst is, gaan we middelpunt en<br />
straal in beide richtingen optellen. Wanneer het resultaat <strong>van</strong> deze optelling bij de kleinste<br />
cirkel het kleinst is in beide richtingen dan ligt de cirkel volledig binnen de andere. Enkel<br />
de grootste cirkel wordt onthouden en de binnenste cirkel wordt uit de tabel verwijderd. We<br />
bespreken dat verder aan de hand <strong>van</strong> Voorbeeld 1.<br />
Onderzoek op te kleine of te grote cirkels heeft geen nut. In het geval <strong>van</strong> te kleine cirkels<br />
bevat de inhoud <strong>van</strong> de cirkel te weinig informatie om mee verder te werken. Bij te grote<br />
cirkels hebben we twee redenen om er geen rekening mee te houden.<br />
Ten eerste, wanneer we de cirkel in rekening nemen, verliezen we enorm veel andere<br />
cirkels omdat ze binnen de grote cirkel liggen (zie vorig punt). Wellicht ligt ons<br />
verkeersbord binnen die grote cirkel, wat de classificatie <strong>van</strong> ons bord sterk bemoeilijkt dan<br />
wel onmogelijk maakt<br />
Ten tweede hebben we het verkeersbord waarschijnlijk al eerder gedetecteerd. Stel, we<br />
rijden door een straat en nemen om de seconde een foto <strong>van</strong> het straatbeeld, dan zullen we<br />
hetzelfde verkeersbord meerdere keren hebben gefotografeerd. Van zeer veraf tot zeer<br />
dichtbij. Wanneer we dus zeer dichtbij zijn, hebben we het verkeersbord groot in beeld, en<br />
zal het niet meer worden onderzocht. Dat is geen probleem aangezien we het verkeersbord<br />
al hebben onderzocht op een <strong>van</strong> de vorige foto’s die <strong>van</strong> verder zijn genomen. Dus daarom<br />
wensen we de zeer grote <strong>verkeersborden</strong> niet meer te onderzoeken.<br />
Met een cirkel die gedeeltelijk buiten het beeld valt, kunnen we niets aan<strong>van</strong>gen aangezien<br />
er in dat geval te veel informatie verloren is gegaan. Bovendien zijn de meeste <strong>van</strong> die<br />
cirkels onderdeel <strong>van</strong> ruis op ons beeld. Cirkels die gedeeltelijk buiten ons beeld liggen<br />
zullen we dus verwaarlozen. Dat doen we door te testen via middelpunt en straal of de<br />
cirkel volledig binnen het beeld valt. Wanneer dat niet zo blijkt te zijn, slaan we die cirkel<br />
niet in onze tabel op.<br />
Aan het probleem <strong>van</strong> cirkels die gevonden zijn door ruis op ons beeld is weinig te doen.<br />
De beste manier om dat te verhelpen is een zo goed mogelijke filter te maken waardoor we<br />
met weinig ruis worden geconfronteerd. Dat is een probleem dat al eerder werd besproken.<br />
Hoe dan ook, wanneer we ondanks onze filter toch een cirkel vinden als gevolg <strong>van</strong> de ruis,<br />
zullen we via een ander programma moeten uitmaken of het al dan niet een verkeersbord is.<br />
Hierover meer in hoofdstuk 7.<br />
Extraheren <strong>van</strong> de cirkel<br />
Als de gevonden cirkels eenmaal zijn vastgelegd, willen we ze uit ons beeld extraheren,<br />
anders gezegd uit ons beeld te knippen. Zo beperken we de informatie die we in het<br />
originele beeld terugvinden. Pas na extractie zullen we kijken of het vermoedelijke<br />
verkeersbord al dan niet een verkeersbord is.<br />
Het extraheren <strong>van</strong> cirkels is binnen MATLAB een probleem omdat het onmogelijk is<br />
een tabel aan te maken die de vorm <strong>van</strong> een cirkel heeft. Elke rij moet even veel kolommen<br />
bevatten als de vorige. Daarom zijn we genoodzaakt in plaats <strong>van</strong> de cirkel, een omhullend<br />
vierkant uit te knippen.<br />
45
Om het vierkant uit te knippen hebben we de linkerbovenhoek en de hoek rechts onder<br />
nodig. Met die twee punten zijn we in staat het omhullende vierkant in de originele foto te<br />
vinden. We nemen natuurlijk een kleine speling voor het vierkant, dat we iets groter<br />
uitknippen dan in werkelijkheid nodig is.<br />
De coördinaten <strong>van</strong> de linkerbovenhoek verkrijgen we door de x- en y-coördinaat <strong>van</strong> het<br />
middelpunt te verminderen met de straal. Voor de hoek rechts onder tellen we de straal bij<br />
het middelpunt op. De functie geeft ons dan een stuk <strong>van</strong> het originele beeld terug, dat we<br />
opslaan in de tabel ‘Cirkel’. Die tabel bevat dus fragmenten <strong>van</strong> het originele beeld.<br />
Voorbeelden<br />
Voorbeeld 1<br />
Beeld 1- Origineel beeld<br />
Beeld 2 – Geëxtraheerd beeld buitenste cirkel Beeld 3 – Geëxtraheerd beeld<br />
binnenste cirkel<br />
In het eerste voorbeeld zien we een cirkel en een driehoek. Zonder rekening te houden met<br />
het verwijderen <strong>van</strong> de binnenste cirkel verkrijgen we Beeld 2 en Beeld 3. We kunnen<br />
duidelijk zien dat Beeld 3 de binnenste cirkel voorstelt. Zoals eerder vermeld negeren we<br />
de binnenste cirkel zodat Beeld 3 uit de tabel wordt verwijderd en dus niet meer in het<br />
uiteindelijke resultaat voorkomt. Het is duidelijk dat als we Beeld 3 verwijderen, we geen<br />
enkele informatie over het verkeersbord verliezen omdat Beeld 2 alle informatie <strong>van</strong> Beeld<br />
3 in zich draagt. Dat is meteen ook de reden waarom we cirkels verwijderen die volledig<br />
omsloten zijn door een andere cirkel.<br />
De driehoek wordt genegeerd door het programma. In hoofdstuk 5 bekijken we dit<br />
voorbeeld nog eens om na te gaan wat de driehoek<strong>detectie</strong> met Beeld 1 doet.<br />
46
Voorbeeld 2<br />
Beeld 4 – Origineel Beeld Beeld 5 – Uitgeknipt beeld<br />
In het tweede voorbeeld zoeken we naar cirkels die een verkeersbord kunnen zijn. Wanneer<br />
we de rode filter gebruiken, vinden we geen enkele cirkel terug. Wanneer we de blauwe<br />
kleur afzonderen, vinden we Beeld 5 terug.<br />
Voorbeeld 3<br />
Beeld 6 – Origineel beeld Beeld 7 en 8 – Uitgeknipte beelden<br />
In voorbeeld 3 hebben we zowel de rood- als de blauwfilter gebruikt. We zien aan Beeld 7<br />
en Beeld 8 dat we de correcte cirkels terugvinden.<br />
47
Voorbeeld 4<br />
Beeld 9 – Origineel beeld Beeld 10 – Uitgeknipt Beeld<br />
Beeld 9 is <strong>van</strong>uit de auto genomen. Door de voorruit is de foto een klein beetje wazig<br />
geworden, maar zoals we met Beeld 10 kunnen vaststellen, creëert dat geen probleem voor<br />
het programma. Hoe ver we kunnen gaan in het wazig maken <strong>van</strong> foto’s wordt in hoofdstuk<br />
8 besproken.<br />
Voorbeeld 5<br />
Beeld 11 – Origineel beeld Beeld 12 en 13 – Uitgeknipte beelden<br />
In Beeld 11 gaan we na hoe het programma reageert als we twee cirkels boven elkaar<br />
hebben. Beeld 12 en Beeld 13 tonen aan dat we in die situatie geen enkel probleem<br />
ondervinden. Beide <strong>verkeersborden</strong> worden perfect teruggevonden. Er worden geen cirkels<br />
gedetecteerd die geen verkeersbord voorstellen.<br />
48
Conclusie<br />
Uit de voorbeelden kunnen we opmaken dat het cirkel<strong>detectie</strong> programma zeer goed werkt.<br />
In 78% <strong>van</strong> de gevallen verkrijgen we erg goede resultaten. Een goed resultaat wil zeggen<br />
dat we een minimaal aantal cirkels terugvinden, waar<strong>van</strong> het verkeersbord zelf ook<br />
gevonden wordt. De random factor zorgt soms nog voor problemen. We krijgen niet altijd<br />
dezelfde resultaten. Het is mogelijk dat in sommige gevallen het verkeersbord wordt<br />
teruggevonden en wanneer we dezelfde foto nog eens onderzoeken, we een ander resultaat<br />
krijgen. Dat is dan ook het grootste nadeel <strong>van</strong> de random factor.<br />
Het vinden <strong>van</strong> cirkels geeft ons goede resultaten en het is nu aan de classificatie om uit te<br />
maken of de gevonden cirkel al dan niet een verkeersbord is.<br />
49
Hoofdstuk 4: Lijn<strong>detectie</strong><br />
Voordat we driehoekige of rechthoekige <strong>verkeersborden</strong> kunnen detecteren, moeten<br />
we in eerste instantie de lijnen uit het beeld kunnen halen. Daarvoor bestaan<br />
verschillende methodes die we in dit hoofdstuk <strong>van</strong> naderbij bekijken. Daarnaast<br />
moeten we ook nog het probleem oplossen <strong>van</strong> lijnen waaruit een stuk ontbreekt als<br />
gevolg <strong>van</strong> pakweg een boom die gedeeltelijk voor een verkeersbord staat. Hoe we dat<br />
oplossen, beschrijven we eveneens in dit hoofdstuk.<br />
Algemeen<br />
Er zijn twee veel gebruikte methodes om lijnen in een beeld te vinden: de Ransac-methode<br />
en de Radon-methode, die een MATLAB functie is. Het principe <strong>van</strong> de Radon-methode is<br />
hetzelfde als die <strong>van</strong> de gekende Hough-methode, maar de werkwijze is verschillend. We<br />
zullen Ransac en Radon <strong>van</strong> dichterbij bekijken en uitvoerig testen.<br />
We hebben de lijnen in poolcoördinaten gedefinieerd omdat de Radon-methode daar<br />
gebruik <strong>van</strong> maakt.<br />
We spreken ook over lijnen, we kennen dus geen begin- en eindpunt en geen<br />
lijnsegmenten. Dat is bewust gedaan omdat een lijnsegment moeilijk te bepalen valt.<br />
Immers, waar begint en eindigt het lijnsegment?<br />
Als we het beeld bekijken dat we na de edge <strong>detectie</strong> krijgen, zien we dat er soms een stuk<br />
<strong>van</strong> de lijn ontbreekt. Dat kan bijvoorbeeld het gevolg zijn <strong>van</strong> een boom die voor een stuk<br />
<strong>van</strong> het verkeersbord staat. Hoe moeten we dat op<strong>van</strong>gen? Het is erg moeilijk om een<br />
herkenningssysteem te maken dat kan uitmaken of de lijnsegmenten al dan niet bij het<br />
verkeersbord horen. Als we gebruik maken <strong>van</strong> lijnen, trekken we de lijn in feite virtueel<br />
door over ons volledige beeld. Het niet kennen <strong>van</strong> het begin- en eindpunt zal een groot<br />
voordeel betekenen. Dat zullen we verder zien.<br />
Wat zijn poolcoördinaten?<br />
Zoals gezegd wordt een lijn voorgesteld in poolcoördinaten door een hoek θ en een afstand,<br />
zoals we in Figuur 1 kunnen zien. De afstand en hoek worden bepaald door de lijn die we<br />
willen definiëren. We trekken een lijn die loodrecht staat op onze te definiërende lijn, naar<br />
de oorsprong. De hoek die deze getrokken lijn met de pool-as maakt, is de hoek θ. De<br />
afstand die we nodig hebben, is de lengte <strong>van</strong> de getrokken lijn.<br />
Figuur 1 – Poolcoördinaten <strong>van</strong> een lijn<br />
50
Zo zal een horizontale lijn een hoek <strong>van</strong> 90° hebben en zal een verticale lijn een hoek <strong>van</strong><br />
0° hebben. De interessante hoeken voor ons zijn die <strong>van</strong> een gelijkzijdige driehoek. Daarop<br />
wordt in het volgende hoofdstuk driehoek<strong>detectie</strong> dieper ingegaan.<br />
In een driehoek hebben we drie lijnen: een horizontale, een lijn onder een hoek <strong>van</strong> 120°<br />
(zoals ongeveer in Figuur 1) en een lijn onder een hoek <strong>van</strong> 30°. De hoeken <strong>van</strong> die lijnen<br />
worden voorgesteld in poolcoördinaten door respectievelijk 90°, 30° en 150°.<br />
Ransac<br />
Ransac gaat uit <strong>van</strong> het wiskundige principe dat we altijd een lijn kunnen berekenen als we<br />
twee punten hebben. De Ransac-methode werkt analoog aan de cirkel<strong>detectie</strong> methode, zie<br />
hoofdstuk 3. We maken opnieuw gebruik <strong>van</strong> een marge en we tellen het aantal pixels die<br />
op onze lijn aanwezig zijn. We spreken <strong>van</strong> een lijn als er 25 pixels op liggen.<br />
We nemen daarbij twee willekeurige pixels uit ons beeld en berekenen de poolcoördinaten<br />
<strong>van</strong> de lijn. Daarna kijken we naar alle andere pixels uit ons beeld en berekenen we of ze<br />
op onze lijn liggen, rekening houdend met de marge. De pixels die op deze lijn liggen,<br />
worden geteld. Wanneer het aantal groter is dan 25 spreken we <strong>van</strong> een lijn en worden alle<br />
pixels op de lijn uit ons beeld verwijderd, zodat het niet mogelijk is tweemaal dezelfde lijn<br />
te vinden. Als er na het verwijderen nog pixels op ons beeld aanwezig zijn, wordt de<br />
Ransac-functie herhaald. Die herhaling is niet oneindig, maar hangt af <strong>van</strong> een vooraf<br />
ingesteld getal. Dat getal bepaalt tevens hoeveel lijnen we op ons beeld willen vinden. Dat<br />
is natuurlijk een grote tekortkoming <strong>van</strong> Ransac, want het is onmogelijk op voorhand te<br />
weten hoeveel lijnen er aanwezig zullen zijn.<br />
Radon<br />
Het beeld dat we bij Radon zullen gebruiken, is binair. Het is een zwart-wit beeld waarop<br />
alle pixels met waarde 0 zwart voorstellen en alle pixels met waarde 1 wit voorstellen. Een<br />
lijn zal dus getekend worden in het wit met een zwarte achtergrond.<br />
De Radon methode gaat helemaal anders te werk dan de Ransac-methode. Radon houdt<br />
helemaal geen rekening met het wiskundige principe dat Ransac toepast, maar werkt met<br />
projecties. We leggen een orthogonaal assenstelsel midden in ons beeld en verdelen de x-as<br />
in allemaal kleine vakjes. Daarna projecteren we ons beeld op de x-as. Alle pixels vallen<br />
als het ware naar beneden in een <strong>van</strong> de vakjes en de optelsom <strong>van</strong> alle 1-pixels wordt<br />
gemaakt. Vervolgens kijken we naar de waarde die in elk vakje zit. Die waarde komt<br />
overeen met het aantal pixels dat op de lijn ligt. Wanneer die waarde groter is dan 25<br />
spreken we <strong>van</strong> een lijn.<br />
Daarna verdraaien we ons assenstelsel 1° graad en projecteren opnieuw. We herhalen dat<br />
tot we aan 179° komen. Wanneer we een lijn hebben gevonden, slaan we in een tabel de<br />
hoek waaronder hij is gevonden en het vakje op. De plaats <strong>van</strong> het vakje is de loodrechte<br />
afstand <strong>van</strong> de lijn tot de oorsprong.<br />
51
Keuze<br />
De keuze tussen Ransac en Radon is niet eenvoudig. Het is de keuze tussen snelheid en<br />
precisie.<br />
We zouden denken dat de Ransac-methode vrij snel werkt omdat ze pixels uit het beeld<br />
verwijdert. Dat is ook zo, maar die snelheid is relatief. Wanneer we een klein aantal lijnen<br />
willen vinden, werkt de Ransac-methode vrij snel. Logisch ook, want ze stopt sowieso na x<br />
aantal herhalingen. Wanneer we het aantal lijnen dat we willen definiëren optrekken,<br />
verloopt het programma al een stuk trager, maar daar tegenover staat dat het resultaat<br />
nauwkeuriger is.<br />
We zetten de nadelen aan de Ransac-methode op een rijtje:<br />
Primo: we moeten voordien bepalen hoeveel lijnen we willen vinden waarmee we ook het<br />
aantal zoekopdrachten vastleggen. Zoals al eerder vermeld, is dat niet eenvoudig aangezien<br />
we niet op voorhand weten hoeveel lijnen er in het beeld aanwezig zullen zijn. Ook bepalen<br />
we daarmee de snelheid <strong>van</strong> het programma.<br />
Secundo: Ransac kiest zijn pixels willekeurig. Daarbij bestaat het risico dat als hij niet de<br />
pixels kiest <strong>van</strong> een lijn, voordat hij gestopt is met zoeken, hij die lijn ook niet zal vinden.<br />
Daar tegenover staat dat dit probleem bij Radon onbestaande is, aangezien hij het hele<br />
beeld bekijkt en op elke graad naar lijnen zoekt. Juist daarom is Radon veel nauwkeuriger.<br />
Teneinde de snelheid bij identieke nauwkeurigheid <strong>van</strong> beide methodes tegenover elkaar te<br />
plaatsen, laten we Ransac 50 keer zoeken wanneer we weten dat Radon 50 lijnen heeft<br />
gevonden. Het resultaat <strong>van</strong> die vergelijking is dat Ransac vier tot vijf keer trager is dan<br />
Radon. Radon heeft natuurlijk het voordeel dat het een MATLAB-functie is waardoor het<br />
in de praktijk sneller werkt. Dus, het grootste voordeel <strong>van</strong> de Ransac-methode – de<br />
snelheid –vervalt hierbij en het grootste nadeel – op voorhand bepalen hoeveel lijnen hij<br />
moet zoeken – blijft bestaan.<br />
Onze keuze gaat uit naar Radon.<br />
Problemen<br />
Nu is het niet zo dat met de keuze <strong>van</strong> Radon alle problemen <strong>van</strong> de baan zijn. Zo vindt<br />
Radon ook lijnen in de ruis en verdeelt hij lijnen over verschillende vakjes.<br />
Aan het vinden <strong>van</strong> lijnen in de ruis kunnen we niet veel doen. Het enige wat helpt, is het<br />
aantal pixels dat we vooropstellen om een lijn te vormen – we hadden dat aantal op 25<br />
gesteld – op te trekken. Maar testen hebben uitgewezen dat 25 het maximum is om in 9%<br />
<strong>van</strong> de gevonden lijnen voor driehoeken) de lijn <strong>van</strong> onze gevarendriehoek niet te<br />
verliezen. Dus dat is geen oplossing. We moeten het probleem aanpakken bij het filteren<br />
<strong>van</strong> ons beeld. Dat hebben we in de voorgaande hoofdstukken al besproken.<br />
Om het probleem <strong>van</strong> de lijn die verdeeld is over verschillende vakjes beter te begrijpen,<br />
nemen we een voorbeeld.<br />
We weten dat een beeld uit een matrix bestaat. Als we dus een verticale lijn op het beeld<br />
tekenen, verwachten we dat hij in één kolom <strong>van</strong> de matrix is getekend. Als we dan de<br />
projectie nemen, verwachten we dat alle pixels <strong>van</strong> de lijn in hetzelfde vakje terecht zullen<br />
komen. Dat is echter niet zo en wel om de volgende twee redenen:<br />
• Het aantal vakjes bedraagt meer dan het aantal kolommen <strong>van</strong> onze beeldmatrix,<br />
wat we eenvoudig kunnen verklaren doordat de x-as roteert <strong>van</strong> 0° tot 179°.<br />
52
Wanneer we met het hele beeld rekening willen houden, moeten we zoeken naar de<br />
uiterste punten <strong>van</strong> ons beeld, m.a.w. de hoekpunten <strong>van</strong> ons beeld. Dus de grootste<br />
afstand is de afstand <strong>van</strong> de oorsprong tot aan de rechterbovenhoek. Die afstand<br />
wordt in kleine vakjes onderverdeeld waardoor hun aantal groter is dan het aantal<br />
kolommen. Wanneer we onze verticale lijn projecteren, zal hij over verschillende<br />
vakjes verdeeld zijn.<br />
• Een tweede reden waarom alle pixels <strong>van</strong> de lijn niet in hetzelfde vakje<br />
terechtkomen, vloeit voort uit het feit dat een lijn dikker kan zijn dan één kolom en<br />
zodoende na projectie over meerdere vakjes verdeeld is.<br />
Oplossing<br />
Dit probleem hebben we opgelost door de tabel die we weer <strong>van</strong> de Radon-methode krijgen<br />
te raadplegen. Zoals we weten, zitten in die tabel de hoek θ en de afstand. We nemen nu<br />
het eerste element uit de tabel, zowel de hoek als de afstand, en vergelijken die met de rest<br />
<strong>van</strong> de tabel. Wanneer zowel de hoek als de afstand, rekening houdend met een kleine<br />
speling, overeenkomen met het eerste element, nemen we dat uit de tabel. Als de volledige<br />
tabel eenmaal is overlopen, verwerken we de elementen die overeenkwamen.<br />
We nemen het gemiddelde <strong>van</strong> de hoek en <strong>van</strong> de afstand en bewaren die in een nieuwe<br />
tabel. Als ze in de nieuwe tabel zijn opgeslagen, verwijderen we ze uit de oorspronkelijke<br />
tabel en nemen opnieuw het eerste element. We herhalen het algoritme tot de tabel leeg is.<br />
De nieuwe tabel bevat alle opgekuiste elementen en is de tabel waarmee we verder zullen<br />
werken.<br />
53
Hoofdstuk 5 : Driehoek<strong>detectie</strong><br />
Om <strong>verkeersborden</strong> in een foto te kunnen vinden, is het noodzakelijk de geometrische<br />
figuren te herkennen. In dit hoofdstuk gaan we dieper in op hoe we driehoeken<br />
zoeken in ons beeld. We krijgen een tabel waarin alle lijnen staan die in ons beeld<br />
gevonden zijn (zie vorig hoofdstuk). Via wiskundige bewerkingen zoeken we of die<br />
lijnen een driehoek vormen. Vervolgens knippen we de gevonden driehoeken uit de<br />
originele foto. We sluiten het hoofdstuk af met enkele voorbeelden.<br />
Wat is een driehoek ?<br />
Driehoekige <strong>verkeersborden</strong> zijn altijd gelijkzijdige driehoeken. Dat wil zeggen dat ze drie<br />
gelijke hoeken <strong>van</strong> 60° hebben en dat de afstand tussen de hoekpunten gelijk is. Die<br />
eigenschappen zullen we gebruiken in het zoeken naar de juiste driehoeken.<br />
Implementatie<br />
Omdat we op zoek zijn naar gelijkzijdige driehoeken zullen we enkel kijken naar de lijnen<br />
die rond de 0°, 60° of 120° liggen. We maken drie tabellen aan en stoppen de coördinaten<br />
<strong>van</strong> die lijnen erin. De namen <strong>van</strong> de tabellen zijn respectievelijk tabel0, tabel60 en<br />
tabel120. We nemen een speling <strong>van</strong> 4° omdat in werkelijkheid de <strong>verkeersborden</strong> nooit<br />
perfect recht staan.<br />
De lijnen die we gebruiken hebben geen begin- of eindpunt, daarom is het noodzakelijk de<br />
snijpunten te berekenen. Hoe we dat doen, bespreken we in ‘bepalen <strong>van</strong> de snijpunten’.<br />
Figuur 1 toont de snijpunten die we berekenen. De punten liggen voor elke driehoek vast.<br />
Daarbij is (a,b) steevast het punt rechts, (c,d) het meest linkse punt <strong>van</strong> de basis en (e,f)<br />
altijd de top.<br />
(e,f)<br />
60° 120°<br />
(c,d) (a,b)<br />
Figuur 1 – Snijpunten die we berekenen<br />
54
Uit tabel120 nemen we de eerste lijn. We berekenen het punt (a,b) met het eerste element<br />
uit tabel0.<br />
Vervolgens controleren we of de coördinaten <strong>van</strong> het snijpunt binnen ons beeld vallen.<br />
Hebben we bijvoorbeeld een beeld <strong>van</strong> 480x640 pixels, dan mag de x-coördinaat niet<br />
groter dan 640 en de y-coördinaat niet groter dan 480 zijn. Deze controle voeren we telkens<br />
uit wanneer we een snijpunt berekenen.<br />
Aangezien we enkel werken met driehoeken die volledig in ons beeld liggen, vormt deze<br />
controle al een eerste indicatie of we met een goede dan wel slechte driehoek te maken<br />
hebben. Zo detecteren we geen verkeersbord dat maar half op de foto staat.<br />
Daarna berekenen we de punten (c,d) en (e,f). (c,d) is het snijpunt <strong>van</strong> de lijn onder een<br />
hoek <strong>van</strong> 60° en de horizontale. (e,f) is de top <strong>van</strong> de driehoek. We hebben nu de drie<br />
hoekpunten.<br />
Van die hoekpunten berekenen we de onderlinge afstand en het gemiddelde. Als de drie<br />
afstanden minder dan 5% <strong>van</strong> het gemiddelde afwijken en de gemiddelde afstand tussen de<br />
50 en 300 pixels bedraagt, slaan we de driehoek in een nieuwe tabel op. In die tabel slaan<br />
we alle driehoeken op die een vermoedelijk verkeersbord zijn.<br />
Waarom die beperkingen? De beperking <strong>van</strong> maximaal 5% afwijking elimineert de niet<br />
gelijkzijdige driehoeken. De beperking in afstand, tussen de 50 en 300 pixels, voorkomt dat<br />
<strong>verkeersborden</strong> die te klein of te groot op het beeld staan voor verdere <strong>detectie</strong> worden<br />
meegenomen.<br />
Voor we de driehoeken opslaan wordt er eerst nog een translatie doorgevoerd. Door de<br />
Radon-functie <strong>van</strong> hoofdstuk 4 ligt ons assenstelsel in het midden <strong>van</strong> het beeld. Om in het<br />
verdere programma met een eenduidig assenstelsel te kunnen werken, transleren we het<br />
middelpunt naar de hoek links boven. Dan slaan we de zes coördinaten en de gemiddelde<br />
afstand <strong>van</strong> de gevonden driehoek op.<br />
We hebben nu onze eerste driehoek verwerkt. Omdat er meestal meerdere lijnen in tabel0,<br />
tabel60 en tabel120 zitten, is het noodzakelijk dat we de andere mogelijkheden ook<br />
overlopen.<br />
We gaan de punten (c,d) en (e,f) opnieuw berekenen. We nemen de volgende lijn uit<br />
tabel60. Zo bekomen we (c,d) en (e,f) (zie Figuur 2) en vormen een nieuwe driehoek die<br />
we opslaan wanneer hij aan alle eisen voldoet. We lopen nu de tabel60 volledig af om alle<br />
geschikte driehoeken te vinden die gevormd worden met het eerste element uit tabel0 en<br />
tabel120.<br />
(e,f)<br />
(c,d)<br />
Figuur 2 – We nemen de volgende lijn uit tabel60<br />
55
Als dat gebeurd is, nemen we het tweede element uit tabel0 en berekenen (a,b) opnieuw<br />
met het eerste element uit tabel120. Met het eerste element uit tabel60 berekenen we (c,d)<br />
opnieuw (zie Figuur 3).<br />
(c,d) (a,b)<br />
Figuur 3 – We nemen de volgende lijn uit tabel0<br />
Nu overlopen we volledig tabel60 om alle driehoeken te zoeken die we kunnen vormen met<br />
de tweede lijn uit tabel0 en de eerste lijn uit tabel120. We herhalen nu het procédé <strong>van</strong><br />
Figuur 2.<br />
We overlopen tabel0 volledig en wanneer er geen elementen meer in tabel0 zijn, nemen we<br />
de volgende lijn uit de tabel120 en berekenen het punt (a,b), met het eerste element uit<br />
tabel0. (e,f) bepalen we met het eerste element uit tabel60 (zie Figuur 4).<br />
(e,f)<br />
(a,b)<br />
Figuur 4 – We nemen de volgende lijn uit tabel120<br />
Met die nieuwe lijn <strong>van</strong> tabel120 herhalen we de acties die we bij Figuur 3 ondernemen.<br />
We overlopen zo elke combinatie <strong>van</strong> drie lijnen. Dat doen we omdat we zeker willen zijn<br />
dat wanneer de edge <strong>detectie</strong> de drie juiste lijnen <strong>van</strong> het verkeersbord vindt, we met 100%<br />
zekerheid kunnen zeggen dat als het verkeersbord aan de eisen voldoet, de coördinaten in<br />
de tabel <strong>van</strong> potentiële <strong>verkeersborden</strong> terug te vinden is.<br />
56
Bepalen <strong>van</strong> de snijpunten<br />
We bepalen de snijpunten en zetten ze om naar cartesiaanse coördinaten. Daarvoor lossen<br />
we dit stelsel op:<br />
X1cosΘ1 + Y1sinΘ1 = R1<br />
X2cosΘ2 + Y2sinΘ2 = R2<br />
Daarbij is R de afstand uit onze tabel en Θ de hoek uit onze tabel. We lossen dit stelsel via<br />
de methode <strong>van</strong> Gauss op.<br />
Problemen<br />
Door de strikt wiskundige manier <strong>van</strong> werken, hebben we enkele problemen gekend. Het<br />
grootste probleem is het grote aantal driehoeken dat wordt gevonden. Hoe meer lijnen we<br />
vinden, hoe meer driehoeken het programma zal berekenen. Het is geen uitzondering dat<br />
het programma meer dan 1500 driehoeken vindt. Figuur 5 illustreert dat probleem. In<br />
Figuur 5 zien we dat er 10 lijnen voldoen aan onze eisen om een juiste driehoek te vormen.<br />
We zien met het blote oog dat er met die combinatie <strong>van</strong> lijnen erg veel gelijkzijdige<br />
driehoeken kunnen worden gevormd. Als we dat met ons programma testen, verkrijgen we<br />
dat er 3298 driehoeken een potentieel verkeersbord zijn.<br />
Figuur 5 – Illustratie <strong>van</strong> de impact <strong>van</strong> het aantal lijnen op het aantal<br />
driehoeken<br />
Ondanks de eisen die we aan onze driehoeken stelden (zie hoger), werden we genoodzaakt<br />
nog een programma te schrijven teneinde de overbodige driehoeken uit ons beeld te<br />
verwijderen. De verwijdering <strong>van</strong> de driehoeken uit de tabel moet zeer omzichtig gebeuren<br />
want alle driehoeken in de tabel zijn in feite een potentieel verkeersbord.<br />
57
Oplossingen<br />
We mogen alleen nog driehoeken verwijderen als we zeker zijn dat we geen informatie<br />
verliezen. Daarom verwijderen we alle driehoeken die qua coördinaten en lengte <strong>van</strong> de<br />
zijden sterk op elkaar lijken. We bekijken ook nog of de top dezelfde positie heeft ten<br />
opzichte <strong>van</strong> de basis.<br />
We nemen de eerste driehoek uit de tabel, dat is de referentiedriehoek, en overlopen alle<br />
andere driehoeken. Eerst controleren we of het punt (a,b) <strong>van</strong> de referentiedriehoek<br />
maximaal 30 pixels verschilt <strong>van</strong> het punt (a,b) <strong>van</strong> de volgende driehoek.<br />
Vervolgens bekijken we of de gemiddelde afstand tussen de hoekpunten <strong>van</strong> beide<br />
driehoeken niet meer 30% verschilt. Ten slotte controleren we de top. We gaan na of de top<br />
in beide gevallen boven of onder de basis ligt. Figuur 6 verduidelijkt dat. Driehoek 1 is de<br />
referentiedriehoek. We zien duidelijk dat de top <strong>van</strong> Driehoek 3 een andere positie heeft ten<br />
opzichte <strong>van</strong> de horizontale dan Driehoek 1 en Driehoek 2. Daarom is het onmogelijk<br />
Driehoek 3 uit te tabel te verwijderen als we die met Driehoek 1 vergelijken. Als Driehoek<br />
2 aan alle vooropgestelde eisen voldoet zal ze worden verwijderd uit de tabel.<br />
Figuur 6 – Ligging <strong>van</strong> de top ten opzichte <strong>van</strong> de horizontale<br />
Wanneer aan alle bovenstaande eisen voldaan is, slaan we de driehoek met de grootste<br />
gemiddelde afstand op, de andere wissen we.<br />
We willen het aantal driehoeken verminderen, maar het is zeker niet de bedoeling om<br />
informatie te verliezen. De informatie in de kleinere driehoek zullen we zeker in de grote<br />
terugvinden. We kunnen Driehoek 3 onmogelijk verwijderen omdat het een voorrangsbord<br />
kan zijn, terwijl Driehoek 1 een gevarendriehoek voorstelt.<br />
We herhalen dit programmafragment tweemaal omdat we proefondervindelijk hebben<br />
vastgesteld dat dit nodig is om goede resultaten te bereiken.<br />
Voor Figuur 5 verkrijgen we, na de eerste keer dit programmafragment te laten lopen, 58<br />
geldige driehoeken. Na de tweede keer zijn het er nog 44.<br />
58
Extraheren <strong>van</strong> de driehoek<br />
Nu proberen we de gevonden driehoeken uit het beeld te knippen. We bedoelen dat we de<br />
gevonden driehoek uit ons beeld extraheren. Zo kunnen we de informatie die we in het<br />
originele beeld terugvinden, beperken. Na het uitknippen zullen we dan kijken of het<br />
vermoedelijke verkeersbord al dan niet een verkeersbord is.<br />
Het extraheren <strong>van</strong> driehoeken is binnen MATLAB een probleem omdat het onmogelijk is<br />
een tabel aan te maken die de vorm <strong>van</strong> een driehoek heeft. Elke rij moet even veel<br />
kolommen bevatten als de vorige. Daarom zijn we genoodzaakt in plaats <strong>van</strong> de driehoek,<br />
een omhullend vierkant uit te knippen.<br />
Om het vierkant uit te knippen, hebben we de linkerbovenhoek en de hoek rechts onder<br />
nodig. Met die twee punten zijn we in staat het omhullende vierkant in de originele foto te<br />
vinden. We nemen natuurlijk een kleine speling voor het vierkant, dat we iets groter<br />
uitknippen dan in werkelijkheid nodig is.<br />
We verkrijgen die punten door de grootste en kleinste waarden <strong>van</strong> de hoekpunten <strong>van</strong> de<br />
driehoek te zoeken. De functie geeft ons dan een stuk <strong>van</strong> het originele beeld terug die we<br />
opslaan in de tabel ‘driehoek’. Die tabel bevat dus fragmenten <strong>van</strong> het originele beeld.<br />
Voorbeelden<br />
Voorbeeld 1<br />
Beeld 1 – Origineel beeld<br />
Beeld 1 is het originele beeld. We zullen proberen het verkeersbord uit de figuur te<br />
knippen. We hernemen hetzelfde beeld als in hoofdstuk 2: edge <strong>detectie</strong>. In dit voorbeeld<br />
zullen we alle belangrijke stappen <strong>van</strong>af de originele foto tot aan de uitgeknipte driehoek<br />
bekijken.<br />
59
Beeld 2 – Beeld na roodfilter<br />
Op Beeld 2 is alleen maar de roodfilter toegepast. We zien zeer goed dat er bijna geen<br />
achtergrond meer op de foto aanwezig is. Het verkeersbord zou dus eerder gemakkelijk te<br />
detecteren moeten zijn.<br />
Beeld 3 – Edge <strong>detectie</strong> (sobel; 0,1) op Beeld 2<br />
Beeld 3 is het resultaat na edge <strong>detectie</strong> en de eerder besproken morfologische operaties.<br />
De lijnen <strong>van</strong> het verkeersbord zijn zeer goed te zien en de ruis is minimaal.<br />
De volgende stap is de <strong>detectie</strong> <strong>van</strong> lijnen. Dat werd in het hoofdstuk 4 besproken. Op dit<br />
beeld vindt de lijn<strong>detectie</strong> 48 verschillende lijnen. In de eerste fase worden die lijnen in<br />
drie tabellen weggeschreven. In Tabel 1 zien we de drie tabellen.<br />
60
Lijnen <strong>van</strong> 120° Lijnen <strong>van</strong> 0° Lijnen <strong>van</strong> 60°<br />
28 -17 86 -150 150 2<br />
28 0 88 123 149 19<br />
30 -14 88 -175 152 -1<br />
30 4 88 -165<br />
88 -157<br />
90 108<br />
90 -188<br />
90 -182<br />
92 -195<br />
91 124<br />
93 -201<br />
93 107<br />
Tabel 1 –<br />
De drie tabellen <strong>van</strong> de lijn<strong>detectie</strong><br />
Van de 48 lijnen gebruiken we er maar 19. We berekenen alle lijnen omdat we<br />
bijvoorbeeld voor de <strong>detectie</strong> <strong>van</strong> rechthoeken andere lijnen nodig hebben. Willen we een<br />
achthoekig verkeersbord detecteren, dan kan de tabel <strong>van</strong> lijn<strong>detectie</strong> daar ook de basis<br />
voor vormen.<br />
We zien ook dat de grootte <strong>van</strong> de hoek telkens 90° verschilt met de echte waarde. Die<br />
oorzaak werd in het hoofdstuk 4 over lijn<strong>detectie</strong> besproken.<br />
Hier zien we heel duidelijk waarom we zo weinig mogelijk ruis in ons beeld wensen. We<br />
hebben een foto die bijna perfect is en we vinden toch nog 19 lijnen die aan onze<br />
voorwaarden voldoen.<br />
De volgende stap in het programma bestaat erin te zoeken naar driehoeken in die lijnen. In<br />
Figuur 5 hebben we kunnen merken dat er vele driehoeken te vinden zijn met een beperkt<br />
aantal lijnen. In dit voorbeeld is het niet anders. We vinden 140 driehoeken in deze lijnen.<br />
Tabel 2 toont een uittreksel <strong>van</strong> de driehoeken die voldoen aan de eisen die we stellen aan<br />
een driehoek om een verkeersbord te kunnen zijn.<br />
a b c d e f lengte<br />
422 397 422 188 238 299 211<br />
422 397 422 224 260 310 180<br />
433 402 440 202 256 308 204<br />
433 402 441 117 238 299 227<br />
433 402 439 215 260 310 195<br />
118 235 115 389 256 308 157<br />
118 235 116 372 238 299 138<br />
118 235 115 387 260 310 158<br />
436 404 447 198 256 308 210<br />
436 404 448 172 238 299 233<br />
436 404 446 211 260 310 201<br />
137 245 130 381 256 308 138<br />
137 245 131 363 238 299 118<br />
137 245 130 379 260 310 139<br />
197 403 385 234 238 318 172<br />
397 403 383 212 221 309 193<br />
115 253 120 387 238 318 136<br />
Tabel 2 – Uittreksel <strong>van</strong> de driehoeken die aan de definitie beantwoorden<br />
61
Tabel 2 toont de punten (a,b),(c,d) ,(e,f) en de gemiddelde waarde <strong>van</strong> de lengte. Het is<br />
duidelijk dat we onmogelijk met zo’n groot aantal driehoeken verder kunnen werken.<br />
Daarom hebben we een functie geschreven om het aantal driehoeken te verminderen. De<br />
moeilijkheid bestaat er hier natuurlijk in dat we het verkeersbord niet uit de tabel mogen<br />
wissen. Na de verwijdering <strong>van</strong> driehoeken verkrijgen we een tabel met nog drie<br />
vermoedelijke <strong>verkeersborden</strong>.<br />
Tabel 3 geeft de 3 overgebleven driehoeken weer.<br />
a b c d e f lengte<br />
435 423 448 172 221 309 252<br />
118 235 115 387 260 310 158<br />
435 436 448 172 218 311 261<br />
Tabel 3 – Overgebleven driehoeken na verwijdering<br />
Nu we de vermoedelijke <strong>verkeersborden</strong> hebben gevonden, rest ons alleen nog om die uit<br />
ons beeld te extraheren. Daarom is het nodig de minimum- en maximumwaarden <strong>van</strong> elke<br />
driehoek te bepalen teneinde die mooi uit te knippen.<br />
De uitgeknipte figuren worden dan in de tabel driehoek opgeslagen. Die tabel gebruiken we<br />
dan voor de classificatie <strong>van</strong> de <strong>verkeersborden</strong>. Figuur 7 toont de tabel driehoek.<br />
driehoek =<br />
[248x272x3 uint8]<br />
[166x173x3 uint8]<br />
[251x285x3 uint8]<br />
Figuur 7 – Tabel driehoek<br />
In Figuur 7 zien we dat we niet meer met coördinaten, maar met een driedimensionale tabel<br />
en uint8 werken. In die tabel zijn foto’s opgeslagen. Omdat die foto’s uit de originele foto<br />
geknipt zijn, gaat het om RGB-beelden, dat is de reden waarom we een 3-dimensionale<br />
matrix verkrijgen. Uint8 wil zeggen dat de RGB-beelden door een 8 bit woord worden<br />
bepaald. Er zijn dus 256 kleurvariaties mogelijk in elk vlak <strong>van</strong> RGB.<br />
De volgende drie figuren tonen de uitgeknipte beelden. We geven ze op ware grootte weer.<br />
62
Beeld 4 Beeld 5<br />
Beeld 6<br />
Beeld 4 tot 6 : Extractie <strong>van</strong> origineel beeld<br />
Beeld 5 is het verkeersbord dat zeer goed uit de originele foto geknipt is.<br />
Beeld 4 en Beeld 6 zijn bijna identiek. Dat is de reden waarom we het programma om<br />
driehoeken uit de tabel te verwijderen tweemaal uitvoeren. Er blijven altijd wel foto’s over<br />
die te veel op elkaar lijken. Wanneer we het programma om driehoeken te verwijderen nog<br />
eens de tabel laten overlopen, zou een <strong>van</strong> de twee foto’s zeker worden verwijderd. We<br />
hebben ervoor geopteerd dat niet te doen. Proefondervindelijk hebben we vastgesteld dat na<br />
twee keer alle dubbele driehoeken uit het beeld verdwenen zijn, op enkele uitzonderingen<br />
na.<br />
63
Voorbeeld 2<br />
Beeld 7 – Origineel beeld<br />
In dit voorbeeld hebben we twee <strong>verkeersborden</strong> boven elkaar. We gaan hier dieper op in<br />
om na te gaan welke problemen dat kan vormen.<br />
Beeld 8 – Beeld 7 na roodfilter en edge <strong>detectie</strong><br />
Beeld 9 Beeld 10 Beeld 11 Beeld 12<br />
64
Beeld 13 Beeld 14<br />
Beeld 9 tot Beeld 15 : Extractie <strong>van</strong> origineel beeld<br />
Beeld 15<br />
In hoofdstuk 3 zien we dat wanneer zich twee cirkelvormige <strong>verkeersborden</strong> boven elkaar<br />
bevinden, we geen enkel probleem ondervinden om die twee cirkels perfect uit ons beeld te<br />
extraheren. Bij driehoekige <strong>verkeersborden</strong> ondervinden we wel enkele problemen. In dit<br />
voorbeeld gaan we er dieper op in waarom zich een probleem voordoet. We merken<br />
duidelijk dat we te veel driehoeken vinden. De veelheid aan driehoeken komt omdat het<br />
programma niet kan onderscheiden welke lijn bij welke driehoek hoort. Hij zal alle lijnen<br />
combineren en zo driehoeken vormen.<br />
We verduidelijken het probleem aan de hand <strong>van</strong> Figuur 8 tot Figuur 12. De lijnen die we<br />
via hoofdstuk 4 vinden, hebben geen begin- of eindpunt. We passen dat toe op Beeld 8 en<br />
tekenen die lijnen. De zwarte lijnen stellen het bovenste verkeersbord voor, de blauwe<br />
lijnen het onderste verkeersbord.<br />
In Beeld 9 en Beeld 10 zijn de <strong>verkeersborden</strong> perfect teruggevonden. In Figuur 8 zien we<br />
dat Beeld 9 de gele driehoek en Beeld 10 de groene driehoek is.<br />
65
Figuur 8 – Weergave <strong>van</strong> Beeld 9 en Beeld 10 in het lijnenspectrum<br />
Beeld 11 en Beeld 12 vinden we door de horizontale lijn <strong>van</strong> het bovenste verkeersbord te<br />
nemen. Dan vormen we een driehoek met een zwarte schuine zijde en een blauwe schuine<br />
zijde, waar<strong>van</strong> er telkens een zijde is die een hoek maakt <strong>van</strong> 60° met de horizontale en een<br />
zijde die een hoek maakt <strong>van</strong> 120° met de horizontale. In Figuur 9 zien we welke<br />
driehoeken we vinden. Beeld 11 en Beeld 12 zijn de weergave <strong>van</strong> de groene driehoeken in<br />
ons originele beeld. Deze twee beelden hebben een gemiddelde afstand <strong>van</strong> respectievelijk<br />
56 en 57 pixels, zodat ze nog net binnen de eisen liggen die we stellen.<br />
Figuur 9 – Weergave <strong>van</strong> Beeld 11 en Beeld 12 in het lijnenspectrum<br />
Beeld 13 en Beeld 14 zijn op dezelfde manier opgebouwd als Beeld 11 en Beeld 12. Ze<br />
maken gebruik <strong>van</strong> de horizontale zijde <strong>van</strong> het onderste verkeersbord. De schuine zijdes<br />
vinden we op een analoge manier als hierboven.<br />
We zien duidelijk dat Beeld 13 met de gele vlakken overeenkomt. Beeld 14 komt overeen<br />
met de grijze vlakken en de lichtgele driehoek.<br />
66
Figuur 10 – Weergave <strong>van</strong> Beeld 13 en Beeld 14 in het lijnenspectrum<br />
Beeld 15 is opgebouwd uit de twee schuine zijden <strong>van</strong> het bovenste bord en de horizontale<br />
<strong>van</strong> het onderste bord. Dat zien we duidelijk in Figuur 11.<br />
Figuur 11 – Weergave <strong>van</strong> Beeld 15 in het lijnenspectrum<br />
Het is bijna onmogelijk om dat te verhinderen. Zoals de Figuren 8 tot 11 aantonen vinden<br />
we perfect gelijkzijdige driehoeken die niet dicht genoeg bij elkaar liggen om als één<br />
driehoek beschouwd te worden. Dat is dan ook het grootste nadeel om met volle lijnen te<br />
werken. Het is nu aan de classificatie om alleen maar Beeld 9 en Beeld 10 als verkeersbord<br />
aan te duiden.<br />
In dit voorbeeld zien we ook dat het verkeersbord lichtjes schuin mag staan. In hoofdstuk 8<br />
zullen we de maximale omstandigheden waaronder het programma nog correct werkt<br />
bestuderen.<br />
We gaan nog enkele voorbeelden bekijken, hoewel niet meer zo uitgebreid.<br />
67
Voorbeeld 3<br />
Beeld 17 –<br />
Beeld 16 – Origineel beeld Extractie <strong>van</strong> origineel beeld<br />
We zien hier dat het verkeersbord perfect uitgeknipt wordt door het programma.<br />
Voorbeeld 4<br />
Beeld 18 – Origineel beeld Beeld 19<br />
Beeld 20 Beeld 21<br />
Beeld 19 tot 21 : Extractie <strong>van</strong> origineel beeld<br />
68
Dit is het voorbeeld dat we ook in hoofdstuk 3 gebruiken. We zien duidelijk aan Beeld 19<br />
dat de driehoek perfect wordt uitgeknipt. We vinden wel nog Beeld 20 en Beeld 21 in de<br />
ruis <strong>van</strong> de achtergrond. De oorzaak daar<strong>van</strong> kunnen we bij het ronde verkeersbord zoeken.<br />
Conclusie<br />
We bestudeerden vier voorbeelden. We hebben dat op een groot aantal beelden uitgetest.<br />
De vraag is nu: wat is een goed resultaat? In alle vier de voorbeelden vinden we het juiste<br />
verkeersbord terug. Maar in drie gevallen zijn er meerdere driehoeken uitgeknipt. Het<br />
vormt geen probleem om Beeld 4, Beeld 6, Beeld 20 en Beeld 21 (uit het eerste en vierde<br />
voorbeeld) als ‘geen verkeersbord’ te classificeren. In voorbeeld 2 kan dat moeilijker<br />
verlopen omdat er altijd een stuk verkeersbord opstaat.<br />
Van de bovenstaande voorbeelden kunnen we zeggen dat het programma in drie <strong>van</strong> de<br />
vier gevallen perfect werkt.<br />
We zien ook dat de positie <strong>van</strong> de top <strong>van</strong> de driehoek ten opzichte <strong>van</strong> de horizontale geen<br />
moeilijkheden veroorzaakt. We detecteren probleemloos gevaarborden en<br />
voorrangsborden.<br />
Als we alle tests die we hebben uitgevoerd – een 100-tal – samennemen, verkrijgen we<br />
toch in 80% <strong>van</strong> de gevallen een goed resultaat. Met een goed resultaat bedoelen we dat we<br />
het verkeersbord kunnen uitknippen met een minimum aan gevonden driehoeken die geen<br />
verkeersbord voorstellen.<br />
69
Hoofdstuk 6: Rechthoek<strong>detectie</strong><br />
Het volgende programmafragment is niet opgenomen in ons uiteindelijke<br />
herkenningssysteem. We hebben ons vooral toegelegd op het vinden <strong>van</strong> driehoeken<br />
en cirkels. Toch vonden we het de moeite waard eens dieper in te gaan op de <strong>detectie</strong><br />
<strong>van</strong> rechthoeken. Er zijn namelijk veel rechthoekige <strong>verkeersborden</strong> die nuttige<br />
informatie aan de bestuurder meedelen. De meeste <strong>van</strong> die borden bevatten echter een<br />
informatieve mededeling en daarom hebben we besloten ze niet te classificeren.<br />
In dit hoofdstuk gaan we dieper in op de vraag hoe we een rechthoek in het beeld<br />
kunnen vinden.<br />
Wat is een rechthoek?<br />
Een rechthoek is wiskundig gezien een vierhoek die 4 hoeken heeft <strong>van</strong> 90° en de vier<br />
zijden lopen twee aan twee evenwijdig met elkaar. Daarop hebben we ons gebaseerd om<br />
een rechthoek in het beeld te vinden. We zullen enkele beperkingen aan de rechthoek<br />
opleggen zodat we niet te veel vermoedelijke <strong>verkeersborden</strong> vinden, want dat is nu juist<br />
een <strong>van</strong> de grootste problemen bij het detecteren <strong>van</strong> rechthoekige <strong>verkeersborden</strong>.<br />
Implementatie<br />
We werken verder met de tabel die we genereerden na het stap lijn<strong>detectie</strong>. In die tabel<br />
staan alle lijnen die in ons beeld gevonden zijn. Omdat we rechte hoeken nodig hebben en<br />
alle rechthoeken horizontaal liggen, slaan we alle lijnen op die bij 0° en 90° gevonden zijn.<br />
We laten uiteraard een kleine speling <strong>van</strong> 4° toe. Bij 0° slaan we alle lijnen op <strong>van</strong> 176 tot<br />
179 en <strong>van</strong> 0 tot 4. Voor 90° nemen we <strong>van</strong> 86° tot 94°. Die waarden slaan we in aparte<br />
tabellen op.<br />
Aan de hand <strong>van</strong> Figuur 1 bekijken we de rest <strong>van</strong> het programma.<br />
Figuur 1 – Coördinaten <strong>van</strong> de hoekpunten <strong>van</strong> de rechthoek<br />
Uit Figuur 1 leiden we af dat we met die horizontale en vier verticale lijnen een groot<br />
aantal rechthoeken kunnen vinden.<br />
70
Om de rechthoeken te vinden, gaan we als volgt te werk. We nemen de eerste lijn <strong>van</strong> de<br />
horizontale tabel en de eerste lijn <strong>van</strong> de verticale tabel en berekenen het snijpunt <strong>van</strong> beide<br />
lijnen. Zo verkrijgen we het punt (a,b). Coördinaat a stelt de rij voor en b de kolom waar<br />
het snijpunt (a,b) te vinden is. Iedere keer als we een snijpunt berekenen, controleren we of<br />
dat snijpunt wel binnen de grenzen <strong>van</strong> het beeld ligt.<br />
Daarna nemen we de tweede lijn <strong>van</strong> de gevonden horizontale lijnen. We berekenen het<br />
snijpunt met de eerste verticale. We verkrijgen het punt (c,d). We berekenen daarna de<br />
snijpunten (e,f) en (g,h) met de tweede verticale.<br />
Nu bekomen we de eerste rechthoek, op Figuur 1 in het grijs aangegeven. Voordat we die<br />
in een tabel opslaan, testen we eerst of de lengte en breedte <strong>van</strong> de rechthoek aan de eisen<br />
qua minimum- en maximumlengte voldoen.<br />
De tweede rechthoek berekenen we met de tweede verticale en de eerste horizontale. Het<br />
programma zal de hierboven opgesomde bewerkingen uitvoeren om de tweede rechthoek te<br />
zoeken.<br />
Problemen<br />
We krijgen nog altijd zeer veel rechthoeken die niet aan de specificaties <strong>van</strong> een<br />
rechthoekig verkeersbord voldoen. De specificaties <strong>van</strong> een rechthoekig verkeersbord zijn<br />
ook zeer moeilijk te achterhalen omdat er zeer veel verschillende formaten zijn. Dat<br />
bemoeilijkt het verminderen <strong>van</strong> het aantal gevonden rechthoeken.<br />
Een ander groot probleem is de grote verscheidenheid in opschriften <strong>van</strong> rechthoekige<br />
<strong>verkeersborden</strong>. Meestal gaat het om een waarschuwing. Enkele voorbeelden zijn:<br />
oppassen voor ijzel – aangegeven door een sneeuwroos, brugdek, private parking, enz. Het<br />
is erg moeilijk om al die verschillende boodschappen te identificeren.<br />
Oplossingen<br />
We hebben geen verdere oplossingen voor die problemen. Enkele eisen zijn aan het<br />
programma toegevoegd, maar we hebben ze niet uitgebreid getest. Het hoofddoel was<br />
immers om cirkels en driehoeken te detecteren en te classificeren.<br />
Extraheren<br />
Net zoals in de hoofdstukken over cirkels en driehoeken zullen we de gedetecteerde<br />
rechthoeken in een tabel opslaan. We extraheren de rechthoeken uit de originele foto zodat<br />
we alleen nog maar de gevonden rechthoek op de foto zien.<br />
Ook bij een rechthoek moeten we het punt linksboven en rechtsonder berekenen. We<br />
zoeken in de tabel naar de kleinste en grootste coördinaten die de hoekpunten hebben. Met<br />
die coördinaten zijn we in staat de rechthoek mooi uit het beeld te knippen, zoals<br />
onderstaand voorbeeld aantoont.<br />
71
Voorbeeld<br />
Voorbeeld 1<br />
Figuur 2 – Origineel beeld Figuur 3 – Geëxtraheerd beeld<br />
Figuur 2 is de originele foto. We gaan eerst het blauw filteren, dan edge <strong>detectie</strong> uitvoeren<br />
en ten slotte de rechthoek zoeken en uitknippen. Het resultaat zien we in Figuur 3.<br />
72
Hoofdstuk 7: Classificatie <strong>van</strong> de <strong>verkeersborden</strong><br />
In de voorgaande hoofdstukken hebben we besproken hoe we het verkeersbord in het<br />
beeld lokaliseren. Als we het verkeersbord eenmaal hebben gevonden, willen we<br />
natuurlijk weten over welk verkeersbord het gaat. We gaan ook na of de vorige<br />
programma’s geen fouten hebben gemaakt. Een simpel voorbeeld <strong>van</strong> een fout is een<br />
driehoek of cirkel die gevonden werd in de ruis waar er geen verkeersbord aanwezig<br />
is.<br />
In dit hoofdstuk zullen we gebruik maken <strong>van</strong> neurale netten, Fourier-analyse en<br />
kleurenanalyse. Ad hoc hebben we enkele methodes gecreëerd om het verkeersbord te<br />
classificeren. We gaan niet tot op het laagste niveau classificeren, maar nemen er<br />
genoegen mee te weten of het al dan niet een gevarendriehoek, een verbods- of<br />
gebodsbord betreft. We zullen dit hoofdstuk in twee delen opsplitsen, het eerste deel<br />
handelt over driehoeken, het tweede deel gaat over cirkels.<br />
Wat is een neuraal net?<br />
Neurale netten zijn ontworpen om het menselijke brein na te bootsen. Een algoritme<br />
reageert altijd op dezelfde manier en wordt niet uit zichzelf ‘intelligenter’. Ook de<br />
computer heeft zijn beperkingen en kan maar één taak per keer uitvoeren. Wanneer we met<br />
neurale netten werken, hebben we die beperkingen niet.<br />
Een neuraal net bestaat uit neuronen zoals er ook in de hersenen aanwezig zijn. We hebben<br />
een aantal invoervariabelen en een aantal uitvoervariabelen. Het aantal invoervariabelen<br />
hangt af <strong>van</strong> het probleem dat we willen oplossen. Het aantal uitvoervariabelen is gelijk aan<br />
het aantal neuronen.<br />
We zullen verder gebruik maken <strong>van</strong> een perceptron met hard-limit transferfunctie (zie<br />
Figuur 1). Dat is het eenvoudigste voorbeeld <strong>van</strong> een neuraal net. Bij dit soort net kan de<br />
uitvoer slechts een 1 of een 0 zijn. Met andere woorden, het net kan enkel ja of neen<br />
antwoorden, wat natuurlijk al een beperking in gebruik <strong>van</strong> dat netwerk impliceert. Een<br />
andere belangrijke beperking is dat de uitvoer lineair separeerbaar moet zijn.<br />
Figuur 1: Voorstelling <strong>van</strong> een perceptron met hard-limit transferfunctie<br />
73
De P’s staan voor het aantal invoervariabelen. W staat voor de weights of het gewicht en<br />
kan voor elke invoer een andere waarde zijn. Hebben we bijvoorbeeld drie<br />
invoervariabelen, dan kan de eerste invoervariabele een ander gewicht hebben dan de<br />
tweede en/of de derde. De b staat voor bias.<br />
Figuur 2: Voorstelling <strong>van</strong> de parameters W en b<br />
Zoals we in Figuur 2 kunnen zien, hebben we twee vlakken. Het bovenste vlak (licht<br />
gearceerd) staat hier voor de uitkomst 1 terwijl het onderste vlak (wit gedeelte) voor de<br />
uitkomst 0 staat. Door de parameters W en b te wijzigen, kunnen we de plaats <strong>van</strong> de<br />
vlakken veranderen en zal het netwerk dus een andere uitkomst geven. De lijn L staat altijd<br />
loodrecht op de W-vector en kan door de bias b worden verschoven. Is de bias b gelijk aan<br />
0 dan zal de lijn door de oorsprong lopen.<br />
Hoe weten we nu in welk vlak onze set <strong>van</strong> invoervariabelen zal terechtkomen? Dat<br />
gebeurt door een berekening die als volgt te werkt gaat. Elke invoervariabele wordt<br />
vermenigvuldigd met zijn respectieve gewicht en daar wordt dan de bias bij opgeteld. Die<br />
waarde wordt dan in ons netwerk naar de hard-limit transferfunctie doorgestuurd, waar de<br />
verkregen waarde wordt vergeleken met een threshold. Is de waarde groter dan de<br />
thresholdwaarde, dan is de uitvoer 1. Is de waarde kleiner, dan is de uitvoer 0.<br />
Nu komt het er dus op aan de weights W en de bias b te kiezen zodat het netwerk de juiste<br />
uitvoer geeft. Het grote voordeel <strong>van</strong> een neuraal net is dat we de keuze niet zelf hoeven te<br />
maken, het netwerk doet dat voor ons via een trainingproces. We leggen een aantal, ook<br />
wel set genoemd, invoervariabelen aan het netwerk en vertellen welke uitvoer er bij hoort.<br />
Aan de hand <strong>van</strong> die set berekent het netwerk zijn weights en de bias. Wij leren het<br />
netwerk dus hoe het zijn uitvoer moet bepalen. Als het net eenmaal is getraind, kunnen we<br />
het netwerk simuleren en het vervolgens gebruiken om problemen op te lossen.<br />
We kiezen ervoor met een perceptron te werken omdat we niet willen weten over welk<br />
soort verkeersbord het precies gaat, maar enkel willen uitmaken of het al dan niet een<br />
verkeersbord is. Een ja/neen antwoord volstaat daarbij.<br />
74
Driehoeken<br />
Nu komt het erop aan om te weten of de geëxtraheerde driehoek effectief een gevaren<br />
driehoek is. Dit doen we door een set variabelen te definiëren die aan ons neuraal net<br />
worden gelegd. Om die variabelen te bepalen maken we gebruik <strong>van</strong> de Fourniertransformatie.<br />
Teneinde met een beter resultaat de Fournier-transformatie toe te passen hebben we<br />
ervoor gekozen eerst te filteren met een roodfilter (zie hoofdstuk 1), zodat er enkel nog<br />
maar rood in het beeld aanwezig is. Vervolgens voeren we een Fourier-transformatie uit.<br />
Met een Fourier-transformatie kunnen we bepaalde periodiciteiten in het beeld bepalen,<br />
zoals een ‘band’. Aangezien een gevarendriehoek uit drie ‘banden’ bestaat is dat een<br />
handig hulpmiddel in ons verdere onderzoek.<br />
a) Wat is een Fourier-transformatie?<br />
Met een Fourier-transformatie ontbinden we het beeld in zijn sinus- en cosinuscomponenten,<br />
zo stappen we over op het frequentie domein. Aangezien we met digitale<br />
beelden werken, passen we de Discrete Fourier Transform (DFT) toe.<br />
Daarvoor hebben we twee redenen:<br />
• De in- en uitvoer <strong>van</strong> de DFT zijn beide discreet en dat maakt het geschikt<br />
voor computermanipulaties.<br />
• MATLAB beschikt over een snel algoritme om de DFT te berekenen,<br />
gekend onder de naam Fast Fourier Transform (FFT).<br />
We berekenen de FFT met volgende formule voor een M x N beeld:<br />
F(p,q) is de DFT coëfficiënt <strong>van</strong> f(m,n). We interpreteren de formule als volgt: de waarde<br />
<strong>van</strong> elk punt F(p,q) verkrijgen we door de sommatie te nemen <strong>van</strong> elke vermenigvuldiging<br />
<strong>van</strong> het beeld met de overeenkomende basisfunctie.<br />
De basisfuncties zijn sinus en cosinus met oplopende frequenties. Bijvoorbeeld: F(0,0) stelt<br />
de DC-component voor, is niets anders dan de optelsom <strong>van</strong> f(m,n) en komt overeen met de<br />
gemiddelde helderheid <strong>van</strong> het beeld. F(M-1,N-1) komt overeen met de hoogste frequentie.<br />
Na de Fourier-transformatie verkrijgen we een beeld met complexe waarden die we in twee<br />
beelden kunnen opdelen, ofwel in het reële en imaginaire deel ofwel in magnitude en fase.<br />
We bekijken verder enkel de magnitude omdat dat stuk de meeste informatie bevat over<br />
geometrische figuren die zich in het beeld bevinden [4].<br />
Een band wordt na de transformatie opnieuw voorgesteld door een band die loodrecht op<br />
de oorspronkelijke band staat (figuur 3.).<br />
75
Figuur 3: Rechts voorstelling <strong>van</strong> een band, links voorstelling na Fourier-transformatie<br />
Het midden <strong>van</strong> de linker figuur, het rood gekleurde gedeelte, stelt de DC-waarde voor.<br />
Zoals eerder vermeld komt die overeen met F(0,0). Daar zit de grootste waarde, <strong>van</strong>daar de<br />
rode kleur. Hoe verder we <strong>van</strong> het middelpunt F(0,0) weggaan, hoe groter de frequentie<br />
wordt.<br />
Met dat in het achterhoofd zullen we een en ander uitbreiden om een verkeersbord via<br />
Fourier-analyse te gaan bepalen.<br />
b) Implementatie<br />
Als we nu naar een verkeersbord kijken, zien we het volgende:<br />
Beeld 1: Orgineel beeld Beeld 2: Na uitknippen driehoek en het<br />
toepassen <strong>van</strong> roodfilter<br />
Beeld 3: Na het toepassen <strong>van</strong> Fourier transformatie<br />
76
Zoals we op Beeld 2 kunnen zien, zijn er duidelijk drie banden aanwezig. Na de Fouriertransformatie,<br />
Beeld 3, zien we dat die drie banden duidelijk zichtbaar zijn. Zo wordt de<br />
horizontale een verticale. De band onder een hoek <strong>van</strong> 30° in het oorspronkelijke beeld<br />
wordt een band onder een hoek <strong>van</strong> 120°, en de band onder een hoek <strong>van</strong> 120° in het<br />
oorspronkelijke beeld een band onder een hoek <strong>van</strong> 30°. Het komt er nu op aan de waarde<br />
in die verschillende banden te bepalen.<br />
Als we de waarde bepalen en die vergelijken met een Fourier-analyse <strong>van</strong> een cirkel, die<br />
opnieuw een cirkel is na de transformatie, dan komen we tot de vaststelling dat deze<br />
waarden niet veel verschillen met de waarden <strong>van</strong> een driehoek.<br />
Hier zitten we met een probleem. We kunnen namelijk niet uitmaken of het om een<br />
driehoek dan wel een cirkel gaat. Om dat probleem op te lossen, kijken we naar de waarde<br />
die zich bevindt in een band op 50° en op 140° – daar moet een kleinere waarde aanwezig<br />
zijn dan in de banden op 30° en 120° – en vergelijken dat opnieuw met de analyse <strong>van</strong> een<br />
cirkel. Het grote probleem hier is dat de banden rond 30° en 120° uitgezaaid zijn, zoals we<br />
ook een beetje kunnen zien op Beeld 3. Er is toch nog voldoende energie aanwezig in de<br />
banden op 50° en 140°, waardoor we opnieuw niet kunnen uitmaken of het een cirkel of<br />
een driehoek betreft.<br />
Als we echter eerst de gemiddelde waarde berekenen in ons beeld en dan elke waarde in<br />
het beeld gaan verminderen met het gemiddelde, krijgen we negatieve waarden voor<br />
banden op 50° en 140° bij driehoeken.<br />
Zo is het programma dan ook opgebouwd, we berekenen de gemiddelde waarde in het<br />
beeld en verminderen elke waarde met het gemiddelde. Daarna berekenen we de waarde op<br />
30° en 120° en op 50° en 140°. Zo krijgen we voor een driehoek waarden voor de banden<br />
op 30° en 120° die rond 1 liggen. Voor de banden die zich op 50° en 140° bevinden,<br />
verkrijgen we waarden die rond -1 liggen. Bij een cirkel zijn die waarden over het<br />
algemeen allemaal negatief, op enkele uitzonderingen na waar de waarden <strong>van</strong> de cirkel<br />
exact overeenkomen met die <strong>van</strong> een driehoek. Daarmee kunnen we eenduidig een<br />
gevarendriehoek bepalen.<br />
Om te weten hoe we een gevarendriehoek <strong>van</strong> een voorrangsdriehoek kunnen<br />
onderscheiden, kijken we waar de top ligt. Ligt de top onder de basis, dan spreken we <strong>van</strong><br />
een voorrangsdriehoek. Ligt hij erboven, dan spreken we <strong>van</strong> een gevarendriehoek.<br />
De eenvoud maakt het programma snel, maar we moeten er toch bij vermelden dat het een<br />
grote beperking heeft. Zo kan het enkel bepalen of het al dan niet om een gevarendriehoek<br />
gaat, maar niet precies welk type het is, met uitzondering <strong>van</strong> het voorrangsbord.<br />
Cirkels<br />
We bekijken hier de cirkels die we <strong>van</strong> het cirkelprogramma terugkrijgen (zie hoofdstuk 3<br />
cirkel<strong>detectie</strong>) en gaan na of het effectief om een cirkelvormig verkeersbord gaat. Bij<br />
cirkels hebben we een keuze tussen gebods- en verbodsborden. We analyseren dat verder,<br />
wat we bij driehoeken niet hebben gedaan, en hebben enkele <strong>verkeersborden</strong> eruit gehaald.<br />
Zo kijken we hoe we een eenrichtingsbord en een geen toegang in beide richtingenbord,<br />
met enkel een rode band en volledig wit <strong>van</strong>binnen, gaan bepalen. De andere<br />
<strong>verkeersborden</strong> zetten we onder de noemer <strong>van</strong> ofwel gebodsbord ofwel verbodsbord.<br />
77
a) Algemeen<br />
Als we de Fourier transformatie toepassen op een cirkelvormige band, zien we dat het<br />
opnieuw een cirkelcirkelvormige band is. Het is echter niet zo duidelijk als bij de<br />
driehoeken. Hier hebben we enkele ongemakken. Zo kennen we na de transformatie de<br />
straal <strong>van</strong> de cirkel niet. Wat met cirkels die volledig opgevuld zijn? Denk aan de<br />
eenrichtingsborden en alle gebodsborden waar we na de transformatie niet meer met een<br />
cirkelvormige band, maar met een volledige schijf overblijven.<br />
We hebben uitvoerig getest op de ronde borden en hebben moeten concluderen dat deze<br />
methode niet geschikt is om cirkelvormige <strong>verkeersborden</strong> te bepalen.<br />
Een betere manier is gaan kijken naar de kleurverhoudingen binnen de cirkel. We<br />
extraheren daarvoor de cirkel die gevonden werd via het cirkel<strong>detectie</strong>programma (zie<br />
hoodstuk 4: cirkel<strong>detectie</strong>, met een marge uit het beeld. Daarmee bedoelen we dat we niet<br />
enkel mooi de cirkel, maar in feite een stuk meer uitknippen. (Voorbeeld hieronder: Beeld<br />
4 en Beeld 5).<br />
Het opzettelijk te groot uitknippen zorgt ervoor dat als we op het uitgeknipte beeld<br />
opnieuw naar cirkels zoeken, we die ook opnieuw zullen vinden. Knippen we zonder<br />
marge uit, dan bestaat de kans dat we geen cirkel meer vinden omdat de cirkel grotendeels<br />
samenvalt met de rand <strong>van</strong> het beeld. .<br />
Binnen het verkeersbord zoeken we naar vier kleuren, met name rood, wit, blauw en zwart.<br />
Om die kleuren te bepalen gebruiken we opnieuw de filters die zijn beschreven in<br />
hoofdstuk 1. Het grote verschil is wel dat we nu niet filteren, maar de voorwaarde<br />
gebruiken die de kleur bepaalt. Nu tellen we de pixels die aan de voorwaarde voldoen om<br />
rood, blauw, wit of zwart te zijn.<br />
Bij het bepalen <strong>van</strong> de invoervariabelen voor het neuraal net hebben we ervoor gekozen<br />
niet alleen de vier kleuren die we binnen de cirkel vinden, mee te geven. Zo hebben we bij<br />
een verbodsbord een rode band, waardoor we twee cirkels zullen vinden. We gaan het<br />
aantal rode pixels tellen die zich in die band tussen de twee cirkels bevinden en het<br />
percentage, berekend via de oppervlakte, ook meesturen. Bij eenrichtingsborden en<br />
verbodsborden zullen die getallen gelijk zijn aan nul, aangezien we daar maar één cirkel<br />
zullen vinden. Ook geven we nog de totale som mee <strong>van</strong> de vier kleuren die in de binnenste<br />
cirkel gevonden zijn. Zo komen we aan zeven invoervariabelen: het aantal rode pixels<br />
gevonden tussen de twee cirkels, het aantal rode, blauwe, zwarte en witte pixels gevonden<br />
binnenin de cirkel, het percentage <strong>van</strong> de rode pixels gevonden in de band en het totaal <strong>van</strong><br />
de vier kleuren gevonden in de binnenste cirkel.<br />
De keuze om voor alle ronde borden die zeven invoervariabelen te gebruiken, ligt hem in<br />
het feit dat we op die manier maar één programma moeten maken om die kleuren te<br />
bepalen en we in principe ook maar één net nodig hebben om dat te testen. We hebben<br />
verschillende netten – perceptrons – , gemaakt voor de verschillende mogelijkheden die we<br />
in de inleiding hebben aangehaald.<br />
78
Beeld 4: Uitgeknipt verkeersbord zonder Beeld 5: Uitgeknipt verkeersbord met<br />
marge marge<br />
b) Implementatie<br />
Voor eenrichtingsborden, zoals het bord op Beeld 4 en Beeld 5, zullen we maar één cirkel<br />
terugvinden als we het cirkelprogramma laten lopen. We kijken nu naar de kleuren binnen<br />
het verkeersbord, we kunnen dus spreken <strong>van</strong> een eenrichtingsbord als er voldoende rood<br />
en een beetje wit in het beeld aanwezig is. Dat lijkt misschien maar vaag, maar het werkt in<br />
71% <strong>van</strong> de gevallen correct.<br />
Beeld 6: Geen toegang in beide richtingen<br />
Bij het bord in Beeld 6 – geen toegang in beide richtingen – zoeken we naar twee cirkels op<br />
ons beeld, met name de buitenste en de binnenste cirkel <strong>van</strong> de rode band. Als die eenmaal<br />
gevonden zijn, kijken we naar het aantal rode pixels tussen de twee cirkels en bepalen we<br />
de kleuren binnen de kleinste cirkel. Bij deze <strong>verkeersborden</strong> is duidelijk te zien dat er een<br />
grote hoeveelheid wit binnen de kleinste cirkel moet aanwezig zijn en dat de band tussen de<br />
twee cirkels volledig rood moet zijn. Toch is een kleine hoeveel rood in de binnenste cirkel<br />
toegestaan, omdat de binnenste cirkel niet altijd exact wordt teruggevonden als gevolg <strong>van</strong><br />
de randomfactor die we bij de cirkel<strong>detectie</strong> gebruiken.<br />
Het classificeren <strong>van</strong> blauwe borden, de gebodsborden, en de rode borden, de<br />
verbodsborden, gebeurt analoog zoals hierboven.<br />
En toch komt het voor dat een bord waar niets abnormaals mee aan de hand is niet kan<br />
worden geclassificeerd. Reden daarvoor vinden we bij een verkeerde kleur – doorgaans<br />
zwart – die op het beeld aanwezig is doordat het beeld bij valavond werd genomen, of<br />
79
doordat er pakweg een stikker op het bord hangt, het bord is verwaarloosd, enzovoort.<br />
Daarom is het aan te bevelen deze methodes verder te ontwikkelen.<br />
Voorbeelden<br />
Bij deze voorbeelden beperken we ons tot de resultaten <strong>van</strong> het classificatie programma,<br />
dus waar het neuraal net ‘ja’ antwoordde. Het extraheren <strong>van</strong> het originele beeld tonen we<br />
hier niet meer.<br />
Voorbeeld 1<br />
Beeld 7: gebodsbord en een gevarendriehoek<br />
Het classificatie programma geeft als uitkomst:<br />
Er is een gebodsbord en een gevarendriehoek gevonden. Hier kunnen we duidelijk zien dat<br />
het programma juist heeft geoordeeld.<br />
Voorbeeld 2<br />
Beeld 8: Geen toegang in beide richtingen Beeld 9: Verbodsbord<br />
De uitkomst hier is geen toegang in beide richtingen. Dus, hoewel het bord niet perfect wit<br />
is, wat zorgt voor zwart in het verkeersbord, is de beoordeling wel juist.<br />
80
De vrijheid om borden die niet perfect wit zijn toch te laten herkennen, kan fouten in de<br />
beoordeling genereren. Zo toont Beeld 9 duidelijk dat het geen bord betreft waarbij toegang<br />
in beide richtingen verboden is en toch wordt het zo beoordeeld.<br />
Voorbeeld 3<br />
Beeld 10: Eenrichtingsbord<br />
Dit beeld is <strong>van</strong>uit een rijdende auto genomen. Het classificatieprogramma geeft als<br />
uitkomst: er is een eenrichtingsbord op het beeld gevonden. De beoordeling is dus correct.<br />
Conclusie<br />
We hebben een eenduidige methode kunnen ontwikkelen die snel en heel efficiënt werkt<br />
om gevarendriehoeken te herkennen. Ons neuraal net geeft in ongeveer 87% <strong>van</strong> de<br />
gevallen een correct antwoord.<br />
Bij cirkels ligt dat percentage lager omdat de methode enkel en alleen de<br />
kleurverhoudingen binnenin de cirkel controleert. De resultaten zijn daardoor niet zo goed<br />
als bij driehoeken, maar ze zijn wel geruststellend. Zo kunnen we bij cirkels in 76%<strong>van</strong> de<br />
gevallen met zekerheid zeggen dat het net zijn werk goed heeft gedaan.<br />
81
Hoofdstuk 8: Testen <strong>van</strong> het herkenningssysteem<br />
Teneinde na te gaan in hoeverre ons herkenningssysteem bij beelden <strong>van</strong> zwakke<br />
kwaliteit werkt, hebben we onze originele foto’s elektronisch bewerkt met ruis,<br />
bepaalde visuele effecten en hebben we ze geroteerd. In dit hoofdstuk kijken we eerst<br />
hoe ons systeem op ruis en visuele effecten reageert, vervolgens bepalen we onder<br />
welke hoeken we de borden mogen roteren om ze alsnog te detecteren.<br />
Gaussian Noise<br />
Op ons originele beeld gaan we extra ruis toevoegen volgens de methode <strong>van</strong> Gauss. Die<br />
methode zal de pixels <strong>van</strong> het originele beeld veranderen. Er wordt bij elke pixel een getal<br />
bijgeteld dat random gekozen is. Daardoor zullen er kleurveranderingen in het beeld<br />
ontstaan. Ons programma ondervindt veel problemen om <strong>verkeersborden</strong> te herkennen die<br />
extra ruis bevatten door toepassing <strong>van</strong> de methode <strong>van</strong> Gauss. De problemen ontstaan<br />
omdat we naar kleur zoeken en die kleuren zijn nu veranderd. We gaan er dieper op in aan<br />
de hand <strong>van</strong> een voorbeeld.<br />
Beeld 1 – Origineel beeld Beeld 2 – Na toevoeging <strong>van</strong> Gaussian ruis<br />
We zien weinig verschil tussen Beeld 1 en Beeld 2. Er is ook maar weinig ruis toegevoegd,<br />
maar dat is het maximum aan ruis dat we kunnen toevoegen. We gaan eens kijken wat er<br />
gebeurt wanneer we de roodfilter op Beeld 1 en Beeld 2 toepassen.<br />
82
Beeld 3 – Beeld 1 na roodfilter Beeld 4 – Beeld 2 na roodfilter<br />
Hier merken we waar het probleem zich lokaliseert. Op Beeld 3 zien we dat het<br />
verkeersbord een witte band heeft. Bij Beeld 4 is die band gebroken door de verkleurde<br />
pixels. Zoals we kunnen zien op Beeld 5 en Beeld 6 zal de edge <strong>detectie</strong> daar grote<br />
problemen mee hebben.<br />
Beeld 5 – Beeld 3 na edge <strong>detectie</strong> Beeld 6 – Beeld 4 na edge <strong>detectie</strong><br />
Op Beeld 6 kunnen we zeer duidelijk zien waar het probleem ligt. De edge <strong>detectie</strong> vindt in<br />
Beeld 5 maar enkele randen omdat we een witte band in ons beeld hebben. Die band zal in<br />
het beste geval na edge <strong>detectie</strong> maar twee lijnen zijn. Een lijn wordt getrokken wanneer<br />
het programma een kleurverandering opmerkt. Bij een volledig witte band is er geen<br />
kleurverandering en zal de edge <strong>detectie</strong> beide uiterste randen slecht detecteren. Bij Beeld 6<br />
zien we zeer veel randen. Dat komt door de niet homogene samenstelling <strong>van</strong> de rode band<br />
<strong>van</strong> het verkeersbord. Er zijn te veel pixels die niet meer in het interval liggen om als rood<br />
te worden aanvaard en daarom zijn er veel meer randen in het verkeersbord te vinden. Het<br />
herkenningssysteem zal in Beeld 6 veel meer lijnen terugvinden.<br />
Het herkenningssysteem vindt in Beeld 6 tweeëntwintig verschillende driehoeken,<br />
waaronder het verkeersbord (zie Beeld 7). Er zijn ook drie cirkels in Beeld 6 gevonden, wat<br />
niet verwonderlijk is gezien het grote aantal pixels dat we in Beeld 6 terugvinden.<br />
Het feit dat ons programma niet zo goed werkt na het toevoegen <strong>van</strong> ruis is niet echt een<br />
probleem. In werkelijkheid zullen namelijk nooit zo veel pixels tegelijkertijd <strong>van</strong> kleur<br />
veranderen.<br />
83
Beeld 7 – Geëxtraheerde driehoek na toevoeging <strong>van</strong> ruis via de Gauss methode<br />
Wazig maken <strong>van</strong> het beeld<br />
We kunnen het beeld op allerlei manieren wazig maken. Bij de voorbeelden hieronder<br />
tonen we enkel het geëxtraheerde beeld. De originele foto’s zijn op de bijgeleverde cd te<br />
vinden, onder directory Beelden hoofdstuk 8. De volgende beelden zijn in PhotoShop<br />
bewerkt.<br />
Beeld 8 - Gaussian blur Beeld 9 – Dust & Scratches<br />
Beeld 10 – Motion Beeld 11 – Motion 90°<br />
Aan de hand <strong>van</strong> deze vier voorbeelden zien we dat ondanks het vrij troebele beeld, we er<br />
toch nog in slagen de <strong>verkeersborden</strong> uit de foto te halen. Een groot voordeel, want vertaald<br />
naar opnames in de praktijk betekent dit dat de lens niet altijd perfect scherp of trilvrij moet<br />
84
staan of onberispelijk proper hoeft te zijn. Op Beeld 10 en Beeld 11 hebben we Motion<br />
toegepast. PhotoShop probeert het beeld zo veel mogelijk te laten lijken op een foto die<br />
<strong>van</strong>uit een bewegend object genomen is.<br />
In Beeld 12 en 13 bekijken we een foto die <strong>van</strong>uit een rijdende auto is genomen <strong>van</strong> op de<br />
passagierszetel.<br />
Beeld 12 – Origineel beeld <strong>van</strong>uit een rijdende auto Beeld 13 – Geëxtraheerd beeld<br />
Beeld 14 is onscherp door een trilling <strong>van</strong> het fototoestel, maar uit beeld 15 blijkt dat dit<br />
weinig problemen oplevert voor de <strong>detectie</strong>. We zien ook dat er geen problemen zijn<br />
wanneer er bijvoorbeeld enkele bladeren voor het bord hangen.<br />
Beeld 14 – Origineel beeld, onscherp Beeld 15 – Geëxtraheerd beeld<br />
Allerlei bewerkingen<br />
Hierna publiceren we nog enkele geëxtraheerde beelden <strong>van</strong> bewerkte beelden. De<br />
volledige beelden zijn op de cd te vinden onder de directory Beelden hoofdstuk 8. We<br />
gaan niet verder in op wat er allemaal mogelijk is met andere vervormingen omdat dat in<br />
werkelijkheid nooit zal voorkomen, en laten de beelden spreken voor zich.<br />
85
Beeld 16 – Glass Beeld 17 – Watercolor<br />
Beeld 18 – Mosaic Beeld 19 – Sponge<br />
Beeld 20 – Pointilize Beeld 21 – 5 lights<br />
86
Beeld 22 – Flashlight Beeld 23 – Bricks<br />
Beeld 24 – Mosaic tiles Beeld 25 – Glowing edges<br />
Beeld 26 – Tiles Beeld 27 – Underpainting<br />
87
Rotaties<br />
Zoals we in voorgaande hoofdstukken al hebben gezien, is het bijna onmogelijk om het<br />
verkeersbord perfect vlak in beeld te brengen. We hebben meestal te maken met een hoek,<br />
maar hoe groot mag die hoek zijn?<br />
a) Cirkelvormige <strong>verkeersborden</strong><br />
Het probleem bij cirkelvormige <strong>verkeersborden</strong> is de vervorming <strong>van</strong> de cirkel wanneer die<br />
niet perfect recht op het beeld staat. Die vervorming uit zich in het feit dat de cirkel<br />
ellipsvormig wordt. De volgende voorbeelden tonen aan dat dit verschijnsel weinig<br />
problemen oplevert.<br />
Voorbeeld 1<br />
Beeld 28 – Origineel beeld Beeld 29 – Geëxtraheerd beeld<br />
In dit voorbeeld zien we dat het geen probleem vormt om een verkeersbord uit het beeld te<br />
extraheren wanneer het meer op een ellips lijkt. Op Beeld 29 zien we hoe we dit<br />
verkeersbord kunnen herkennen.<br />
De rode cirkel is ongeveer de cirkel die het programma heeft gevonden. Er zijn dus genoeg<br />
pixels op de rechterrand <strong>van</strong> het verkeersbord aanwezig die voldoen aan de eigenschap om<br />
een cirkel te vormen. Daarom knipt het programma niet enkel het verkeersbord uit, ook aan<br />
de meest elliptische zijde <strong>van</strong> het bord toont het nog een stuk <strong>van</strong> de omgeving.<br />
In het volgende voorbeeld zien we hetzelfde effect.<br />
88
Voorbeeld 2<br />
Beeld 28 – Origineel beeld Beeld 29 – Geëxtraheerd beeld<br />
In Beeld 29 zien we hetzelfde effect als in Voorbeeld 1 besproken, maar nu met de<br />
elliptische zijde <strong>van</strong> het verkeersbord aan de rechterkant.<br />
b) Driehoekige <strong>verkeersborden</strong><br />
Driehoekige <strong>verkeersborden</strong> kunnen we roteren ten opzichte <strong>van</strong> de horizontale as. We<br />
gaan na welk effecten dit geeft op ons herkenninssysteem.<br />
Voorbeeld<br />
In het eerste voorbeeld kijken we wat er gebeurt wanneer we het verkeersbord<br />
draaien ten opzichte <strong>van</strong> de horizontale. Daarvoor gebruiken we geen foto die we<br />
zelf hebben genomen, maar een prent <strong>van</strong> een verkeersbord. Dat doen we om er<br />
100% zeker <strong>van</strong> te zijn dat het verkeersbord zelf geen kleine hoekverdraaiing heeft<br />
ten opzichte <strong>van</strong> de grond. We verkrijgen de rotatie door een functie in MATLAB<br />
zodat we er ook zeker <strong>van</strong> zijn dat de hoek correct is.<br />
Beeld 30 – Origineel beeld<br />
89
Conclusie<br />
Beeld 31 – Origineel 4° gedraaid Beeld 32 – Geëxtraheerd beeld<br />
Op Beeld 32 zien we de maximale rotatie die mogelijk is voor een verkeersbord.<br />
Dat is 4°. Wanneer we Beeld 30 5° draaien, vindt het programma geen enkele<br />
driehoek die mogelijk een verkeersbord is.<br />
Beeld 33 – Origineel 356° gedraaid Beeld 34 – Geëxtraheerd beeld<br />
Beeld 34 bewijst dat we het verkeersbord ook 4° in wijzerzin mogen draaien.<br />
In dit hoofdstuk hebben we de grenzen <strong>van</strong> het programma afgetast. Op sommige beelden<br />
zijn de resultaten verbluffend, op andere beelden zijn de resultaten minder.<br />
Zolang er niet veel aan de kleur verandert, behalen we zeer goede resultaten. Wanneer we,<br />
zoals met de Gaussian blur, de kleur <strong>van</strong> de pixels wijzigen, verkrijgen we veel minder<br />
goede resultaten. Dat is logisch, want de eerste stap die we ondernemen is het zoeken naar<br />
kleur in het beeld.<br />
De resultaten die we krijgen wanneer het beeld ‘bewogen’ is, zijn heel goed. In de praktijk<br />
is dat erg nuttig, want als we bijvoorbeeld beelden krijgen <strong>van</strong> een camera in de auto<br />
moeten we er rekening mee houden dat dit beeld niet altijd even scherp zal zijn.<br />
De hoek waaronder cirkels kunnen worden genomen is zeer ruim. Hoewel de cirkels<br />
hierdoor eerder ellipsvormig worden detecteert ons herkenningssysteem ze nog altijd. Bij<br />
gedraaide borden zijn de toleranties dan weer heel wat kleiner. Een hoek <strong>van</strong> 4° in<br />
positieve of negatieve zin is de maximale afwijking.<br />
90
Hoofdstuk 9: Conclusie<br />
In dit laatste hoofdstuk vatten we eerst nog eens samen hoe we ons<br />
herkenningssysteem hebben opgebouwd, dus volgens welke stappen we te werk gaan<br />
teneinde tot een behoorlijk resultaat te komen.<br />
Vervolgens belichten we de resultaten <strong>van</strong> een complete <strong>detectie</strong>run. Daar waar we<br />
voordien stap per stap het systeem hebben uitgetest laten we nu alle stappen ineens los<br />
op de meest complexe beelden.<br />
Het herkenningssysteem slaagt erin om in 73% <strong>van</strong> de onderzochte gevallen een<br />
perfect resultaat te geven.<br />
Opbouw <strong>van</strong> het volledige herkenningssysteem<br />
Het herkenningssysteem is in twee grote delen opgebouwd, namelijk een rood gedeelte en<br />
een blauw gedeelte. We weten dat we in de blauwe <strong>verkeersborden</strong> geen driehoeken<br />
moeten zoeken omdat er geen blauwe verkeersdriehoeken bestaan. Daardoor is het blauwe<br />
gedeelte minder uitgebreid dan het rode gedeelte. We filteren het originele beeld met de<br />
blauwfilter, passen de edge detector toe en zoeken naar cirkels. De gevonden cirkels<br />
onderzoeken we met het neuraal net, dat de classificatie bepaalt. De classificatie bij de<br />
blauwe ronde borden is enkel een ja/neen antwoord.<br />
Het rode gedeelte vraagt iets meer tijd omdat we hier ook nog de gevarendriehoeken in<br />
rekening moeten brengen. Het begin verloopt analoog aan het blauwe gedeelte; we passen<br />
de roodfilter en de edge detector toe. We zoeken nu naar cirkels en lijnen.<br />
Bij de rode cirkels hebben we er twee borden uitgehaald die we kunnen classificeren, het<br />
eenrichtingsbord en het geen toegang in beide richtingen bord. De andere borden vallen<br />
onder de noemer verbodsbord. De classificatie zal hier dus een <strong>van</strong> die drie antwoorden<br />
geven als het om een verkeersbord gaat.<br />
De gevonden lijnen worden onderzocht om er driehoeken en rechthoeken mee te maken.<br />
De gevonden driehoeken worden terug aan een neuraal net gelegd die de classificatie<br />
bepaalt. Hier bepalen we gevarendriehoeken en de verleen voorrangsdriehoek.<br />
De gevonden rechthoeken worden niet verder bekeken. Zij zijn niet in het volledige<br />
herkenningssysteem opgenomen.<br />
91
Voorbeelden<br />
Voorbeeld 1<br />
Beeld 1 – Origineel beeld<br />
Wanneer we het volledige <strong>detectie</strong>systeem op Beeld 1 uitvoeren, verkrijgen we in eerste<br />
instantie volgende vermoedelijke <strong>verkeersborden</strong>.<br />
Beeld 2 – Geëxtraheerd beeld Beeld 3 – Geëxtraheerd beeld<br />
Beeld 4 – Geëxtraheerd beeld<br />
92
We zien aan Beeld 2 en Beeld 4 dat de juiste figuren in het originele beeld worden<br />
gevonden. Bij Beeld 3 zou je ook kunnen denken dat het beeld gevonden is door het<br />
cirkel<strong>detectie</strong>systeem, maar dat is niet het geval. Wanneer we nagaan waarom we Beeld 3<br />
vinden, merken we dat dit door het driehoek<strong>detectie</strong>systeem is. De reden daarvoor is vrij<br />
simpel. We vinden twee lijnen die <strong>van</strong> het driehoekige verkeersbord komen. De horizontale<br />
komt door de camera zelf. Op het originele beeld staat immers een datum in rood-oranje.<br />
Die datum wordt als een lijn beschouwd.<br />
Het classificatiesysteem vindt de volgende resultaten:<br />
Beeld 2: er is een verleen voorrangsdriehoek op het beeld gevonden.<br />
Beeld 3: er is een gevarendriehoek op het beeld gevonden.<br />
Beeld 4: er is een gebodsbord op het beeld gevonden.<br />
Het classificatiesysteem heeft hier een fout gemaakt en dat komt door het volgende:<br />
Beeld 3 verkrijgen we zoals eerder vermeld door driehoek<strong>detectie</strong>, dus zullen we verder<br />
zoeken naar de ‘banden’ <strong>van</strong> de driehoeken (zie hoofdstuk 7). Er wordt geen onderzoek<br />
meer gedaan naar cirkels op het geëxtraheerde beeld.<br />
De cirkel zorgt hier toevallig voor dezelfde waarden als een driehoek, wat uitzonderlijk is,<br />
en het neuraal net zegt ons dus dat er een driehoek gevonden is. Als er een driehoek wordt<br />
gevonden, onderzoeken we nog of het een gevarendriehoek of verleen voorrangsdriehoek<br />
betreft. In dit geval ligt de top boven de basis, <strong>van</strong>daar dat de classificatie zegt dat het om<br />
een gevarendriehoek gaat.<br />
Voorbeeld 2<br />
Beeld 5 – Origineel beeld Beeld 6 en Beeld 7 – Geëxtraheerde beelden<br />
Dit tweede voorbeeld toont aan dat beide <strong>verkeersborden</strong> probleemloos door het<br />
<strong>detectie</strong>systeem worden gevonden.<br />
Het classificatiesysteem vindt de volgende resultaten:<br />
Beeld 6: er is een gebodsbord op het beeld gevonden.<br />
Beeld 7: er is een verleen voorrangsdriehoek op het beeld gevonden.<br />
De classificatie heeft het hier dus 100% bij het rechte eind. De twee geëxtraheerde beelden<br />
werden perfect geclassificeerd.<br />
93
Voorbeeld 3<br />
Beeld 8 – Origineel beeld Beeld 9 en 10 – Geëxtraheerde beelden<br />
In dit derde voorbeeld zien we dat het programma om de geometrische figuren te zoeken<br />
perfect werkt. Er werd een blauw bord gevonden – Beeld 9 – en een rood bord – Beeld 10.<br />
Er werd geen enkel vermoedelijk driehoekig verkeersbord gevonden.<br />
Het classificatiesysteem vindt de volgende resultaten:<br />
Beeld 9: er is een gebodsbord op het beeld gevonden.<br />
Beeld 10: er is een eenrichtingsbord op het beeld gevonden.<br />
De classificatie is hier perfect verlopen.<br />
Voorbeeld 4<br />
Uiteraard werken niet alle beelden zo goed als in de eerste drie voorbeelden. Met dit<br />
voorbeeld willen we aantonen waar het grootste probleem <strong>van</strong> ons herkenningssysteem<br />
zich bevindt.<br />
Beeld 11 – Origineel beeld<br />
Op Beeld 11 zien we vier ronde <strong>verkeersborden</strong> en één driehoekig bord. Wanneer we Beeld<br />
11 met het herkenningssysteem testen, constateren we dat het systeem zeer veel rekentijd<br />
nodig heeft. Na onderzoek naar de reden daar<strong>van</strong> hebben we gevonden dat dit te wijten is<br />
94
aan de driehoek<strong>detectie</strong>. Er zijn in dit beeld veel te veel lijn teruggevonden. We kunnen dat<br />
zien aan Beeld 12, het beeld dat we verkrijgen na de kleurfilter en de edge <strong>detectie</strong>.<br />
Beeld 12 – Origineel beeld na roodfilter en edge <strong>detectie</strong><br />
We zien hier duidelijk dat het oranje bord voor de problemen zorgt. Het oranje bord heeft<br />
Hue-waarden die rond 20 schommelen. Dat is de grens waarop wij ons rood detecteren. Dat<br />
wil zeggen dat er heel veel kleurveranderingen in het oranje bord zitten, wat weer tot zeer<br />
veel pixels en zeer veel lijnen zal lijden. De driehoek<strong>detectie</strong> heeft het moeilijk met te veel<br />
lijnen, want dan zal het veel vermoedelijke driehoeken vinden. De cirkel<strong>detectie</strong> werkt ook<br />
niet perfect wanneer er na de edge <strong>detectie</strong> erg veel witte pixels op het beeld staan. Er<br />
worden twee rode en één blauw vermoedelijk verkeersbord gevonden, maar in geen enkel<br />
geval werd er een verkeersbord getoond. Dat komt natuurlijk door de randomfactor <strong>van</strong> de<br />
cirkel<strong>detectie</strong>. Als er zoveel witte pixels op Beeld 12 staan, kunnen we ons makkelijk<br />
inbeelden dat het zeer toevallig zou zijn mocht de randomfactor telkens drie pixels nemen<br />
die op een <strong>van</strong> de <strong>verkeersborden</strong> liggen. Dat is meteen ook de grootste tekortkoming <strong>van</strong><br />
het herkenningssysteem. Als er na de edge <strong>detectie</strong> nog te veel pixels wit zijn, heeft het<br />
herkenningssysteem bijna altijd moeilijkheden om de juiste figuren uit ons beeld te<br />
extraheren. Dat komt door een teveel aan rode of blauwe voorwerpen die we in de<br />
achtergrond vinden.<br />
Als we de drie borden zelf uit ons beeld extraheren, zien we dat het herkenningssysteem er<br />
geen moeite mee heeft om ze terug te vinden. We gaan er dieper op in aan de hand <strong>van</strong><br />
Beeld 13.<br />
95
We vinden de volgende beelden terug:<br />
Beeld 17 – Geëxtraheerd beeld<br />
Beeld 13 – Extractie <strong>van</strong> Beeld 11<br />
Beeld 14 en Beeld 15 en Beeld 16 – Geëxtraheerd beeld<br />
Deze vier beelden vindt het herkenningssysteem terug. Wanneer we er dieper op ingaan<br />
welk onderdeel <strong>van</strong> het systeem de beelden terugvindt, concluderen we dat de Beeld 14 tot<br />
Beeld 16 door de roodfilter en de cirkel<strong>detectie</strong> gevonden zijn. Beeld 17 werd gevonden<br />
door de blauwfilter en de cirkel<strong>detectie</strong>. De driehoek<strong>detectie</strong> vindt geen enkele<br />
vermoedelijke driehoek terug.<br />
96
De classificatie vindt bij deze beelden :<br />
Beeld 14,15,16: er is een geen toegang in beide richtingen bord op het beeld gevonden.<br />
Beeld 17: er is een gebodsbord op het beeld gevonden.<br />
Hier is de classificatie totaal verkeerd. Waarom de beelden 14 tot 16 verkeerd werden<br />
geclassificeerd, ligt aan de training <strong>van</strong> het neuraal net op geen toegang in beide richtingen.<br />
We hebben er namelijk voor gekozen dat we <strong>verkeersborden</strong> die bestaan uit een rode band<br />
met volledig wit <strong>van</strong>binnen – het geen toegang in beide richtingen verkeersbord – ook<br />
willen herkennen als ze vuil zijn. Daarmee bedoelen we dat er iets <strong>van</strong> zwart op het beeld<br />
aanwezig mag zijn. In dit voorbeeld is er ook zwart in het beeld aanwezig, maar<br />
overwegend toch wit. Daardoor heeft de classificatie verkeerd beoordeeld.<br />
Op Beeld 17 werd er nog een cirkel gevonden door de witte letters die erop aanwezig zijn,<br />
waardoor het neuraal net veel blauw en een weinig wit vindt. De beoordeling is daardoor<br />
ook hier fout gelopen.<br />
Conclusie<br />
Het herkenningssysteem werkt niet perfect, er zijn nog tal <strong>van</strong> verbeteringen nodig om het<br />
nog beter te laten werken. Wij hebben ervoor gekozen in ons beeld op twee verschillende<br />
manieren naar geometrische figuren te zoeken. De random manier, zoals bij cirkels, en een<br />
strikt wiskundige methode, zoals bij driehoeken en rechthoeken. Beide implementaties<br />
hebben in feite hetzelfde probleem. Hoe meer pixels er na de edge <strong>detectie</strong> op het beeld<br />
staan, hoe moeilijker het wordt om de juiste figuren terug te vinden.<br />
We kunnen besluiten dat het herkenningssysteem in bijna alle weersomstandigheden vrij<br />
goed werkt. Als resultaat kunnen we vaststellen dat het herkenningssysteem het in 73% <strong>van</strong><br />
de geteste gevallen bij het rechte eind had.<br />
97
Appendix A<br />
Thumbnails<br />
98
100
101
102
103
104
105
106
Appendix B<br />
Code herkenningssysteem<br />
107
Deze appendix bevat alle code <strong>van</strong> het herkenningssysteem. We hebben telkens eerst de<br />
hoofdfuncties geplaatst met eronder de subfuncties.<br />
Hoofdprogramma<br />
function<br />
HoofdProgramma(filename,NetDriehoek,NetEenrichting,NetGeenToegangInBeideR<br />
ichting,NetGebods,NetVerbods)<br />
if nargin kolom & rij>640 & kolom>480 )<br />
I=imresize(I,[640,480]);<br />
end<br />
if(kolom>rij & rij>480 & kolom>640)<br />
I=imresize(I,[480,640]);<br />
end<br />
end<br />
[rij,kolom,d]=size(I);<br />
figure,imshow(I);<br />
%eerst de rode dingen afwerken<br />
im=RoodFilter(I,rij,kolom);<br />
im=EdgeDetector(im);<br />
[AantalGeenToegang,AantalEenrichting,AantalVerbodsBorden,agb]=CirkelProgr<br />
amma(I,im,rij,kolom,'rood',NetEenrichting,NetGeenToegangInBeideRichting,N<br />
etGebods,NetVerbods); %agb hebben we hier niet nodig<br />
[AantalGevarenDriehoek,AantalVoorangsDriehoek]=DriehoekProgramma(I,im,rij<br />
,kolom,NetDriehoek);<br />
%de blauwe<br />
im=BlauwFilter(I,rij,kolom);<br />
im=EdgeDetector(im);<br />
[agt,ae,avb,AantalGebodsBorden]=CirkelProgramma(I,im,rij,kolom,'blauw',Ne<br />
tEenrichting,NetGeenToegangInBeideRichting,NetGebods,NetVerbods); %<br />
agt,ae,avb zijn al aangemaakt bij rood<br />
%eindresultaat<br />
if (AantalGeenToegang>0)<br />
disp ('er zijn' ), disp(AantalGeenToegang), disp('Geen toegangsborden<br />
in beide richtingen in het beeld gevonden')<br />
end<br />
if (AantalEenrichting>0)<br />
disp ('er zijn' ), disp(AantalEenrichting), disp('Eenrichtingsborden<br />
in het beeld gevonden')<br />
end<br />
if (AantalVerbodsBorden>0)<br />
disp ('er zijn' ), disp(AantalVerbodsBorden), disp('Verbodsborden in<br />
het beeld gevonden')<br />
108
end<br />
if (AantalGebodsBorden>0)<br />
disp ('er zijn' ), disp(AantalGebodsBorden), disp('Gebodsborden in<br />
het beeld gevonden')<br />
end<br />
if (AantalGevarenDriehoek>0)<br />
disp ('er zijn' ), disp(AantalGevarenDriehoek),<br />
disp('Gevarendriehoeken in het beeld gevonden')<br />
end<br />
if (AantalVoorangsDriehoek>0)<br />
disp('er zijn'),<br />
disp(AantalVoorangsDriehoek),disp('Voorangansdriehoeken in het beeld<br />
gevonden')<br />
end<br />
if(AantalGeenToegang==0 & AantalEenrichting==0 & AantalVerbodsBorden==0 &<br />
AantalGebodsBorden==0 & AantalGevarenDriehoek==0 &<br />
AantalVoorangsDriehoek==0)<br />
disp('het programma heeft geen verkeersbord(en) in het beeld<br />
gevonden')<br />
end<br />
109
RoodFilter<br />
function [im]=RoodFilter(I,rij,kolom)<br />
%Roodfilter maken adh gemiddelde waardes (afwijking +-10) en waardes op s<br />
boven 0,5<br />
im=rgb2hsv(I);<br />
s=im(:,:,2);<br />
h=im(:,:,1);<br />
%for lussen die de gehele matrix zal overlopen en op rood of zwart zetten<br />
for ho=1:rij<br />
for br=1:kolom<br />
if (h(ho,br)0.94) & s(ho,br)>0.5<br />
h(ho,br)=1; %rood volledig wit maken<br />
else<br />
h(ho,br)=0; %niet-rood zwart maken<br />
end<br />
im=h;<br />
end<br />
end<br />
110
BlauwFilter<br />
function [im]=BlauwFilter(I,rij,kolom)<br />
%Blauwfilter maken adh gemiddelde waardes (afwijking +-10) en waardes op<br />
s vlak boven 0,5<br />
im=rgb2hsv(I);<br />
s=im(:,:,2);<br />
h=im(:,:,1);<br />
%for lussen die de gehele matrix zal overlopen en op blauw of zwart<br />
zetten<br />
for ho=1:rij<br />
for br=1:kolom<br />
if h(ho,br)0.514 & s(ho,br)>0.5<br />
h(ho,br)=1; %blauw volledig wit maken<br />
else<br />
h(ho,br)=0; %niet-blauw zwart maken<br />
end<br />
end<br />
end<br />
im=h;<br />
111
EdgeDetector<br />
function [im]=EdgeDetector(im)<br />
im=edge(im,'sobel',0.1);<br />
im=bwmorph(im,'skel');<br />
im=bwareaopen(im,50);<br />
im=bwmorph(im,'clean');<br />
im=bwmorph(im,'fill');<br />
112
CirkelProgramma<br />
function<br />
[AantalGeenToegang,AantalEenrichting,AantalVerbodsBorden,AantalGebodsBord<br />
en]=CirkelProgramma(I,im,rij,kolom,kleur,NetEenrichting,NetGeenToegangInB<br />
eideRichting,NetGebods,NetVerbods)<br />
ck=CirkelsDetectie(im,rij,kolom);<br />
if ~(isempty(ck))<br />
ck=CirkelFilter(ck);<br />
if ~(isempty(ck))<br />
cirkel=CirkelKnip(I,ck,rij,kolom);<br />
else<br />
cirkel=[];<br />
end<br />
end<br />
ResGeenToegangBeideRichting=[];<br />
ResEenrichting=[];<br />
ResGebods=[];<br />
ResVerbods=[];<br />
if ~(isempty(cirkel))<br />
for i=1:size(cirkel,1)<br />
figure,imshow(cirkel{i,1});<br />
c=imresize(cirkel{i,1},[100,100]);<br />
if(strcmp(kleur,'rood'))<br />
im=RoodFilter(c,100,100);<br />
end<br />
if(strcmp(kleur,'blauw'))<br />
im=BlauwFilter(c,100,100);<br />
end<br />
im=edge(im,'sobel');<br />
ck=CirkelsDetectie(im,100,100,50);<br />
%ledige plaatsen in ck verwijderen<br />
teller=20; %wanneer je het aantal cks verandert in<br />
cksDetectie dan moet je dit ook aanpassen<br />
z=1;<br />
%De lege plaatsen in de doorgestuurde tabel verwijderen<br />
while z
end<br />
end<br />
end<br />
AantalGeenToegang=0;<br />
if~(isempty(ResGeenToegangBeideRichting))<br />
for k=1:size(ResGeenToegangBeideRichting,2)<br />
if(ResGeenToegangBeideRichting(1,k)==1)<br />
AantalGeenToegang=AantalGeenToegang+1;<br />
end<br />
end<br />
end<br />
AantalEenrichting=0;<br />
if~(isempty(ResEenrichting))<br />
for k=1:size(ResEenrichting,2)<br />
if(ResEenrichting(1,k)==1)<br />
AantalEenrichting=AantalEenrichting+1;<br />
end<br />
end<br />
end<br />
AantalGebodsBorden=0;<br />
if~(isempty(ResGebods))<br />
for k=1:size(ResGebods,2)<br />
if(ResGebods(1,k)==1)<br />
AantalGebodsBorden=AantalGebodsBorden+1;<br />
end<br />
end<br />
end<br />
AantalVerbodsBorden=0;<br />
if~(isempty(ResVerbods))<br />
for k=1:size(ResVerbods,2)<br />
if(ResVerbods(1,k)==1)<br />
AantalVerbodsBorden=AantalVerbodsBorden+1;<br />
end<br />
end<br />
end<br />
114
CirkelsDetectie<br />
function [Ck] = CirkelsDetectie(I,rij,kolom,pix)<br />
if nargin < 3, error('Not enough input arguments.'); end<br />
if nargin == 3 pix=100; end<br />
marge = 1;<br />
aant_cirkels=20; %Er kunnen 10 cirkels bepaald worden<br />
Ck = cell(aant_cirkels,1);<br />
Coord = cell(aant_cirkels,1);<br />
H = ones(size(I));<br />
for i=1:aant_cirkels<br />
[r,k] = find(I==1); %r en k zijn de coordinaten <strong>van</strong> de pixels<br />
die 1 zijn<br />
B = [r,k];<br />
[B_rij,B_kol] = size(B);<br />
min_aant = pix; %min aantal pixels die een cirkel moet<br />
bevatten<br />
aant = 0; %aantal gevonden pixels<br />
max_aant = pix;<br />
Ptn=[];<br />
if ~(isempty(B))<br />
for j=1:100<br />
if aant
h3 = ceil(rand*aant);<br />
x1 = Coord{i,1}(h1,1);<br />
y1 = Coord{i,1}(h1,2);<br />
x2 = Coord{i,1}(h2,1);<br />
y2 = Coord{i,1}(h2,2);<br />
x3 = Coord{i,1}(h3,1);<br />
y3 = Coord{i,1}(h3,2);<br />
end % while<br />
end % if<br />
%Wiskundige achtergrond <strong>van</strong> een cirkel<br />
% punten mogen niet collineair zijn: x1*y2+x2*y3+x3*y1-x3*y2x2*y1-x1*y3==0<br />
% Vgl ve cirkel<br />
%<br />
% (x1-a)² + (y1-b)² = R² |+1<br />
% (x2-a)² + (y2-b)² = R² |-1 |+1<br />
% (x3-a)² + (y3-b)² = R² |-1<br />
%<br />
% x1²-x2²-2a(x1-x2)+y1²-y2²-2b(y1-y2)=0<br />
% x2²-x3²-2a(x2-x3)+y2²-y3²-2b(y2-y3)=0<br />
%<br />
% c1-c6: hulpvariabelen<br />
c1 = 2*(x2-x1);<br />
c2 = 2*(y2-y1);<br />
c3 = y2*y2-y1*y1+x2*x2-x1*x1;<br />
c4 = 2*(x3-x2);<br />
c5 = 2*(y3-y2);<br />
c6 = y3*y3-y2*y2+x3*x3-x2*x2;<br />
% c1 is soms 0 als 2 gekozen ptn op dezelfde horizontale liggen<br />
ym = ceil((c6-(c4*c3/c1))/(c5-(c4*c2/c1)));<br />
xm = ceil((c3-(c2*ym))/c1);<br />
straal = ceil(abs(sqrt((x1-xm)*(x1-xm) + (y1-ym)*(y1-ym))));<br />
% (xm,ym) = middelpunt vd ck<br />
% Bepalen <strong>van</strong> aantal ptn die op of in de buurt <strong>van</strong> cirkel liggen<br />
adh vd afstand<br />
% (Afstand tss 2 ptn (p1,p2))² = (x2-x1)² + (y2-y1)²<br />
aant=0;<br />
if(xm+straal0 & ym+straal0 &<br />
15
if aant>max_aant<br />
Ck{i,1} = [xm ym straal aant];<br />
Ptn = Coord{i,1};<br />
max_aant = aant;<br />
end<br />
% Ptn bevat de coordindaten <strong>van</strong> de punten die op de ck liggen<br />
end % for j=1:100<br />
end % isempty<br />
if ~(isempty(Ptn))<br />
[Ptn_rij,Ptn_kol] = size(Ptn);<br />
for m=1:Ptn_rij<br />
H(Ptn(m,1),Ptn(m,2))=0;<br />
end<br />
end<br />
% punten vd gevonden ck op 0 zetten, opdat de ck geen 2de keer kan<br />
gevonden worden<br />
I = I & H;<br />
% om uit te tekenen<br />
%figure(3);<br />
%imshow(H);<br />
end % for i=1:aant_cirkels<br />
117
CirkelFilter<br />
function [ck]=CirkelFilter(ck)<br />
%Overbodige cks uit de tabel verwijderen<br />
teller=20; %wanneer je het aantal cks verandert in cksDetectie dan<br />
moet je dit ook aanpassen<br />
z=1;<br />
%De lege plaatsen in de doorgestuurde tabel verwijderen<br />
while z=2)<br />
for i=1:teller % *0.9 : omdat je je ck 10% groter<br />
wil maken moet je dit voor de onderste coordinaat verkleinen<br />
j=i+1; % *1,1 : idem, maar je moet vergroten<br />
while j ck{j,1}(1,3)+ck{j,1}(1,1)<br />
& (ck{i,1}(1,1)-ck{i,1}(1,3))*0.9ck{j,1}(1,2)+ck{j,1}(1,3) &<br />
(ck{i,1}(1,2)-ck{i,1}(1,3))*0.9 < ck{j,1}(1,2)-ck{j,1}(1,3)<br />
end<br />
ck(j)=[];<br />
j=j-1;<br />
teller=teller-1;<br />
end<br />
j=j+1;<br />
end<br />
end<br />
%nu is de tabel overlopen <strong>van</strong> element 1 tot n<br />
%nu ga ik de tabel omgekeerd overlopen en hetzelfde doen<br />
%zo kan je ook de cks die een index lager hebben en toch binnen een ck<br />
zitten met hogere index verwijderen<br />
if (teller>=2)<br />
while teller>1<br />
j=teller-1;<br />
while j>0<br />
if (ck{teller,1}(1,3)+ck{teller,1}(1,1))*1.1 ><br />
ck{j,1}(1,3)+ck{j,1}(1,1) & (ck{teller,1}(1,1)ck{teller,1}(1,3))*0.9ck{j,1}(1,2)+ck{j,1}(1,3) &<br />
(ck{teller,1}(1,2)-ck{teller,1}(1,3))*0.9 < ck{j,1}(1,2)-ck{j,1}(1,3)<br />
ck(j)=[];<br />
teller=teller-1;<br />
end<br />
j=j-1;<br />
end<br />
teller=teller-1;<br />
end<br />
end<br />
118
CirkelKnip<br />
function [cirkel]=CirkelKnip(I,ck,rij,kolom)<br />
%Maken rechthoek rond cirkel + uitknippen + op scherm tonen<br />
marge=ceil((rij./100).*3.5);<br />
[teller g]=size(ck);<br />
for i=1:teller<br />
xm=ck{i,1}(1,1); %middelpunt + straal cirkel<br />
nemen<br />
ym=ck{i,1}(1,2);<br />
straal=ck{i,1}(1,3);<br />
hulp=xm-straal-marge; % er een rechthoek <strong>van</strong><br />
maken<br />
if hulprij x2=rij; end<br />
y1=ym-straal-marge;<br />
if y1kolom y2=kolom; end<br />
cirkel{i,1}=Uitknippen(I,hulp,x2,y1,y2);<br />
end<br />
%Op het scherm tonen <strong>van</strong> de geknipte cirkels<br />
%for i=1:teller<br />
% figure(i);<br />
% imshow(cirkel{i,1});<br />
%end<br />
119
Uitknippen<br />
function [tab]=Uitknippen(I,x1,x2,y1,y2)<br />
%Hier krijg je de linkerbovenhoek en de rechteronderhoek <strong>van</strong> een<br />
rechthoek<br />
%vervolgens wordt deze rechthoek uit de foto geknipt<br />
tab=[];<br />
for i=1:3<br />
for R=x1:x2<br />
for K=y1:y2<br />
tab((R-x1+1),(K-y1+1),i)=I(R,K,i);<br />
end<br />
end<br />
end<br />
tab=uint8(round(tab-1)); %converteren naar unit8 formaat<br />
120
KleurWaardesCirkel<br />
function<br />
[RoodCirkel,RoodBinnenCirkel,BlauwBinnenCirkel,ZwartBinnenCirkel,WitBinne<br />
nCirkel,Percentage,TotaalBinnen]=KleurWaardesCirkel(ck,c)<br />
RoodCirkel=0;<br />
RoodBinnenCirkel=0;<br />
WitBinnenCirkel=0;<br />
ZwartBinnenCirkel=0;<br />
BlauwBinnenCirkel=0;<br />
Percentage=0;<br />
im=rgb2hsv(c);<br />
h=im(:,:,1);<br />
s=im(:,:,2);<br />
v=im(:,:,3);<br />
r=c(:,:,1);<br />
g=c(:,:,2);<br />
b=c(:,:,3);<br />
if(size(ck,1)>=2)<br />
GrootsteStraal=ck{1,1}(1,3);<br />
KleinsteStraal=GrootsteStraal;<br />
PlaatsGrootste=1;<br />
PlaatsKleinste=1;<br />
for i=2:size(ck,1)<br />
if(GrootsteStraal < ck{i,1}(1,3))<br />
GrootsteStraal=ck{i,1}(1,3);<br />
PlaatsGrootste=i;<br />
end<br />
if(KleinsteStraal > ck{i,1}(1,3))<br />
KleinsteStraal=ck{i,1}(1,3);<br />
PlaatsKleinste=i;<br />
end<br />
end<br />
if(GrootsteStraal-KleinsteStraal < 4) %de stralen moeten minimum 4<br />
pix <strong>van</strong> elkaar liggen<br />
hulpck{1,1}=ck{PlaatsGrootste,1};<br />
else<br />
hulpck{1,1}=ck{PlaatsGrootste,1};<br />
hulpck{2,1}=ck{PlaatsKleinste,1};<br />
end<br />
ck=hulpck;<br />
end<br />
if(size(ck,1)==1)<br />
BinnensteStraal=ck{1,1}(1,3);<br />
x=ck{1,1}(1,1);<br />
y=ck{1,1}(1,2);<br />
for i=1:100;<br />
for j=1:100;<br />
if (sqrt((i-x)^2+(j-y)^2)0.5)<br />
RoodBinnenCirkel=RoodBinnenCirkel+1;<br />
end<br />
if (sqrt((i-x)^2+(j-y)^2)0.5)<br />
BlauwBinnenCirkel=BlauwBinnenCirkel+1;<br />
end<br />
if ( sqrt((i-x)^2+(j-y)^2)
ZwartBinnenCirkel=ZwartBinnenCirkel+1;<br />
end<br />
gemiddelde=(double(r(i,j))+double(b(i,j))+double(g(i,j)))/3;<br />
if (sqrt((i-x)^2+(j-y)^2)
end<br />
GrootsteOpp=floor(BuitensteStraal^2*pi);<br />
KleinsteOpp=floor(BinnensteStraal^2*pi);<br />
Opp=GrootsteOpp-KleinsteOpp;<br />
Percentage=ceil((100./Opp)*RoodCirkel);<br />
TotaalBinnen=RoodBinnenCirkel+BlauwBinnenCirkel+ZwartBinnenCirkel+WitBinn<br />
enCirkel;<br />
123
MaakNetEenRichting<br />
% In de tabel p_eenrichting staan de waarden die we terugkrijgen <strong>van</strong> het programma<br />
% KleurWaardesCirkel. Hier staat in elke kolom de waarden <strong>van</strong> een cirkel. In de tabel tm<br />
% staat telkens het resultaat of het al dan niet een cirkel is. Een 1 stelt een goede cirkel<br />
% voor. De volgende netten die we maken voor cirkels zijn analoog gemaakt.<br />
p_eenrichting =[<br />
0 0 2271 0 0 0 0 0 965 0 0<br />
3345 2450 42 2978 2440 3012 1000 1638 43 102 3465<br />
0 0 0 0 0 0 2 0 0 0 0<br />
89 18 0 227 201 0 980 1745 773 31 992<br />
885 499 2072 178 683 0 800 28 2676 4146 855<br />
0 0 92 0 0 0 0 0 59 0 0<br />
4319 2967 2114 3383 3324 3125 3265 3411 3492 4279 5312];<br />
t_eenrichting=[ 1 1 0 1 1 0 0 0 0 0 1] ;<br />
NetEenrichting=newp([0 5000;0 5000;0 5000;0 5000;0 5000;0 101;0<br />
10000],1);<br />
NetEenrichting.trainParam.epochs=10000;<br />
NetEenrichting=train(NetEenrichting,p_eenrichting,t_eenrichting);<br />
124
MaakNetGebods<br />
p_gebods =[<br />
0 0 0 1 0 0 0 0 0 6 0 0 0 0<br />
0 0 0 4 45 0 3 0 0 36 0 0 0 752<br />
1773 924 1074 394 1012 1385 1419 515 822 537 131 461 2380 3068<br />
0 602 39 2891 2221 4177 2085 2606 2320 194 26 1043 0 0<br />
771 817 621 1656 182 136 103 98 402 295 455 1147 8 11<br />
0 0 0 1 0 0 0 0 0 1 0 0 0 0<br />
2544 2343 1734 4945 3460 5698 3610 3219 3544 1062 612 2651 2388 3831];<br />
t_gebods=[1 1 1 0 0 0 0 0 0 1 1 0 1 0];<br />
NetGebods=newp([0 5000;0 5000;0 5000;0 5000;0 5000;0 101;0 10000],1);<br />
NetGebods.trainParam.epochs=10000;<br />
NetGebods=train(NetGebods,p_gebods,t_gebods);<br />
125
MaakNetGnTIBR<br />
p_GeenToegang =[<br />
2391 899 2680 2526 2084 973 1370 2277 2553 1651 940<br />
77 13 58 63 88 2467 507 56 42 80 647<br />
0 0 0 0 0 0 0 179 0 4 0<br />
16 36 489 0 0 5 0 291 737 384 2<br />
2566 2586 1888 3853 2808 733 713 44 2275 1856 3058<br />
95 50 99 96 96 72 56 93 96 90 96<br />
2659 2635 2435 3916 2896 3205 1220 570 3054 2324 3707];<br />
t_GeenToegang=[1 1 1 1 1 0 0 0 0 0 1];<br />
NetGeenToegangInBeideRichting=newp([0 5000;0 5000;0 5000;0 5000;0 5000;0<br />
101;0 10000],1);<br />
NetGeenToegangInBeideRichting.trainParam.epochs=10000;<br />
NetGeenToegangInBeideRichting=train(NetGeenToegangInBeideRichting,p_GeenT<br />
oegang,t_GeenToegang);<br />
126
MaakNetVerbods<br />
p_Verbods =[<br />
745 2287 2554 2216 2599 0 2822 88 566<br />
845 53 42 56 424 823 1405 1068 177<br />
0 177 0 0 1692 3057 0 0 247<br />
0 294 737 0 0 1 0 594 214<br />
625 10 2274 2114 11 29 685 267 116<br />
73 94 96 96 80 0 81 10 41<br />
1470 534 3053 2170 2127 3910 2090 1929 754];<br />
t_Verbods=[1 1 1 0 1 0 0 0 1];<br />
NetVerbods=newp([0 5000;0 5000;0 5000;0 5000;0 5000;0 101;0 10000],1);<br />
NetVerbods.trainParam.epochs=10000;<br />
NetVerbods=train(NetVerbods,p_Verbods,t_Verbods);<br />
127
DriehoekProgramma<br />
function<br />
[AantalGevarenDriehoek,AantalVoorangsDriehoek]=DriehoekProgramma(I,im,rij<br />
,kolom,NetDriehoek)<br />
driehoek=[];<br />
h=[];<br />
tabel=[];<br />
tabel=LijnCoordinaten(im);<br />
if ~(isempty(tabel))<br />
h=DriehoekDetectie(tabel,rij,kolom);<br />
end<br />
if ~(isempty(h))<br />
h=DriehoekFilter(h);<br />
h=DriehoekFilter(h);<br />
driehoek=DriehoekKnip(I,h,rij,kolom);<br />
if~(isempty(driehoek))<br />
resultaat=[];<br />
for i=1:size(driehoek,1)<br />
im=imresize(driehoek{i,1},[100,100]);<br />
figure,imshow(im);<br />
im=RoodFilter(im,100,100);<br />
[En30,En150,En0,En50,En130]=BerekenEnergie(im);<br />
p=[En30;En150;En0;En50;En130];<br />
a=sim(NetDriehoek,p);<br />
%resultaat=[resultaat a];<br />
driehoek{i,3}=a;<br />
end<br />
end<br />
end<br />
AantalGevarenDriehoek=0;<br />
AantalVoorangsDriehoek=0;<br />
if~(isempty(driehoek))<br />
for l=1:size(driehoek,1);<br />
if(driehoek{l,3}==1)<br />
top=driehoek{l,2}(1,5);<br />
basis=driehoek{l,2}(1,1);<br />
if (basis-top < 0)<br />
AantalVoorangsDriehoek=AantalVoorangsDriehoek + 1;<br />
else<br />
AantalGevarenDriehoek=AantalGevarenDriehoek + 1;<br />
end<br />
end<br />
end<br />
end<br />
128
LijnCoördinaten<br />
function tabel=LijnCoordinaten(im)<br />
%im=ingelezen foto<br />
if nargin == 0<br />
error('Not enough input arguments.');<br />
end<br />
pix=25; %aantal pixels die nodig zijn om een lijn te vormen<br />
%tabel wordt aangemaakt met de coordinaten <strong>van</strong> de lijnen<br />
tab = [];<br />
for theta=0:179<br />
[R,xp]=radon(im,theta);<br />
hulp=find(R>pix);<br />
hulp=hulp';<br />
for i=hulp<br />
tab=[tab;theta xp(i)]; %eerste kolom: hoek theta, tweede kolom:<br />
loodrechte afstand tot de oorsprong (R)<br />
end<br />
end<br />
%dubbelzinnige coordinaten worden uit de tabel verwijderd<br />
aantal=size(tab,1);<br />
tabel=[];<br />
while(0
Rres=R;<br />
else<br />
hulpteller=hulpteller-1;<br />
end<br />
j=1:hulpteller;<br />
tab(XY(j),:)=[]; %verwijderen <strong>van</strong> de<br />
verwerkte lijnen<br />
aantal=aantal-hulpteller;<br />
tabel=[tabel;floor(Rtheta./hulpteller) floor(Rres./hulpteller)]; %de<br />
opgekuiste tabel wordt aangemaakt<br />
end<br />
130
Gemeenschappelijk<br />
function XY=Gemeenschappelijk(min,max,X,Y) %tabel maken<br />
<strong>van</strong> gemeenschappelijke elementen <strong>van</strong> X en Y<br />
XY=[];<br />
teller=1; %teller die<br />
de kleinste tabel overloopt<br />
while(teller
DriehoekDetectie<br />
function [hoekCoordinaten]=DriehoekDetectie(tabel,rij,kolom)<br />
% hoekCoordinaten bevat de coordinaten <strong>van</strong> de driehoeken<br />
% tabel meegeven waar de lijnen in poco vermeld staan(via LijnCoordinaten<br />
wordt die tabel aangemaakt)<br />
% rij en kolomgrootte <strong>van</strong> de foto meegeven (kan je opvragen via<br />
[rij,kolom]=size() )<br />
if nargin < 3<br />
error('Not enough input arguments.');<br />
end<br />
%tabel wordt opgesplitst in 3 tabellen resp. voor 0°<br />
30° 150°<br />
hoek30=[]; %een gelijkzijdige driehoek heeft hoeken <strong>van</strong> 60°<br />
hoek90=[]; %Deze tabel stelt 0° voor:in poco wordt de<br />
horizontale voorgesteld door een hoek <strong>van</strong> 90°<br />
hoek150=[];<br />
hoekCoordinaten=[];<br />
grensrij=rij./2;<br />
grenskolom=kolom./2;<br />
for i=tabel' %opvullen <strong>van</strong> de 3 hoek tabellen<br />
if (25
gem=(af1+af2+af3)./3;<br />
%gem=gemiddelde lengte tussen de 3 hoekpunten<br />
speling=(gem./100).*5; %er mag een<br />
speling <strong>van</strong> 5% aanwezig zijn tussen de gemiddelde afstand en de 3<br />
onderlinge afstanden<br />
if ( gem>50 & gem
BerekenHoekpunt<br />
function [y,x]=BerekenHoekpunt(theta1,r1,theta2,r2)<br />
%het uitrekenen <strong>van</strong> het snijpunt tussen 2 rechten, via methode <strong>van</strong> gauss<br />
pie=pi./180;<br />
y=((r1./(cos(pie*theta1)))-<br />
(r2./(cos(pie*theta2))))./(((sin(pie*theta1))./(cos(pie*theta1)))-<br />
((sin(pie*theta2))./(cos(pie*theta2))));<br />
x=(r1./(cos(pie*theta1)))-(y.*(sin(pie*theta1)./cos(theta1*pie)));<br />
134
DriehoekFilter<br />
function [hoekCoordinaten]=DriehoekFilter(hoekC)<br />
%De tabel met alle gevonden driehoeken wordt bekeken en de overbodige<br />
driehoeken worden verwijderd<br />
hoekCoordinaten=[]; %lege tabel die opgevuld wordt met de unieke<br />
driehoeken<br />
pos=0; %houdt de positie bij <strong>van</strong> hoekCoordinaten<br />
while ~(isempty(hoekC))<br />
hulp=[]; %hulptabel die bijhoudt welke elementen uit<br />
hoekC verwijderd mogen worden<br />
pos=pos+1;<br />
hoekCoordinaten(pos,:)=hoekC(1,:);<br />
hoekC(1,:)=[];<br />
[tel g]=size(hoekC);<br />
x1=hoekCoordinaten(pos,1);<br />
y1=hoekCoordinaten(pos,2);<br />
gem1=hoekCoordinaten(pos,7);<br />
x3=hoekCoordinaten(pos,5);<br />
y2=hoekCoordinaten(pos,4);<br />
for i=1:tel<br />
if x1-30=hoekC(i,1) & y1-30=hoekC(i,2) & floor(gem1*0.7)=hoekC(i,7) & sign(x1-x3)==sign(hoekC(i,1)-hoekC(i,5)) &<br />
sign(y1-y2)==sign(hoekC(i,2)-hoekC(i,4))<br />
% kijken of 1e punt <strong>van</strong> hoekCoordinaten binnen een interval <strong>van</strong><br />
+-10 ligt bij punt in hulp kijken of de gemiddelde<br />
waardes in een 10% interval overeenkomen kijken of top zelfde pos<br />
heeft tov 1e pt idem ander hoekpunt<br />
if hoekCoordinaten(pos,7)
DriehoekKnip<br />
function [driehoek]=DriehoekKnip(I,hoekCoordinaten,rij,kolom)<br />
%De driehoeken <strong>van</strong> hoekCoordinaten worden uit het beeld geknipt dmv<br />
Rechthoek<br />
[i,j]=size(hoekCoordinaten);<br />
for j=1:i %bepalen <strong>van</strong> de linkerbovenhoek en<br />
rechteronderhoek die aan Rechthoek meegegeven moeten worden<br />
klx=hoekCoordinaten(j,1); %klx=kleinste x waarde<br />
grx=hoekCoordinaten(j,1); %grx=grootste x waarde<br />
if klx>hoekCoordinaten(j,3) klx=hoekCoordinaten(j,3); end<br />
if klx>hoekCoordinaten(j,5) klx=hoekCoordinaten(j,5); end<br />
if grxhoekCoordinaten(j,6) kly=hoekCoordinaten(j,6); end<br />
if gry
BerekenEnergie<br />
function<br />
[EnergieBand30,EnergieBand150,EnergieBand0,EnergieBand50,EnergieBand130]=<br />
BerekenEnergie(im)<br />
%im=imresize(im,[100,100]); % indien niet hoofdprogramma resized moet<br />
het hier!<br />
%level=graythresh(im); % we krijgen <strong>van</strong> roodfilter bw<br />
%im=im2bw(im,level);<br />
f=fft2(im);<br />
[rij,kol]=size(f);<br />
for i=1:rij % is noodzakelijk anders foutmelding bij het<br />
berekenen <strong>van</strong> de log<br />
for j=1:kol<br />
if(f(i,j)==0)<br />
f(i,j)=1;<br />
end<br />
end<br />
end<br />
f=log(abs(f));<br />
f=fftshift(f);<br />
x=mean(mean(f)); % berekening <strong>van</strong> de gemiddelde waarde<br />
for i=1:100<br />
for j=1:100<br />
f(j,i)=f(j,i)-x; % aftrekking <strong>van</strong> de gemiddelde waarde<br />
end<br />
end<br />
rij=rij./2;<br />
kol=kol./2;<br />
band30=0; teller30=0;<br />
band150=0; teller150=0;<br />
band0=0; teller0=300; % als hij geresized is op 100 100 anders moet je<br />
dit herbereken<br />
band50=0; teller50=0;<br />
band130=0; teller130=0;<br />
for i=-rij+1:rij<br />
for j=-kol+1:kol<br />
if(i~=0 & atan(j./i)> ((pi./180).*26) & atan(j./i)<<br />
((pi./180).*34)) % berekening <strong>van</strong> de energie waarde rond de 30°<br />
band30=band30+f(j+kol,i+rij);<br />
teller30=teller30+1;<br />
end<br />
if(i~=0 & atan(j./i)-<br />
((pi./180).*34)) % berekeking <strong>van</strong> de energie waarde rond de -30°<br />
band150=band150+f(j+kol,i+rij);<br />
teller150=teller150+1;<br />
end<br />
if(i>-2 & i ((pi./180).*46) & atan(j./i)<<br />
((pi./180).*54)) % berekening <strong>van</strong> de energie waarde rond de 50°<br />
band50=band50+f(j+kol,i+rij);<br />
teller50=teller50+1;<br />
end<br />
137
if(i~=0 & atan(j./i)-<br />
((pi./180).*54)) % berekeking <strong>van</strong> de energie waarde rond de -50°<br />
band130=band130+f(j+kol,i+rij);<br />
teller130=teller130+1;<br />
end<br />
end<br />
end<br />
EnergieBand30=floor(band30./teller30);<br />
EnergieBand150=floor(band150./teller150);<br />
EnergieBand0=floor(band0./teller0);<br />
EnergieBand50=floor(band50./teller50);<br />
EnergieBand130=floor(band130./teller130);<br />
138
MaakNetDriehoek<br />
% De waarden die we terug krijgen <strong>van</strong> BerekenEnergie zijn hier weergegeven in de tabel<br />
% pm. Elke kolom staat voor de waarden <strong>van</strong> een driehoek die we hebben ingegeven. In de<br />
% tabel tm staat het resultaat dat het net moet weergeven bij de invoer. Zo kunnen we zien<br />
% dat de eerste kolom <strong>van</strong> pm een driehoek is want bij tm staat er een 1. Zo wordt het net<br />
% getraind.<br />
pm =[<br />
];<br />
0 0 -1 0 -1 0 -1 -1 0 0 0 0<br />
0 0 -1 0 -1 0 -1 -1 0 0 0 0<br />
90 145 147 133 111 98 128 128 119 128 90 9<br />
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1<br />
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1<br />
tm =[1 1 0 1 0 1 0 0 1 1 1 0<br />
];<br />
NetDriehoek=newp([-2 1;-2 1;0 200;-2 1;-2 1],1);<br />
NetDriehoek=train(NetDriehoek,pm,tm);<br />
139
RechthoekDetectie<br />
function rechthoek=RechthoekDetectie(tabel,rij,kolom)<br />
%In deze functie zullen we uit tabel de rechthoeken in het beeld zoeken<br />
hoek0=[]; %een rechthoek vind je op 0° en 90°<br />
hoek90=[];<br />
rechthoek=[];<br />
grensrij=rij./2;<br />
grenskolom=kolom./2;<br />
for i=tabel' %opvullen <strong>van</strong> de 2 hoek tabellen, 5° speling<br />
if (175
echthoek=[rechthoek;floor(a)+grensrij floor(b)+grenskolom<br />
floor(c)+grensrij floor(d)+grenskolom floor(e)+grensrij<br />
floor(f)+grenskolom floor(g)+grensrij floor(f)+grenskolom];<br />
end<br />
end<br />
end<br />
end<br />
end<br />
end<br />
end<br />
end<br />
end<br />
141
RechthoekKnip<br />
function [rechthoeken]=RechthoekKnip(I,rechthoek);<br />
rechthoeken=[];<br />
for i=1:size(rechthoek,1)<br />
grx=rechthoek(i,1);<br />
klx=rechthoek(i,1);<br />
if grxrechthoek(i,3) klx=rechthoek(i,3); end<br />
if grxrechthoek(i,5) klx=rechthoek(i,5); end<br />
if grxrechthoek(i,7) klx=rechthoek(i,7); end<br />
gry=rechthoek(i,2);<br />
kly=rechthoek(i,2);<br />
if gryrechthoek(i,4) kly=rechthoek(i,4); end<br />
if gryrechthoek(i,6) kly=rechthoek(i,6); end<br />
if gryrechthoek(i,8) kly=rechthoek(i,8); end<br />
rechthoeken{i,1}=Uitknippen(I,klx-10,grx+10,kly-10,gry+10);<br />
end<br />
%Op het scherm tonen <strong>van</strong> de geknipte rechthoek<br />
teller=size(rechthoeken,1);<br />
for i=1:teller<br />
figure(i);<br />
imshow(rechthoeken{i,1});<br />
end<br />
142
Literatuurlijst<br />
[1] Road Sign Recognition groups in the world.<br />
URL:http://euler.fd.cvut.cz/research/rs2/other.html [18 September 2003]<br />
[2] Recognition of Road Signs using Support Vector Machine and Approximated Invariant<br />
Method. URL: http://visl.technion.ac.il/projects/2000s04/ [18 September 2003]<br />
[3] DESPOPULOS AGAMEMMON, SILBERNAGL STEFAN, Color atlas of Physiology,<br />
4 th edition revised and enlarged, Stuttgarth, Thieme, 1991, hoofdstuk 11, p. 314-315<br />
[4] Image Processing Learning Resources. URL: http://homepages.inf.ed.ac.uk/rbf/HIPR2<br />
[18 September 2003]<br />
BISHOP CHRISTOPHER M., Neural Networks for Pattern Recognition, New York,<br />
Oxford University Press Inc., 1995<br />
Road Sign Recognition by Single Positioning of Space-Variant Sensor Window.<br />
URL:http://www.cipprs.org/vi2002/pdf/s4-5.pdf [18 September 2003]<br />
Road Traffic Sign Detection and Classification.<br />
URL:http://www.uc3m.es/uc3m/dpto/IN/dpin04/IE3tie97.pdf [18 September 2003]<br />
Road Sign Recognition from a Moving Vehicle,URL:http://citeseer.ist.psu.edu/570294.html<br />
[18 September 2003]<br />
Road Sign Classification without Color Information.<br />
URL:http://www.ph.tn.tudelft.nl/~pavel/files/asci2000.pdf [18 September 2003]<br />
Road Sign classification using Laplace kernel classifier.<br />
URL:http://www.ph.tn.tudelft.nl/~pavel/files/paclik99:SCIA.pdf [18 September 2003]<br />
An Introduction to Edge Detection: the Sobel Edge Detector.<br />
URL:http://www.generation5.org/content/2002/im01.asp [24 September 2003]<br />
Canny Edge Detection Tutorial. URL: http://www.pages.drexel.edu/~weg22/can_tut.html<br />
[24 September 2003]<br />
The MatWorks Worldwide.<br />
URL:http://www.mathworks.com/access/helpdesk/help/techdoc/matlab.shtml [5 Mei 2004]<br />
Matlab, The Language of Technical Computing(6.1.0.450)[Computer Program].(18 Mei<br />
2001).<br />
National Instruments LabVIEW(7.0)[Computer Program].<br />
Adobe Photoshop(7.0)[Computer Program].<br />
143
144