2009-07-20 9 views
10

Sto utilizzando XNA per creare un progetto in cui posso disegnare "graffiti" sulla mia parete utilizzando un proiettore LCD e una fotocamera monocromatica che viene filtrata per vedere solo puntatori laser a mano. Voglio usare qualsiasi numero di puntatori laser - non mi interessa davvero distinguerli a questo punto.Rilevamento rapido del punto laser sub-pixel

La parete è 10' x 10' , e la fotocamera è soltanto 640x480 quindi sto tentando di usare la misurazione sub-pixel utilizzando una curva spline come illustrato qui: tpub.com

La fotocamera funziona a 120 fps (8 -bit), quindi la mia domanda a tutti voi è il modo più veloce per trovare quel centro del punto laser subpixel. Attualmente sto usando una ricerca 2D a forza bruta per trovare il pixel più luminoso sull'immagine (0 - 254) prima di eseguire l'interpolazione spline. Questo metodo non è molto veloce e ogni frame richiede più tempo del computer.

Modifica: per chiarire, alla fine i dati della fotocamera sono rappresentati da una matrice 2D di byte che indica la luminosità dei pixel.

Quello che mi piacerebbe fare è usare uno shader XNA per scricchiolare l'immagine per me. È pratico? Da quello che ho capito, non c'è davvero un modo per mantenere le variabili persistenti in un Pixel Shader come totali, medie, ecc.

Ma per ragioni argomentative, diciamo che ho trovato i pixel più luminosi usando la forza bruta, quindi memorizzato loro e i loro pixel adiacenti per la curva spline in X numero di vertici usando texcoords. È pratico quindi utilizzare HLSL per calcolare una curva spline usando texcoords?

Sono aperto anche a suggerimenti esterni al mio box XNA, sia DX10/DX11, forse una sorta di FPGA, ecc. Non ho molta esperienza con i metodi di scriccatura dei dati in questo modo. Immagino che se possono fare qualcosa del genere su un Wii-Mote usando 2 batterie AA, probabilmente sto andando in questo modo sbagliato.

Qualche idea?

+0

Che cos'è lento eseguire la scansione o eseguire l'interpolazione spline in seguito? – Nosredna

+0

L'interpolazione spline è di gran lunga la componente più lenta di esso, a seconda del delta con cui valuto la spline. In questo caso, vorrei una precisione di 0.1px. – bufferz

+0

Devo aggiungere che se avessi 20 laser, il calcolo spline diventerebbe molto costoso cPU saggio. – bufferz

risposta

3

Hai a che fare con matematica piuttosto complessa se vuoi la precisione sub-pixel. Penso che lo this paper sia qualcosa da considerare. Sfortunatamente, dovrai pagare per vederlo usando quel sito. Se hai accesso a una libreria adatta, potrebbero essere in grado di procurarselo.

Il collegamento nel post originale suggeriva di eseguire calcoli a spline 1000 per ciascun asse: trattava xey indipendentemente, il che è OK per le immagini circolari ma è un po 'off se l'immagine è un'ellisse asimmetrica. È possibile utilizzare il seguente per ottenere una stima ragionevole:

x c = somma (x n .F (x n))/sum (f (x n))

dove x c è la media, x n è il punto lungo l'asse x ed f (x n) è il valore al punto x n. Quindi, per questo:

  * 
     * * 
     * * 
     * * 
     * * 
     * * 
     * * * 
    * * * * 
    * * * * 
* * * * * * 
------------------ 
2 3 4 5 6 7 

dà:

somma (x n .f (x n)) = 1 * 2 + 3 * 3 + 4 * 9 + 5 * 10 + 6 * 4 + 7 * 1

somma (f (x n)) = 1 + 3 + 9 + 10 + 4 + 1

x c = 128/28 = 4,57

e ripetere per l'asse y.

+0

Funziona abbastanza bene. Questo per me è molto più veloce della mia implementazione spline. È praticamente tutto il tempo reale! Grazie per il suggerimento. – bufferz

+0

Informazioni sul collegamento: basta cercare il titolo. Top hit: http://groups.mrl.illinois.edu/granick/Publications/pdf%20files/2009/stephen_2009_image%20analysis%20with%20rapid%20and%20accurate%202d%20gaussian%20fit.pdf – jnm2

5

Se per forzatura Brute intendete osservare ogni pixel in modo indipendente, è fondamentalmente l'unico modo per farlo. Dovrai scansionare tutti i pixel delle immagini, indipendentemente da ciò che vuoi fare con l'immagine. Sebbene non sia necessario trovare i pixel più luminosi, è possibile filtrare l'immagine per colore (es .: se si utilizza un laser rosso). Questo è fatto facilmente usando un'immagine con codice colore HSV. Se stai cercando algoritmi più veloci, prova OpenCV. E 'stato ottimizzato ancora e ancora per il trattamento delle immagini, ed è possibile utilizzarlo in C# tramite un wrapper:

[http://www.codeproject.com/KB/cs/Intel_OpenCV.aspx][1]

OpenCV può anche aiutare a trovare facilmente i centri di punti e tenere traccia di ogni punti.

C'è un motivo per cui si sta utilizzando una fotocamera 120fps? sai che l'occhio umano può vedere solo circa 30fps giusto? Immagino che segua movimenti laser molto veloci ... Potresti prendere in considerazione l'idea di ridurlo, perché l'elaborazione in tempo reale di 120fps sarà molto difficile da raggiungere.

4

che attraversa 640 * 480 byte per trovare il byte più alto dovrebbe essere eseguito entro un ms. Anche con processori lenti. Non c'è bisogno di prendere la via degli shader.

Consiglierei di ottimizzare il ciclo. per esempio: questo è molto lento (perché fa una moltiplicazione con ogni ricerca array):

byte highest=0; 
foundX=-1, foundY=-1; 
for(y=0; y<480; y++) 
{ 
    for(x=0; x<640; x++) 
    { 
     if(myBytes[x][y] > highest) 
     { 
      highest = myBytes[x][y]; 
      foundX = x; 
      foundY = y; 
     } 
    } 
} 

questo è molto più veloce:

byte [] myBytes = new byte[640*480]; 
//fill it with your image 

byte highest=0; 
int found=-1, foundX=-1, foundY=-1; 
int len = 640*480; 
for(i=0; i<len; i++) 
{ 
    if(myBytes[i] > highest) 
    { 
     highest = myBytes[i]; 
     found = i; 
    } 
} 
if(found!=-1) 
{ 
    foundX = i%640; 
    foundY = i/640; 
} 

Questa è la parte superiore della mia testa così dispiaciuto per errori; ^)

3

La forza bruta è l'unico modo reale, tuttavia la tua idea di utilizzare uno shader è buona: stai scaricando il controllo della forza bruta dalla CPU, che può guardare solo un piccolo numero di pixel contemporaneamente (all'incirca 1 per core), alla GPU, che probabilmente ha 100 o più core muti (pipeline) che possono confrontare simultaneamente i pixel (potrebbe essere necessario modificare un po 'il tuo algoritmo per funzionare bene con l'istruzione 1-molti core di una GPU).

Il problema maggiore che vedo è se è possibile spostare tali dati sulla GPU abbastanza velocemente.

+0

Come posso monitorare il singolo pixel più alto su un frame nella GPU? Sto capendo questo corretto in quanto i core muti non possono condividere la memoria in un modo che permetterebbe loro di confrontare un pixel con il pixel più luminoso precedente? – bufferz

+1

Una GPU può essere pensata come una grande raccolta di CPU veramente semplici ottimizzate per le operazioni matematiche. La più grande differenza però è che il decodificatore di istruzioni è stato rimosso - un singolo controller invia le stesse istruzioni a ciascun core muto, dove viene eseguito su quel pezzo di dati core. Le istruzioni IF vengono eseguite eseguendo lo stesso codice due volte: invece di diramazioni, i core che non corrispondono alla condizione si fermano. Gli stessi dati vengono quindi inviati nuovamente, ma con l'istruzione di confronto invertita. – David

+1

Nel tuo caso, non puoi confrontare il pixel più luminoso * immediato * precedente, perché uno qualsiasi dei (128) core potrebbero aver trovato un pixel più luminoso. Invece, cerca di concentrare ogni nucleo sulla propria linea - trova il pixel più luminoso della linea (elaborando 128 linee contemporaneamente). Una volta che le linee nell'immagine sono state effettivamente riassunte come solo il pixel più luminoso in quella linea, è possibile trovare il più luminoso in maniera seriale. – David

1

Mettere leggermente la fotocamera fuori fuoco e bitblt contro un campione neutro. È possibile eseguire rapidamente la scansione delle righe per valori non 0. Inoltre, se si è a 8 bit e si acquisiscono 4 byte alla volta, è possibile elaborare l'immagine più rapidamente. Come altri hanno sottolineato si potrebbe ridurre la frequenza dei fotogrammi. Se si ha meno fedeltà dell'immagine risultante, non vi è molto margine nell'alta velocità di scansione.

(Il leggero fuori fuoco fotocamera aiuterà ottenere solo i punti più luminosi e ridurre i falsi positivi se si dispone di una superficie occupata ... ovviamente supponendo che non sono riprese una superficie liscia/piatta)

2

Un'altra ottimizzazione considerare: se stai disegnando, la posizione corrente del puntatore probabilmente chiuderà l'ultima posizione del puntatore. Ricorda l'ultima posizione registrata del puntatore tra i frame e scansiona solo una regione vicino a quella posizione ... ad esempio un'area di 1'x1 '. Solo se il puntatore non viene trovato in quell'area, si dovrebbe eseguire la scansione dell'intera superficie.

Ovviamente, ci sarà un compromesso tra la rapidità con cui il programma è in grado di eseguire la scansione e quanto velocemente sarete in grado di muovere il mouse prima che la fotocamera "perda" il puntatore e debba andare al lento, immagine intera scansione. Probabilmente una piccola sperimentazione rivelerà il valore ottimale.

Progetto interessante, a proposito.

+0

Perché solo 1x1. Perché non aumentare la dimensione 1^2. Quindi, se non viene trovato in una 1x1, allora controllerà 2x2, 4x4 ecc. Un po 'di attenzione e potresti attraversare l'area che hai già controllato. –

+0

Ci ho pensato anche io. Ma può avere più laser, quindi dovrà comunque controllare ogni pixel. Un laser può accendersi o rientrare nell'area senza preavviso. – Nosredna

1

Inizia con un buffer di output nero. Dimentica il subpixel per ora. Ogni fotogramma, ogni pixel, fai questo:

outbuff = max (outbuff, inbuff);

Fa filtraggio subpixel a un terzo buffer "pulito" quando hai finito con l'immagine. Oppure fai un chunk o una linea dello schermo alla volta in tempo reale. Vantaggio: vista "grezza" in tempo reale del disegno, ripulita man mano che si procede.

Quando si converte dal buffer di output approssimativo al terzo buffer "pulito", è possibile cancellare il grezzo in nero. Questo ti permette di continuare a disegnare per sempre senza rallentare.

Disegnando il "pulito" sopra il "grezzo", magari in un colore leggermente diverso, avrai il meglio di entrambi i mondi.

Questo è simile a ciò che fanno i programmi di disegno - se si disegna molto velocemente, si vede una versione approssimativa, quindi il programma di pittura "pulisce" l'immagine quando ha tempo.


Alcuni commenti sul algoritmo:

ho visto un sacco di trucchi in questa arena. Ho giocato a Sonic su un emulatore Sega Genesis che esegue l'upsample. e ha alcuni algoritmi piuttosto selvaggi che funzionano molto bene e sono molto veloci.

In realtà hai alcuni vantaggi che puoi ottenere perché potresti conoscere la luminosità e il raggio sul punto.

Si potrebbe semplicemente osservare ciascun pixel e i suoi 8 vicini di casa e lasciare che quei 9 pixel "votino" in base alla loro luminosità per dove si trova il subpixel.


Altri pensieri

La tua mano non è che precisa quando si controlla un puntatore laser. Prova a ottenere tutti i punti ogni 10 fotogrammi o giù di lì, identificando quali fasci sono quali (in base al movimento precedente e tenendo conto di nuovi punti, laser disattivati ​​e punti che sono entrati o lasciati nel campo visivo), quindi semplicemente disegnando un alto curva di risoluzione. Non preoccuparti del sub pixel nell'input: basta disegnare la curva nell'output ad alta risoluzione.

Utilizzare una spline Catmull-Rom, che attraversa tutti i punti di controllo.

+0

Mi piace questa idea, ha perfettamente senso. Quindi forse rappresentano i pixel "puliti" come strutture contenenti valori di pixel 5x5 e passano attraverso di essi in una coda su un thread separato. Tuttavia, la masterizzazione di questa coda sarebbe un'impresa enorme. Forse posso memorizzare ciascuna di queste strutture in un vertice e fare la curva spline sulla scheda video? Sto ancora cercando un modo rapido per calcolare le spline 2D 5x5. Grazie per questo suggerimento di alto livello! – bufferz

+0

Non importa quanto sia lento. Puoi ottimizzare in seguito. Basta guardare il timer e vedere quanta parte dello schermo è possibile fare ogni fotogramma. – Nosredna

Problemi correlati