24.09.2013 Views

Automatische detectie van verkeersborden. - Departement ...

Automatische detectie van verkeersborden. - Departement ...

Automatische detectie van verkeersborden. - Departement ...

SHOW MORE
SHOW LESS

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!