Difference between revisions of "GolfBot"
m |
|||
Line 1: | Line 1: | ||
[[Projects_AI_Robotics|Nazad na projekty ...]] | [[Projects_AI_Robotics|Nazad na projekty ...]] | ||
− | GolfBot | + | GolfBot spis projektu (pripravuje sa) ... |
+ | |||
+ | == Program == | ||
+ | |||
+ | === Prepojenie s kamerou a určovanie orientačných bodov === | ||
+ | |||
+ | Obraz sme získavali pomocou Kinectu pre XBox 360. Máme dve triedy, <code>Kinect</code> (odvodená od <code>edu.ufl.digitalworlds.j4k.J4KSDK</code>) a <code>Camera</code> (implementuje <code>Runnable</code>). | ||
+ | |||
+ | Hlavný program spúšťa vlákno kamery, ktoré následne pri inicializácii spustí vlákno kinectu v móde <code>J4KSDK.COLOR</code>. Inštancii tredy <code>Kinect</code> je potom poslaná referencia na kameru. Trieda <code>Kinect</code> prekrýva metódu udalosti <code>onColorFrameEvent</code>, ktorá nastáva po zosnímaní farebného obrazu kinectom, pričom tento obraz posiela inštancii kamery cez referenciu volaním jej verejnej metódy <code>setImageFromKinect</code>. | ||
+ | |||
+ | Hlavné vlákno kamery vykonáva cyklicky tieto akcie: | ||
+ | |||
+ | Najprv sa otestuje, či existuje snímka z kamery. | ||
+ | * Ak nie, ukončí iteráciu cyklu a pokračuje ďalšou iteráciou. | ||
+ | * Ak áno: | ||
+ | *# Vytvorí si novú kópiu obrázku (pre účely spracovania). | ||
+ | *# Aplikuje gaussovo rozmazanie pracovného obrázka z polomerom 3px. | ||
+ | *# Skonvertuje obrázok z farebného formátu BGR0 do LAB. | ||
+ | *# Pomocou práhovania, nájdeniu najväčšieho spojitého komponentu a priemerovania x, y pozícií pixelov najväčšieho spoločného komponentu nájde stredy kruhových značiek zelenej, modrej a oranžovej farby. | ||
+ | *# Určia sa polohy cieľa (stred obrázka), lopty (oranžová značka na obrázku), polomer lopty a pozicia robota. | ||
+ | *# Spočíta sa uhol natočenia robota (podľa zelenej a modrej značky). | ||
+ | *# Vykreslia sa získané body do náhľadového obrázka. | ||
+ | *# Hlavné vlákno programu je notifikované o dokončení cyklu kamery (teda sú spočítané potrebné body pre ďalšiu fázu programu hlavného vlákna). | ||
+ | |||
+ | ==== Gaussovo rozmazanie obrázku ==== | ||
+ | |||
+ | Na rozmazanie obrázka (blur) je použítá aproximácia gaussovho rozmazávacieho algoritmu, ktorý dokáže pracovať v lineárnom čase. Použili sme port algoritmu z JavaScriptu z blogu Ivana Kuckira, nájsť ho je možné na stránke [http://blog.ivank.net/fastest-gaussian-blur.html Fastest Gaussian Blur (in linear time)] (jedná sa o algoritmus 4 na tejto stránke). | ||
+ | |||
+ | Keďže algoritmus počíta s tým, že obrázok je tvorený polom bajtov, kde jeden bajt reprezentuje jeden pixel, bolo nutné obrázok rozdeliť na tri obrázky, ktoré reprezentovali jeho červenú, zelenú a modrú farebnú zložku samostatne. Potom, ako algoritmus rozmazania dokončil svoju prácu na každom z týchto rozdelených obrázkov, bolo treba ich opätovne spojiť do jedného obrázka. Na toto nám slúžia metódy <code>separateColor</code> a <code>putColor</code>. | ||
+ | |||
+ | ==== Prevod z RGB do LAB ==== | ||
+ | |||
+ | Keďže zosnímaný obrázok z kamery je vo formáte, kde jeden pixel je určený štyrmi bajtmi s významom: Blue, Green, Red a posledný je vždy nulový (hodnota 0), pričom tieto hodnoty sú v rozsahu od 0 do 255, je treba najprv každý pixel preformátovať do tvaru RGB, kde každá hodnota je <code>float</code> s hodnotou od 0 do 1. Na to máme metódu <code>getPixel</code> s následným predelením každej zložky hodnotou 255. | ||
+ | |||
+ | Každý pixel je potom vložený do statickej metódy triedy <code>CIELab</code> s názvom <code>fromRGB</code>, ktorá vráti hodnotu pixelu vo formáte farieb LAB. Trieda <code>CIELab</code> na prevod z RGB do LAB ešte používa medzikrok, kde každý RGB pixel prevedie do formátu XYZ, z ktorého následne vytvorí LAB formát. | ||
+ | |||
+ | ==== Práhovanie ==== | ||
+ | |||
+ | Práhovanie používame na získanie mapy informácií o prítomnosti farebnej informácie v LAB formáte v spracovávanom obrázku. Tento algoritmus (metóda <code>prahuj(float[] from, float[] to)</code>) dostáva minimálnu a maximálnu hodnotu práhu farby v LAB formáte a v obrázku zisťuje, pre každý pixel, či je v rozsahu tejto hodnoty alebo nie je. Ak pixel v rozsahu je, dostane výstupná mapa na pozícii pixelu hodnotu 1, v opačnom prípade je použitá hodnota 0. | ||
+ | |||
+ | '''int[]''' ''o'' = '''new int['''potrebná veľkosť''']''' | ||
+ | '''for''' každé ''x'' | ||
+ | '''for''' každé ''y'' | ||
+ | '''if''' pixel na ''x'' a ''y'' je medzi ''from'' a ''to'' | ||
+ | zapíš do ''o'' 1 | ||
+ | '''else''' | ||
+ | zapíš do ''o'' 0 | ||
+ | '''return''' ''o'' | ||
+ | |||
+ | ==== Najväčší spojitý komponent ==== | ||
+ | |||
+ | Výstupom z práhovania je mapa obsahujúca nuly a jednotky, na pozíciách, kde bola zistená vhodná farba. Algoritmus nájdenia najväčšieho spojitého komponentu prehľadáva pôvodnú mapu, v prípade nájdenia hodnoty jedna spustí prehľadávanie do šírky, pričom každý susodný pixel (v každom z 8 smerov) označí hodnotou N. N začína na hodnote 2 a je zvyšovaný po dokončení označenia komponentu, tento číselný údaj je vpisovaný do vstupnej mapy. Tento komponent sa hľadá metódou <code>int flood(int px, int py, int[] in, int n)</code>, ktorá dostáva súradnice prvého bodu komponentu, mapu a číselné označenie komponentu, označí komponent a spočíta počet pixelov v tomto komponente, ktorý následne vráti. | ||
+ | |||
+ | Každý komponent je zapísaný do <code>HashMap</code>, kde kľúč je číslo komponentu a hodnota je počet pixelov v komponente. Po nájdení všetkých komponentov sa určí najväčší z nich a mapa sa opäť preznačí na hodnoty 0 a jednoa takto: | ||
+ | |||
+ | * Ak pixel má hodnotu čísla najväčšieho komponentu, bude nastavený na hodnotu 1. | ||
+ | * Ak pixel má inú hodnotu, bude nastavený na 0. | ||
+ | |||
+ | Metóda hľadajúca najväčší spojitý komponent má názov <code>najSpoj</code>. | ||
+ | |||
+ | ==== Určenie stredu a obálky komponentu ==== | ||
+ | |||
+ | Na získanie stredu a obálky komponentu sa používa metóda <code>drawX</code>. Metóda dostáva mapu s určeným najväčším spojitým komponentom, pričom pre každý pixel, ktorého hodnota je rovná 1, je pozícia pixelu x a y pripočítaná k ceľkovému súčtu. Rovnako sú pre každé x a y upravené hodnoty premenných <code>maxX</code>, <code>minX</code>, <code>maxY</code> a <code>minY</code>. Výsledný stred je vypočítaný ako pomer súčtu x ku počtu pixlov a súctu y k počtu pixlov. | ||
+ | |||
+ | '''int[]''' ''stred'' = '''new int['''6''']''' | ||
+ | '''long''' ''sx'' = 0, ''sy'' = 0 | ||
+ | '''int''' ''maxX'' = 0, ''maxY'' = 0, ''minX'' = ''width'', ''minY'' = ''height'', ''pocet'' = 0 | ||
+ | '''for''' každý ''x'' | ||
+ | '''for''' každý ''y'' | ||
+ | '''if''' pixel ''x'',''y'' patrí komponentu | ||
+ | ''sx'' += ''x'', ''sy'' += ''y'', ''pocet''++ | ||
+ | ''maxX'' = max(''maxX'', ''x'') | ||
+ | ''maxY'' = max(''maxY'', ''y'') | ||
+ | ''minX'' = min(''minX'', ''x'') | ||
+ | ''minY'' = min(''minY'', ''y'') | ||
+ | '''if''' ''pocet'' je 0 | ||
+ | '''return''' ''stred'' | ||
+ | ''stred''[0] = round(''sx'' / ''pocet'') | ||
+ | ''stred''[1] = round(''sy'' / ''pocet'') | ||
+ | ''stred''[2] = ''minX'' | ||
+ | ''stred''[3] = ''minY'' | ||
+ | ''stred''[4] = ''maxX'' | ||
+ | ''stred''[5] = ''maxY'' | ||
+ | '''return''' ''stred'' |
Revision as of 15:32, 27 May 2015
GolfBot spis projektu (pripravuje sa) ...
Contents
Program
Prepojenie s kamerou a určovanie orientačných bodov
Obraz sme získavali pomocou Kinectu pre XBox 360. Máme dve triedy, Kinect
(odvodená od edu.ufl.digitalworlds.j4k.J4KSDK
) a Camera
(implementuje Runnable
).
Hlavný program spúšťa vlákno kamery, ktoré následne pri inicializácii spustí vlákno kinectu v móde J4KSDK.COLOR
. Inštancii tredy Kinect
je potom poslaná referencia na kameru. Trieda Kinect
prekrýva metódu udalosti onColorFrameEvent
, ktorá nastáva po zosnímaní farebného obrazu kinectom, pričom tento obraz posiela inštancii kamery cez referenciu volaním jej verejnej metódy setImageFromKinect
.
Hlavné vlákno kamery vykonáva cyklicky tieto akcie:
Najprv sa otestuje, či existuje snímka z kamery.
- Ak nie, ukončí iteráciu cyklu a pokračuje ďalšou iteráciou.
- Ak áno:
- Vytvorí si novú kópiu obrázku (pre účely spracovania).
- Aplikuje gaussovo rozmazanie pracovného obrázka z polomerom 3px.
- Skonvertuje obrázok z farebného formátu BGR0 do LAB.
- Pomocou práhovania, nájdeniu najväčšieho spojitého komponentu a priemerovania x, y pozícií pixelov najväčšieho spoločného komponentu nájde stredy kruhových značiek zelenej, modrej a oranžovej farby.
- Určia sa polohy cieľa (stred obrázka), lopty (oranžová značka na obrázku), polomer lopty a pozicia robota.
- Spočíta sa uhol natočenia robota (podľa zelenej a modrej značky).
- Vykreslia sa získané body do náhľadového obrázka.
- Hlavné vlákno programu je notifikované o dokončení cyklu kamery (teda sú spočítané potrebné body pre ďalšiu fázu programu hlavného vlákna).
Gaussovo rozmazanie obrázku
Na rozmazanie obrázka (blur) je použítá aproximácia gaussovho rozmazávacieho algoritmu, ktorý dokáže pracovať v lineárnom čase. Použili sme port algoritmu z JavaScriptu z blogu Ivana Kuckira, nájsť ho je možné na stránke Fastest Gaussian Blur (in linear time) (jedná sa o algoritmus 4 na tejto stránke).
Keďže algoritmus počíta s tým, že obrázok je tvorený polom bajtov, kde jeden bajt reprezentuje jeden pixel, bolo nutné obrázok rozdeliť na tri obrázky, ktoré reprezentovali jeho červenú, zelenú a modrú farebnú zložku samostatne. Potom, ako algoritmus rozmazania dokončil svoju prácu na každom z týchto rozdelených obrázkov, bolo treba ich opätovne spojiť do jedného obrázka. Na toto nám slúžia metódy separateColor
a putColor
.
Prevod z RGB do LAB
Keďže zosnímaný obrázok z kamery je vo formáte, kde jeden pixel je určený štyrmi bajtmi s významom: Blue, Green, Red a posledný je vždy nulový (hodnota 0), pričom tieto hodnoty sú v rozsahu od 0 do 255, je treba najprv každý pixel preformátovať do tvaru RGB, kde každá hodnota je float
s hodnotou od 0 do 1. Na to máme metódu getPixel
s následným predelením každej zložky hodnotou 255.
Každý pixel je potom vložený do statickej metódy triedy CIELab
s názvom fromRGB
, ktorá vráti hodnotu pixelu vo formáte farieb LAB. Trieda CIELab
na prevod z RGB do LAB ešte používa medzikrok, kde každý RGB pixel prevedie do formátu XYZ, z ktorého následne vytvorí LAB formát.
Práhovanie
Práhovanie používame na získanie mapy informácií o prítomnosti farebnej informácie v LAB formáte v spracovávanom obrázku. Tento algoritmus (metóda prahuj(float[] from, float[] to)
) dostáva minimálnu a maximálnu hodnotu práhu farby v LAB formáte a v obrázku zisťuje, pre každý pixel, či je v rozsahu tejto hodnoty alebo nie je. Ak pixel v rozsahu je, dostane výstupná mapa na pozícii pixelu hodnotu 1, v opačnom prípade je použitá hodnota 0.
int[] o = new int[potrebná veľkosť] for každé x for každé y if pixel na x a y je medzi from a to zapíš do o 1 else zapíš do o 0 return o
Najväčší spojitý komponent
Výstupom z práhovania je mapa obsahujúca nuly a jednotky, na pozíciách, kde bola zistená vhodná farba. Algoritmus nájdenia najväčšieho spojitého komponentu prehľadáva pôvodnú mapu, v prípade nájdenia hodnoty jedna spustí prehľadávanie do šírky, pričom každý susodný pixel (v každom z 8 smerov) označí hodnotou N. N začína na hodnote 2 a je zvyšovaný po dokončení označenia komponentu, tento číselný údaj je vpisovaný do vstupnej mapy. Tento komponent sa hľadá metódou int flood(int px, int py, int[] in, int n)
, ktorá dostáva súradnice prvého bodu komponentu, mapu a číselné označenie komponentu, označí komponent a spočíta počet pixelov v tomto komponente, ktorý následne vráti.
Každý komponent je zapísaný do HashMap
, kde kľúč je číslo komponentu a hodnota je počet pixelov v komponente. Po nájdení všetkých komponentov sa určí najväčší z nich a mapa sa opäť preznačí na hodnoty 0 a jednoa takto:
- Ak pixel má hodnotu čísla najväčšieho komponentu, bude nastavený na hodnotu 1.
- Ak pixel má inú hodnotu, bude nastavený na 0.
Metóda hľadajúca najväčší spojitý komponent má názov najSpoj
.
Určenie stredu a obálky komponentu
Na získanie stredu a obálky komponentu sa používa metóda drawX
. Metóda dostáva mapu s určeným najväčším spojitým komponentom, pričom pre každý pixel, ktorého hodnota je rovná 1, je pozícia pixelu x a y pripočítaná k ceľkovému súčtu. Rovnako sú pre každé x a y upravené hodnoty premenných maxX
, minX
, maxY
a minY
. Výsledný stred je vypočítaný ako pomer súčtu x ku počtu pixlov a súctu y k počtu pixlov.
int[] stred = new int[6] long sx = 0, sy = 0 int maxX = 0, maxY = 0, minX = width, minY = height, pocet = 0 for každý x for každý y if pixel x,y patrí komponentu sx += x, sy += y, pocet++ maxX = max(maxX, x) maxY = max(maxY, y) minX = min(minX, x) minY = min(minY, y) if pocet je 0 return stred stred[0] = round(sx / pocet) stred[1] = round(sy / pocet) stred[2] = minX stred[3] = minY stred[4] = maxX stred[5] = maxY return stred