spájame
slovenskú
IT komunitu
pridaj sa
Registrácia · Login

Jozef Bakos 16.12.2016
Hodnoť článok:
0 0

Keď sa projekt zmení na poslanie a príbeh bez šťastného konca (2).

Dozviete sa ako som začínal od nuly vytvárať pomôcky pre umierajúcich ľudí

Toto je príbeh o tom, ako sa môj sen stal poslaním, žiaľ bez šťastného konca. Príbeh, ktorý nemá koniec a zatiaľ vždy končí stále rovnako. Dozviete sa ako som začínal od nuly vytvárať pomôcky pre umierajúcich ľudí a kde v zúfalstve pretiekli aj moje posledné nervy. V tejto časti si ukážeme podrobnejšie, ako mnou písané programy v Delphi fungovali.

Pôvodný program bol navrhnutý tak aby umožňoval plnohodnotne ovládať Windows prostredie. Celé to bolo založené na tom, že bola sledovaná poloha kurzoru a očakávali sa na určité gestá ( konkrétne súradnice, ako napríklad Y=0 ). V tejto dobe som sa učil programovať OOP ( objektovo orientované programovanie ), no teraz sa len posmejem, keď vidím výplod svojej práce, algoritmus, ktorý zaisťoval sledovanie polohy kurzoru:

// Real mouse x and mouse y position

MouseX:=Mouse.CursorPos.X;

MouseY:=Mouse.CursorPos.Y;

// Asistence switch

if TrackerDevice<>'light' then begin

// Left click emulation

if MouseX=0 then LeftClick:=true;

if LeftClick=true then begin

if BlockSound=0 then begin // Block sound event

if EnableSound='EnableSound:=true' then PlaySound('sounds\lavy.wav',0,0);

BlockSound:=1;

end;

if LeftClick=true then begin

if MouseX=TMPMouseX then begin // Detect changes in position

if MouseY=TMPMouseY then begin

for LoopStop:=1 to 2 do begin // Doble click emulation

mouse_event(MOUSEEVENTF_LEFTDOWN, mousex, mousey, 0, 0);

mouse_event(MOUSEEVENTF_LEFTUP, mousex, mousey, 0, 0);

sleep(500);

end;

end;

end;

TMPMouseX:=MouseX;

TMPMouseY:=MouseY;

if mousey=0 then begin

LeftClick:=false;

BlockSound:=0;

if EnableSound='EnableSound:=true' then PlaySound('sounds\zrusenylavy.wav',0,0);

end;

end;

end;

// Right click emulation

HighScrResolution:=Screen.Width-1;

if MouseX=HighScrResolution then RightClick:=true;

if RightClick=true then begin

if BlockSound=0 then begin // Block sound event

if EnableSound='EnableSound:=true' then PlaySound('sounds\pravy.wav',0,0);

BlockSound:=1;

end;

if MouseX=TMPMouseX then begin // Detect changes in position

if MouseY=TMPMouseY then begin

for LoopStop:=1 to 2 do begin

mouse_event(MOUSEEVENTF_RIGHTDOWN, mousex, mousey, 0, 0);

mouse_event(MOUSEEVENTF_RIGHTUP, mousex, mousey, 0, 0);

sleep(500);

end;

end;

end;

TMPMouseX:=MouseX;

TMPMouseY:=MouseY;

if mousey=0 then begin

RightClick:=false;

BlockSound:=1;

if EnableSound='EnableSound:=true' then PlaySound('sounds\zrusenypravy.wav',0,0);

end;

end;

end;

// Display form1 after y=highest resolution

HighScrResolution:=Screen.Height-1;

if MouseY=HighScrResolution then begin

if TrackerDevice='light' then Form2.Show

Ako je vidieť v zdrojovom kóde, keď sa kurzor dostane na určité súradnice, vtedy spúšťa požadovanú úlohu. Ľavý a pravý klik je riešený tak, že keď v prípade ľavého kliku pôjdete do ľavého rohu ( spustíte emuláciu ľavého kliku ) tak sa čaká pokiaľ nezastavíte na tom mieste, ktoré chcete kliknúť ľavým tlačidlom. To isté platí aj pre pravý klik, no problém je v tom, že vtedy som bol pevne presvedčený, že sa mi podarí odstrániť problém s neurčitosťou kurzoru, a že riadenie polohy kurzoru bude rovnako precízne, ako je tomu u polohovaní počítačovou myškou. Je jasné, že dnes produkt viacej predáva a oslovi dizajn ako funkcionalita no a tak som sa zameral aj na grafické efekty.

Tento algoritmus postupne nechal zmiznúť okno:

Form1.Show;

Form1.WindowState:=wsNormal;

LeftClick:=true;

Form1.AlphaBlendValue := 255-strtoint(TranspaSeting); // 0..255

Form1.AlphaBlend := True;

Timer2.enabled:=true;

end;

end;

S načítavaním konfiguračného súboru som si moc hlavu nelámal a urobil som to ako pravý začiatočník. Viď ukážka s kódu:

// Real PATH to pa.exe

apath:=ExtractFilePath(Application.ExeName);

// Load ICO to tray

TrayIcon1.Icon.LoadFromFile(apath+'update\pa.ico');

TrayIcon1.Show;

// Load Setings from file

AssignFile(f,apath+'youtribe.ini');

try

ReSet(f);

Readln(f,ID);

Readln(f,TimerSeting);

Readln(f,TranspaSeting);

Readln(f,TrackerDevice);

Readln(f,AutoUpdate);

Readln(f,EnableSound);

Readln(f,Go2TransparentFrame);

Readln(f,AppWatcher);

Closefile(f);

except // Error on load file

on E : Exception do begin

ShowMessage('Zapnite youtribe.exe a spustite inštaláciu.');

halt;

end;

end;

Základnou úlohou podprogramu pa.exe ( personálny asistent ) bolo sledovanie polohy kurzoru a podľa toho spúšťať požadovanú úlohu alebo aplikáciu. V tej dobe som sa snažil použiť TTS od Microsoftu, ale zistil som, že nepodporuje jazyky ( SK a CZ ). Riešenie bolo napísať vlastný hlasový syntetizátor. Dlho netrvalo a napísal som vlastný algoritmus pre rozklad vedy a následnú syntéza hlasu.

Rozkladový algoritmus a hlasová syntéza:

begin

EnterWord:=Edit1.text;

for j:=1 to length(EnterWord) do

begin

SpeakThis:=apath+'sounds\'+Copy(EnterWord, j, 1)+'.wav';

PlaySound(pchar(SpeakThis),0,0);

end;

// Clean Edit 1

Edit1.Clear;

end;

Ďalšie utility ako setup.exe ( Lazarus ), callhelp.exe ( Blizt3D ) a server.exe ( Blitz3D ), boli vlastne iba prídavne utility. Zatiaľ ale jedinou plne funkčnou vecou bolo setup.exe. Ak si zdrojové kódy poriadne preštudujete, nájdete tam zaujímavé veci a aj také, ktoré mali riešiť podivné chovanie Lazarusu a spúšťanie ďalších súborov. Youtribe ( youtribe.exe ) bol samostatný inštalačný program, ktorý používal knižnicu synapse pre sťahovanie obsahu s serveru, detekciu operačného systému ( 32 lebo 64 bit ) a zápis do registrov a samozrejme generovanie nastavenia. Programy boli žiaľ použiteľné len v prípade, že ste mali zdravé ruky a tak som bol nútený vylepšiť moje zariadenie na sledovanie očí.

Problémom bolo vlastné zariadenie na sledovanie oči a taktiež obslužný program pre výpočet polohy oka. Teraz sa budeme podrobnejšie venovať riešeniu problému s neurčitosťou polohy kurzoru. Kamera musela byť umiestnená priamo pred okom tak, aby zaberala čo najviac samotného oka.

Najlepšie pozícia snímania oka:


Tu si vysvetlíme, ako funguje tento algoritmus napísaný v jave:

/*

(C) Jozef Bakoš, jb@jbakos.sk
Publikované pod GNU/GPL v3
*/

// Import external function
import processing.video.*;
import java.awt.AWTException;
import java.awt.Robot;

// Global definition
Capture cam;
PImage img; // Eye motion detect
iWidth = 640; // Screen resolution Width
int ScreenHeight = 480; // Screen resolution Height
int brightestX = ScreenWidth/2; // X-coordinate of the brightest video pixel
int brightestY = ScreenHeight/2; // Y-coordinate of the brightest video pixel
int MouseXposition=ScreenWidth/2;
int MouseYposition=ScreenHeight/2;
PImage prevFrame; // Eye motion detect
Capture video;
Robot robot;

// Setup web cam and frame definition
void setup() {
size(ScreenWidth, ScreenHeight); // Setup screen resolution
String[] cameras = Capture.list(); // List of web cams
img = loadImage("jblogo.png"); // Load logo

// Check if web cam is available
if (cameras.length == 0) {
exit(); // Not present is exit
}

// Web cam available
cam = new Capture(this, cameras[0]);
println("Selected camera:"+ cameras[0]);
cam.start();
prevFrame = createImage(ScreenWidth,ScreenHeight,RGB);

try {
robot = new Robot();
}
catch (AWTException e) {
e.printStackTrace();
}
robot.mouseMove(displayWidth/2, displayHeight/2);
}

void draw() {
frame.setTitle("eyeCTRL by jb"); // Frame name
if (cam.available() == true) {
prevFrame.copy(cam,0,0,cam.width,cam.height,0,0,cam.width,cam.height);
prevFrame.updatePixels();
cam.read();
}
image(cam, 0, 0);
image(img, 0, ScreenHeight-60, img.width/2, img.height/2); // Show logo

// Draw a large, yellow circle at the darkest pixel
fill(255, 204, 0, 128);
//ellipse(brightestX, brightestY, 40, 40);

float brightestValue = 255; // Brightness of the darkest video pixel
// Search for the darkest pixel: For each row of pixels in the video image and
cam.loadPixels();
int index = 0;
for (int y = 0; y < cam.height; y++) {
for (int x = 0; x < cam.width; x++) {

int loc = x + y*cam.width;
color current = cam.pixels[loc];
color previous = prevFrame.pixels[loc];

float r1 = red(current); float g1 = green(current); float b1 = blue(current);
float r2 = red(previous); float g2 = green(previous); float b2 = blue(previous);
float diff = dist(r1,g1,b1,r2,g2,b2);
if (diff > 190) {

for (y = 0; y < cam.height; y++) {
for (x = 0; x < cam.width; x++) {
// Get the color stored in the pixel
int pixelValue = cam.pixels[index];
// Determine the brightness of the pixel
float pixelBrightness = brightness(pixelValue);
float pixelBrightness2 = brightness(pixelValue+1);
float pixelBrightness3 = brightness(pixelValue+2);
float pixelBrightness4 = brightness(pixelValue+3);
float pixelBrightness5 = brightness(pixelValue+4);
float pixelBrightness6 = brightness(pixelValue+5);
float pixelBrightness7 = brightness(pixelValue+6);
float pixelBrightness8 = brightness(pixelValue+7);
// If that value is darker than any previous, then store the
// brightness of that pixel, as well as its (x,y) location
if (pixelBrightness < brightestValue && pixelBrightness2 < brightestValue && pixelBrightness3 < brightestValue && pixelBrightness4 < brightestValue && pixelBrightness5 < brightestValue && pixelBrightness6 < brightestValue && pixelBrightness7 < brightestValue && pixelBrightness8 < brightestValue ) {
brightestValue = pixelBrightness;
brightestY = y;
brightestX = x;
println("Suradnice X: "+x+" Suradnice Y:"+y);
robot.mouseMove(x, y);
}
index++;
}
}
}
}
}

}

V podstate si prejdeme každý nasnímaný pixel v horizontálnej aj vertikálnej časti a hľadáme čierne body, ktoré potom označíme a zaznamenáme. Tam, kde je čiernych bodov najviac, sa nachádza zrenička, zatiaľ jednoduché. Aby ste si vedeli predstaviť ako to vypadá, tu je ukážka:

Vidieť, že teória je síce pekná vec, prax je podstatne iná. Čiernych bodiek je viac než by sme potrebovali a je viacej miest kde sú pokope. Tento problém som sa snažil riešiť osvetľovaním bielim svetlom, ktoré odstraňovalo čierne bodky tam, kde nemajú byť. Výsledok tohto snaženia vidíte tu:

Výsledok zatiaľ slušný, menšie zhluky čiernych bodiek sú preč ak nerátame, že oko dráždime bielim svetlom. Rovnaký výsledok dostanete aj keď použijete IR podsvietenie. Kamera musí byť stále presne nad (resp. pred) okom, v zornom poli a musí snímať čisto iba oko. Ako je vidieť, zornička je mierne rozpadnutá a tento problém spôsobuje šumenie, ktoré nám vytvára kamera. Tým nám vzniká ďalší problém s určovaním polohy oka, tým je naša neurčitosť polohy oka. Algoritmus toto šumenie vyhodnocuje ako pohyb oka aj v prípade, žiaden pohyb nie je. Kurzor behá všetkými smermi bez predvídateľného chovania, pokúšal som sa to kompenzovať tak, že som dopísal detektor pohybu, ktorý pri určitej zmene pixelov spusti samotný hore uvedený algoritmus. Výsledok bol síce lepši, ale stále sa nedal ovládať počítač. Ďalším zásadným problémom bolo že pohyb kurzora bol +- 20 pixelov. Toto som sa snažil riešiť tak, že som vypočítaval z rozlíšenia obrazovky o koľko pixelov sa pohne kurzor. Problém bol už pri skoku 50 pixelov sa trafiť do malého tlačidla.

Z hľadiska konštrukcie polohovacieho zariadenia vychádzalo, že musím isť do IR kamery, ktorá odstraňuje problémy ktoré mám už v samotnej podstate. Chcel som sa tomuto vyhnúť, lebo tieto kamery sú drahé. Našťastie sa mi podarilo prerobiť normálnu web kameru na IR kameru. Ale toto budeme preberať až v ďalšom pokračovaní príbehu.

Jozef Bakos Jozef Bakos

Astronóm, hacker, programator a milovník všetkého čo boh stvoril. Astronóm srdcom aj dušou nenávidím ľudskú hlúposť lebo ta je bez konca na rozdiel od vesmíru. Moje projekty: nadejazivot.sk


Hodnoť článok:
0 0

1 komentár k článku:

Komentovať môžu iba prihlásení

Zaregistruj sa cez bezplatnú registráciu alebo použi login cez Facebook (FB Connect)

Prihlás sa tu, ak už máš profil na Zajtra.sk:


Zabudol som heslo

0 0 Jozef Bakos 16.12.2016 01:31:54
Kód pre sledovanie oči: http://download.vpnhosting.cz/jb/OpenSource/osetrybe.zip
Zajtra.sk > Technológie > Software > Keď sa projekt zmení na poslanie a príbeh bez šťastného konca (2).


Kritika

Vieš ako robiť veci lepšie? Pomôž našim odvážnejším členom a skritizuj im projekty!

Reklama

Seriály zo Zajtra.sk

Reklama