Difference between revisions of "Projects AI Robotics"
m (→2015) |
m |
||
Line 1: | Line 1: | ||
− | + | [[Projects_AI_Robotics|Nazad na projekty ...]] | |
− | + | 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 BGR do LAB. | ||
+ | *# Pomocou prahovania, 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 a lopty. | ||
+ | *# 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. | |
− | + | ==== Prahovanie ==== | |
− | [[ | + | Prahovanie používame na získanie masky 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 prahu 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á maska 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 prahovania je maska 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ú masku, v prípade nájdenia hodnoty jedna spustí prehľadávanie do šírky, pričom každý susedný 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 masky. 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, masku 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 maska 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 AABB ohraničenia komponentu ==== | |
− | + | Na získanie stredu a AABB ohraničenia komponentu sa používa metóda <code>drawX</code>. Metóda dostáva masku 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 16:06, 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 BGR do LAB.
- Pomocou prahovania, 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 a lopty.
- 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.
Prahovanie
Prahovanie používame na získanie masky 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 prahu 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á maska 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 prahovania je maska 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ú masku, v prípade nájdenia hodnoty jedna spustí prehľadávanie do šírky, pričom každý susedný 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 masky. 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, masku 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 maska 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 AABB ohraničenia komponentu
Na získanie stredu a AABB ohraničenia komponentu sa používa metóda drawX
. Metóda dostáva masku 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