Projects AI Robotics

From RoboWiki
Revision as of 18:10, 27 May 2015 by Robot (talk | contribs)
Jump to: navigation, search

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, 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:
    1. Vytvorí si novú kópiu obrázku (pre účely spracovania).
    2. Aplikuje gaussovo rozmazanie pracovného obrázka z polomerom 3px.
    3. Skonvertuje obrázok z farebného formátu BGR do LAB.
    4. 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.
    5. Určia sa polohy cieľa (stred obrázka), lopty (oranžová značka na obrázku), polomer lopty a pozicia robota.
    6. Spočíta sa uhol natočenia robota (podľa zelenej a modrej značky).
    7. Vykreslia sa získané body do náhľadového obrázka.
    8. 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).

Diagram spracovania obrázka z kamery

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