Home

Projectomschrijving
De opstelling
Het programma
Apparatuur
Raw data
Broncode

Planning
Dagboek
Logbook

Contact

Het programma

Op deze pagina vindt u alle informatie over wat ons programma doet. De uitleg van de functies wordt vergezeld met plaatjes van een voorbeeld zet.

Initialiseren van het bord

Na een vruchteloos begin met het schrijven van het hele programma in één functie ‘start’, kwamen we tot de conclusie dat het eerst noodzakelijk was om bepaalde parameters in onze software te initialiseren. Zie de functie initBoard. Dit doen we in eerste instantie door een leeg bord te fotograferen met op de hoekpunten 4 zwarte pionnen.

Deze aanpak stelt ons in de gelegenheid de 4 vlekken die de pionnen vormen op te sporen en hiervan de coordinaten terug te geven. Grofweg gebeurt dit door de foto eerst om te zetten van RGB naar grijswaarden en daarna het negatief ervan te nemen. Hierdoor worden de zwarte pionnen witte vlekken. Vervolgens zetten we dit negatief om naar een zwart/wit afbeelding. Hierbij kiezen we een grenswaarde die ervoor zorgt dat alle grijswaarden boven deze ‘threshold’ wit worden en daaronder zwart. Het kiezen van deze grenswaarde gebeurt in een aparte functie correctBw, welke iteratief de grenswaarde ophoogt of verlaagt totdat het totaal aantal witte pixels binnen een bepaalde regio van een gewenst aantal witte pixels ligt (bwGoalWhiteVal). De exacte waarden voor deze grenzen zijn uiteraard afhankelijk van de specifieke belichtingsomstandigheden, maar het zorgt ervoor dat er niet te veel of te weinig van de originele grijswaarde-afbeelding wordt weggegooid. Uiteindelijk levert dit een afbeelding op met 4 witte vlekken.

In deze afbeelding lokaliseert de functie findBlobs de witte vlekken en retourneert de pixel-coordinaten van de middelpunten van deze vlekken. Deze functie werkt door de afbeelding per rij te doorlopen, de zwarte pixels over te slaan en elke witte pixel die het tegenkomt te expanden totdat de gehele blob is gelokaliseerd. Vervolgens loopt het de rijen verder af, waarbij het weer de zwarte pixels overslaat, maar nu ook de al tot een eerder gevonden blob bijbehorende witte pixels. Per blob worden tenslotte de middelpunten berekend.

De hoekpunten die aldus worden verkregen worden opgeslagen in een .mat-file, alsmede een aantal andere variabelen die van pas komen bij het omzetten van pixel-coordinaten naar schaakbord-coordinaten.

Zet detecteren

De main-functie: start.m
Er is inmiddels al een hoop werk gedaan alvorens we kunnen beginnen met de daadwerkelijke zet-detectie. We nemen een foto voor en na de zet en verkrijgen als output twee RGB kleurenafbeeldingen. Zie hiervoor ook de pagina met informatie over de camera (link: Camera & Matlab )

Voorbeeld van twee opnamen bij een zet
Voor
Na

Verschil image
Van deze twee afbeeldingen nemen we het absolute verschil in intensiteit (eigenlijk de wortel van het verschil in het kwadraat) wat voorkòmt dat negatieve verschillen de positieve verschillen opheffen. Hierovoor gebruiken we de functie imageDifference.

Aangezien het grootste deel van het bord onveranderd is gebleven, levert dit twee lichte plekken op en een hoop donker beeld. Merk op dat pixels waarvoor niets is veranderd resulterende RGB-waardes zullen hebben die dicht bij 0 liggen, wat overeenkomt met (bijna) zwart.

 
Verschilbeeld van de twee plaatjes

Eén van deze lichte vlekken representeert het ‘from’-vakje, de ander de ‘to’-positie. De grootte van deze witte vlekken blijkt afhankelijk van de specifieke zet die wordt uitgevoerd. Verzet je een stuk van een vakje naar een ander vakje met dezelfde kleur, dan zijn de vlekken even groot, aangezien het contrast met de ondergrond in beide situaties gelijk is. Verplaats je echter een stuk van een wit vakje naar een zwart vakje, dan zal er op de plaats van het zwarte vakje een veel grotere vlek ontstaan dan op de plek van het witte vakje (we gebruiken witte markers voor de stukken). Het slaan van een (zwart) stuk is min of meer gelijk aan het verplaatsen naar een zwart vakje, aangezien deze ongeveer dezelfde kleur hebben.

Het verschil in grootte van de ‘blobs’, zoals we ze stijlvol hebben gedoopt, plaatste ons in eerste instantie voor een probleem. Het probleem werd ingewikkelder daar ons verschilbeeld af en toe in plaats van één blob, twee kleinere blobs opleverde. Dit was in eerste instantie te wijten aan de beperkte resolutie van de camera en reflectie. Hoe om te gaan met een zet, waarvan door de intrinsieke eigenschappen van het bord en de stukken de blobs al in grootte verschillen en (bijvoorbeeld) de grootste ook nog eens in tweeën was gedeeld?

In eerste instantie hebben we dit opgelost door verschillen in belichting tussen de twee foto’s zoveel mogelijk te beperken, wat een dramatische verbetering opleverde (evenals het dumpen van een glazen bord). Was er af en toe toch ruis of reflectie, dan gaf de functie findBlobs alleen coordinaten terug van blobs met een bepaalde afmeting: niet te groot, niet te klein. Uiteindelijk blijft het toch echter een kwestie van de opstelling zo ideaal mogelijk maken door reflectie en schaduwen te minimaliseren.

Projectie van het bord
Voordat we blobs kunnen gaan detecteren, normaliseren we het verschilbeeld in plaats: we voeren een projectie uit op basis van de eerder berekende hoekpunten en gooien zo alle pixels weg die buiten het schaakbord liggen. Hiervoor gebruiken we de functie myFastProjection. Door deze projectie komen de hoekpunten van het schaakbord op de hoekpunten van de nieuwe afbeelding te liggen. De afmetingen van deze afbeelding zijn vastgelegd in de .mat-file die aangemaakt is in initBoard. Door deze projectie verminder je verder het effect van de kromming in de lens van de gebruikte webcam. Deze kromming zorgt er voor dat rechte lijnen opeens krom lijken te zijn.

In de onderstaande afbeelding is het effect van een projectie goed te zien. Dit voorbeeld is gehaald uit een run van initBoard. Bij initBoard wordt wel geen projectie gemaakt, maar dit verduidelijkt wel wat een projectie precies doet. Zoals u kunt zien wordt bij de projectie het bord virtueel loodrecht onder het blikveld van de camera geplaatst.

Naar zwart-wit
Het genormaliseerde verschilbeeld zetten we om naar een zwart/wit afbeelding, waardoor het grootste deel van eventueel aanwezige ruis (‘noise’) wordt geëlimineerd. Het bepalen van de grenswaarde bij het omzetten gebeurt op dezelfde wijze als in initBoard. De doelwaarde van het aantal witte pixels staat in de variabele bwGoalWhiteVal.

 
Het zwart-wit verschilbeeld

Afhandeling
Nu we een zwart/wit, genormaliseerd verschilbeeld hebben verkregen kunnen we eindelijk blobs gaan opsporen. Ook dit gebeurt zoals in initBoard. De laatste stappen zijn vervolgens erg simpel. Aangezien we het beeld genormaliseerd hebben, kan de functie getBoardCoords bijna direct de schaakbord-coordinaten teruggeven op basis van de pixel-coordinaten zoals gegenereerd door findBlobs. Hierbij worden de variabelen rowCoords en columnCoords gebruikt uit de .mat-file.

De functie determineMoveOrder bepaalt vervolgens welke van de twee de ‘from’-positie was en welke de ‘to’-positie. Dit gebeurt op basis van de file ‘board.txt’, welke wordt gegenereerd door het playchess-programma uit de eerste week van dit project. Deze file bevat het bord na de laatste zet van zwart (de computer).

Deze laatste twee stappen worden uiteindelijk afgesloten met het schrijven naar een file ‘humanmove.txt’. De computer kan inlezen wat de menselijke zet was en zich eens achter de oren krabben welke tegenzet te doen...!



© Hylke Buisman & Mark Beumer 2005