Ovládání počítače

July 23rd, 2010 uiii No comments

Jakmile jsem měl zprovozněné snímání z kamery, musel jsem pořád do pilotní verze projektu ještě něco udělat. Rozhodl jsem se, že udělám rozhraní pro ovládání počítače posíláním falešných událostí (stisk klávesy, pohyb myši, kliknutí, …).

Zasílání falešných událostí rozhodně nebylo tak snadné jak jsem si zprvu myslel. Původně jsem měl za to, že to zvládne Qt knihovna a to rovnou přenositelně. Bohužel jsem rychle zjistil, že byla celkem mylná představa. Qt sice umí posílat události, ale jen pro svoje widgety, takže jsem se musel poohlédnout někde jinde. Moc jsem na výběr neměl, jako jediná možnost se zdá knihovna Xlib a její rozšíření XTest pro X Window system. Takže o nějaké přenositelnosti jsem si mohl nechat zdát. No každopádně jsem začal studovat posílání událostí v Xlib. Rošíření XTest není nutné používat, ale ohromně to ulehčí práci. Našel jsem tedy příklad s použitím pouze Xlib kihovny ale i pár příkladů s použitím XTest rozšíření.

Nejprve jsem se pustil od klávesnicových událostí:

Pro odeslání klávesnicové události je potřeba znát název události (klávesy). Z názvu klávesy lze zjistit název keysym konstanty, což je číslo reprezentující konkrétní klávesu. Keysym je pak nutné převést kód události, tzv. keycode, ten už se pak jednoduše předhodí funkci pro vyvolání události.

Název keysym se odvodí tak, že se před název klávesy připojí XK_. Převod keysym na keycode se provede pomocí funkce XKeysymToKeycode.

Pro samotné odeslání události je určena funkce XTestFakeKeyEvent z rozšíření XTest.

Kód pro odeslání události stisku klávesy enter by vypadal takto:

1
2
3
4
5
6
Display* display = XOpenDisplay(0);
 
KeySym keysym = XK_Return;
Keycode keycode = XKeysymToKeycode(display, keysym);
 
XTestFakeKeyEvent(display, keycode, true, CurrentTime);

Zdrojový kód ukázkové aplikace je zde.

S událostmi pro ovládání myši se pracuje takto:

U myši jsou dva typy událostí – pohyb nebo stisk/uvolnění tlačítka (mezi něž se počítá i točení kolečkem).

Pro pohyb s kurzorem jsou určeny dvě funkce XTestFakeMotionEvent a XTestFakeRelativeMotionEvent. Fuknce se liší pouze v tom, že ta první umístí kurzor na danou pozici, kdežto ta druhá ho posune relativně vůči aktuální pozici.

Stisk tlačítka myši se provede funkcí XTestFakeButtonEvent. Je potřeba znát číslo tlačítka, číslování je následující: 1 – levé tlačítko, 2 – prostřední tlačítko (kolečko), 3 – pravé tlačítko, 4 – točení kolečkem nahoru a 5 – točení kolečkem dolu.

Kód pro pohyb myši na pozici [10;10], následné přesunutí směrem [5;3] a na konec kliknutí pravým tlačítkem bude tedy tento:

1
2
3
4
5
6
7
Display* display = XOpenDisplay(0);
 
XTestFakeMotionEvent(display, -1, 10, 10, CurrentTime);
XTestFakeRelativeMotionEvent(display, 5, 3, CurrentTime);
 
XTestFakeButtonEvent(display, 3, true, CurrentTime);
XTestFakeButtonEvent(display, 3, false, CurrentTime);

Zdrojový kód ukázkové aplikace je zde.

A nakonec jak vykonat příkaz pro shell:

Vykonání příkazu sice není přímo událost, ale zařadím to mezi ně. Nyní už není potřeba knihovna Xlib, stačí už pouze systémový hlavičkový soubor stdlib.h a funkce system. Této funkci se jednoduše předá jako argument řetězec obsahující příkaz pro shell a ona ho jednoduše vykoná, toť vše. Toto je si moc pěkné, ale je potřeba si dát na něco pozor. Pokud příkaz spouští program, který vyžaduje vstup z konzole a vaše aplikace vyvolávající onen příkaz nebyla puštěna z konzole, může dojít k zamrznutí X serveru.

Zde ještě na ukázku kód spouštějící webový prohlížeč firefox:

1
system("firefox");

Zdrojový kód ukázkové aplikace je zde.

Pokud byste si chtěli zde zmiňované vyzkoušet naživo, pak po zkompilování projektu budou ve složce bin/test/manual_tests/ testovací mini-aplikace.

Snímání z kamery

July 17th, 2010 uiii No comments

Zprovoznil jsem základní snímání z kamery. Obsluhu snímání jsem zapouzdřil do třídy Camera s nejdůležitější metodou getFrame, která vrací aktuální snímek z kamery jako instanci objektu QImage.

Ve starších verzích knihovny OpenCV se pro reprezentaci snímku z kamery používal IplImage, na internetu je možné nalézt několik příkladů na převod IplImage -> QImage. V aktuální verzi OpenCV se ale už IplImage nepoužívá a je nahrazen třídou cv::Mat, která se používá pro reprezentaci matice, obrázku, mapy optického toku, atd.

Musel jsem tedy provést převod objektu cv::Mat (OpenCV) na QImage (Qt).

Převod cv::Mat -> QImage je opravdu jednoduchý:

1
2
3
4
5
6
7
8
9
10
11
12
QImage Camera::cvMatToQImage(const cv::Mat& image) const
{
    QImage qImage(
        image.data,
        image.size().width,
        image.size().height,
        image.step,
        QImage::Format_RGB888
    );
 
    return qImage.rgbSwapped();
}

Otestovat snímání můžete pomocí manuálního testu cameraTest_manual (po kompilaci se spustitelný test objeví ve složce bin/test/manual_tests/)

Knihovna pro TDD

July 15th, 2010 uiii No comments

Takže nasazuji knihovnu CxxTest pro unit-testování. Proč zrovna tuhle? Za prvné má v tomto článku dobré hodnocení, za druhé se mi ji podařilo snadno rozběhat a za třetí jsem si ji už trochu odzkoušel na jedné práci do školy. Netvrdím, že je to nejlepší knihovna pro TDD, jsem ale zatím spokojený.

Test-driven development a GUI

July 13th, 2010 uiii No comments

Jak jsem již psal ve specifikaci, chtěl bych jako GUI použít knihovnu Qt. Na internetu jsem našel aplikaci, která snímá obraz z web-kamery pomocí OpenCV a následně ho zobrazuje pomocí Qt, takže není problém skloubit obě knihovny dohromady. Problém ale byl v tom, že přenášený obraz nebyl tak plynulý jak by mohl být. Nakonec jsem zde narazil na program ke stažení, který zvládá přenášení obrazu krásně plynule, tedy možné to je a mám se z čeho inspirovat.

Co se týče způsobu vývoje projektu, tak mě velmi zaujal Test-driven development (Programování řízené testy). Nemám sice s touto metodikou žádné praktické zkušenosti, ale pokusím se ji využívat co nejvíc to půjde. Při zpracovávání obrazu se ale najdou situace, které prostě takto testovat nelze, nebo alespoň nemám tušení jak to rozumně realizovat (výsledek algoritmu po zpracování obrazu, záznam z kamery, …). Budu tedy testovat pomocí unit testů jen kód u které ho to má smysl a pro ostatní případy napíšu testy spíše jako příklad užití, které nebudou prováděny automaticky, ale ručně.

Nyní už mi zbývá jen vybrat tu správnou knihovnu pro řešení TDD a můžeme vyrazit.

Začátek projektu

July 10th, 2010 uiii No comments

Tímto dnem oficiálně začínám pracovat na projektu Webcam control.

Na github.com jsem založil repozitář projektu.

První nejbližší termín je 17.7.2010, do kdy mám udělat pilotní verzi projektu. Tedy minimálně rozběhat snímání obrazu z kamery a k tomu buď základní detekci objektů, nebo simulaci ovládání počítače pomocí skriptu, na kterou pak naváži s detekcí objektů.

Nyní se jdu tedy rozběhat kameru a ponořit do studia knihovny OpenCV :-) .

Categories: Webcam control Tags: , ,