Rozpoznávání a klasikace fotograí pivních přepravek Seminární práce z předmětu Neuronové sítě v aplikacích: Rozpoznávání obrazu Ondřej Veselý, N-II Inženýrská informatika, Automatizace řízení a informatika Úvod Rozpoznávání obrazu je důležitou úlohou oboru umělé inteligence. Ke klasikaci obrazových dat se nejčastěji používá fuzzy rozhodování a neuronové sítě. Tato práce se bude zabývat klasikací obrazů za použití klasické vícevrstvé neuronové sítě. Popis použitých technologií Nástroj Convert z balíku Imagemagick pro změnu vzorkování rastrových dat Bash shell pro řízení preprocessingu Python pro implementaci algoritmu na detekci hran Jazyk C a Fast Articial Neural Network Library pro implementaci neuronové sítě Metodika Z důvodu snadnějšího a rychlejšího zpracování obrazu jsem se rozhodl nepoužívat převod na vektory, ale po celou dobu pracovat s rastrovými daty. Proto v prvním kroku předzpracování provádím škálování obrazu na nižší rozlišení pomocí nástroje Convert. Vzhledem k tomu, že zdrojové obrazy byly různě nasvětleny, považoval jsem za nejdůležitější součást předzpracování obrazu detekci hran. Protože taková implementace je poměrně triviální, použil jsem několikařádkové řešení v Pythonu (operátor Sobel využívající konvolučních masek). Tento skript rovnou převádí obrázek na číselný vektor, přičemž se zahazuje informace o barvách a škála šedé se redukuje pouze na šestnáct odstínů. Celý preprocessing je řízen shellovým skriptem, který parsuje názvy vstupních souborů, vytváří z nich další údaje potřebné pro učení a ty spolu s číselným vektorem ukládá do tzv. prepo souboru, který už je ve formátu kompatibilním s metodami knihovny FANN. Testovací sadu jsem vytvořil vždy z prvního obrázku v sadě; na ostatních se síť učila. Vlastní učení jednouchý program využívající vysokoúrovňových metod zmíněné knihovny. Naučená síť je uložena jako soubor. Testování dat je implementování opět Cčkovým programem. Ten načte neuronovu síť ze souboru; pak testovací sadu předzpracovanou shellovým skriptem a vypíše pro každý testovací záznam dva údaje nejpravděpodobnější index vzorku a míru jistoty. Síť jsem testoval na standardním vzorku třiceti ořezaných fotek přepravek; průběh experimentu popisuji dále. Podobnou procentuální úspěšnost síť vykazovala i na dvojnásobném vzorku lépe předpřipravených fotek. Vlastní experiment Jako výkonnostně snesitelné se ještě ukázala být neuronová síť s řádově jednotky tisíc vstupních neuronů; proto jsem se rozhodl pro rozměr 60 x 60 pixelů, tedy 3600 vstupních neuronů. Parametry použité neuronové sítě
Aktivační funkce: sigmoidální, symetrická Počet vstupních neuronů: 3600 Počet výstupních neuronů: 30 Počet vrstev: 3 Počet neuronů ve skryté vrstvě: 90 Počet expoch: 25 Trvání jednotlivých částí experimentu akce čas (s) Preprocessing tréninkových dat 55 Učení 12 Preprocessing testovacích dat 22 Testování testovacích dat 1 Výsledky název sady číslo sady rozpoznaná přepravka Míra jistoty (-1 až 1) určeno správně bakalarlogo 1 22-0,44! ne bakalar 2 2 0,01 ano bazantt 3 3 0,87 ano bazant 4 11-0,17! ne birell 5 5 0,81 ano branik 6 6 0,72 ano cernahora 7 7 0,90 ano dudak 8 8 0,70 ano gambrinus 9 9 0,98 ano gorgon 10 10 0,86 ano horden 11 11 0,42 ano hostan 12 12 0,63 ano chotebor 13 13 0,21 ano ch 14 14-0,37! ano klaster 15 15 0,85 ano koruna 16 16 0,39 ano most 17 17 0,32 ano ostravar 18 18-0,55! ano passau 19 19-0,40! ano pelhrimov 20 20 0,81 ano plzen 21 21-0,71! ano popper 22 22 0,79 ano postrizinske 23 23-0,19! ano primator 24 24-0,21! ano primus 25 25 0,97 ano purkmistr 26 26 0,60 ano rr 27 27 0,87 ano
schoffer 28 28-0,28! ano steiger 29 29 0,70 ano urpiner 30 30 0,48 ano Úspěšnost sítě v tomto experimentu je tedy přibližně 93%. Diskuze Síť měla problémy nejčastěji s přepravkou bazant. Následující série obrázků znázorňuje 1. přepravku bazant 2. přepravku bazant tak jak je posílána na vstup neuronové síti a 3. přepravku horden, která je nejčastěji chybně určována místo přepravky bazant. 1) 2) 3) V tomto případě se neúspěch podobností loga, které nebylo zachyceno v dostatečném rozlišení. Vzhledem k tomu, že jsem neprováděl rozsáhlé množstí experimentů, které by vedly k doladění parametrů, má tato síť pravěpodobně skrytý potenciál jak v oblasti preprocessingu tak při samotném učení. Preprocessing bych doporučil vylepšit tak, aby generoval hned dva obrazy ke zpracování hrubý rastr 12 x 12 pixelů celé přepravky a pak o něco větší výřez detekovaného loga (zde se ovšem objevuje nutnost detekce polohy loga). Závěr I přes zmíněné kvalitatvní nedostatky úspěšnost sítě předčila mé očekávání, přesto že podávala dobré výsledky rovnou bez jakéhokoli ladění. Především je velice rychlá. Celá implementace je navíc provedena relativně nízkoúrovňově a dá se snadno přizpůsobit dalším úlohám, nebo snadno zaintegrovat např. do automatizovaného serverového řešení.
Příloha 1: Kód skriptu řídící preprocessing #!/bin/sh # skript vytvori soubor prepo-$1 pro nacteni neuronovou siti # pracuje se sadou obrazku v adresari bedny # author: ondrej.vesely@orwen.org # nastavime parametry podle toho jaka data chceme predzpracovat if [ "all" = "$1" ] maximalni_sada=30 hlavicka="100 3600 30" echo "Generuji ucici sadu pro vsechna data" if [ "vsekromenuly" = "$1" ] maximalni_sada=30 hlavicka="70 3600 30" echo "Generuji ucici sadu pro ne-prvni obrazky ze sady" if [ "pouzenuly" = "$1" ] maximalni_sada=30 hlavicka="30 3600 30" echo "Generuji ucici sadu pro prvni obrazky ze sady" if [ "" = "$1" ] [! "$hlavicka" ] echo "nespravne parametry" exit 1 echo $hlavicka > prepro.data sadanum=0 for fname in `ls bedny/*.png sort`; do # parse lenames to get metadata sada=`echo $fname cut -f1 -d'0' cut -f2 -d'/'` obrazek=`echo $fname cut -f2 -d'0' cut -f1 -d'.'` if [ $obrazek -eq 1 ] sadanum=$((sadanum+1)) # pokud nechceme zahrnout testovaci obrazky, vynechame cyklus if [ "vsekromenuly" = "$1" ] && [ $obrazek -eq 1 ] continue # pokud ucime pouze testovaci obrazky, vynechame cyklus if [ "pouzenuly" = "$1" ] && [! $obrazek -eq 1 ] continue echo "Processing: sada $sada number $sadanum, obrazek $obrazek..." convert -resize 62x62! $fname tmp.png./s.py tmp.png >> prepro.data # zmena velikosti # normalizace dat v obrazku
done # pozadovany vystup z neuronky for i in `seq 1 $maximalni_sada`; do if [ $i -eq $sadanum ]; echo -n "1 " >> prepro.data else echo -n "-1 " >> prepro.data done echo >> prepro.data rm tmp.png rm tmp.png.png mv prepro.data prepo-$1.data echo "Normalised data saved to prepo-$1.data"
Příloha 2: Normalizace vstupních dat v jednom obrázku #!/usr/bin/python # Provede prevod do sede skaly a detekci hran; zapise je do obrazku. Ten ulozi jako $1.png # Na vystup vypise radu cisel odpovidajici tmavosti pixelu. # prevzato a prizpusobeno z # http://lu-vision-dock.blogspot.com/2009/04/sobel-edge-detection.html import sys import Image import math import opencv def sobel(img): if img.mode!= "RGB": img = img.convert("rgb") out_image = Image.new(img.mode, img.size, None) imgdata = img.load() outdata = out_image.load() gx = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]] gy = [[-1, -2, -1], [0, 0, 0], [1, 2, 1]] p = 0 for row in xrange(1, img.size[0]-1): for col in xrange(1, img.size[1]-1): pixel_gx = pixel_gy = 0 pxval = sum(imgdata[row,col])/3 for i in range(-1, 2): for j in range(-1, 2): val = sum(imgdata[row+i,col+j])/3 pixel_gx += gx[i+1][j+1] * val pixel_gy += gy[i+1][j+1] * val newpixel = math.sqrt(pixel_gx * pixel_gx + pixel_gy * pixel_gy) newpixel = 255 - int(newpixel) outdata[row, col] = (newpixel, newpixel, newpixel) print (newpixel / 16), return out_image img = Image.open(sys.argv[1]) out = sobel(img) out.save(sys.argv[1] + ".png")