2016-05-11 20 views
6

Ho sviluppato il robot che può essere eseguito nell'impianto di mais e guidato dai sensori della bussola ma voglio applicare la fotocamera come l'occhio del robot e utilizzare l'elaborazione dell'immagine per rilevare l'angolo di errore dell'errore.Come rilevare la direzione del robot da Immagine?

Questo è l'esempio di immagine.

immagine elaborata processed image immagine grezza raw image immagine segmentata segmented image

uso questo passo successivo

  1. Fase 1: La tecnica attuale che uso è convertire co valore lor HSV modificato da this code

  2. Fase 2: Quindi Rileverà colore selezionato che è il colore marrone o sporcizia poi raccogliere più a sinistra ea destra del colore marrone o selezionata di ciascuna riga dell'immagine in due array (un punto rosso).

  3. Fase 3: I tracciare una retta di regressione lineare 2 come un punto blu e calcolare punto di intersezione come un punto di colore rosa
  4. Fase 4: tracciare la linea verde per confrontare il punto di colore rosa con un altro immagini. Non sono sicuro di cosa fare con questa linea verde ancora
  5. Il problema è la sporcizia o il colore marrone è esistere tra la foglia di mais troppo poi faccio il mio codice di perdere un calcolo

La domanda è come filtrare il pixel marrone che si trova tra la foglia di mais o un'altra area che non si trova nel percorso del mais? Quale algoritmo o metodologia dovrei studiare o applicare in questo problema?

Edit1: Usando la risposta di Spektre e sembra meglio

Ecco il risultato dopo applico con JAVA + Boofcv

  • Fase 1: controllo della soglia o Colore segmentazione Thresholding or Color Segmentation

  • Passaggio 2: Blured (utilizzare il filtro gaussiano e mediano) Blured

  • Fase 3: trama lineare Regressione Plot Linear Regression

Ulteriori informazioni

Full Code Here

LinearRegression Class

10 example images with the same process

+0

vorrei prendere in considerazione le domande che non hanno una precisa formulazione (molte utili "visione/apprendimento" problemi simili) troppo ampia. Vorrei che ci fosse un altro sito di rete dedicato a loro, ma non riesco a trovarne uno. –

+1

un filtro mediano di dimensioni discrete, come 9x9 dovrebbe sbarazzarsi della maggior parte delle cose. potresti anche provare a combinare i filtri massimo e minimo. – Piglet

+0

@Piglet Grazie. Applico il filtro mediano come suggerimento per liberarmi di piccole particelle. Vedi il post modificato. –

risposta

3

Per la vostra immagine di origine

source

lo farei:

  1. creare maschera di roba marrone

    Basta soglia H,S e ignorare V, Hai già presente. Uso il numero intero 255 anziché il colore (Blue) per il calcolo finale.

    mask

  2. sfocatura maschera

    Questo rimuove piccoli gruppi di parti selezionate erroneamente.Dopodiché dovresti ritagliare nuovamente la maschera perché il valore della maschera sarà un po 'più piccolo di 255 a meno che tu non abbia aree completamente selezionate. Più grande è l'area, maggiore è il valore (più vicino a 255). I soglia con >=150

  3. scansione della maschera da linee orizzontali

  4. per ciascuna linea trovare il centro di gravità di tutti i pixel selezionati

    Dopo sfocatura e tresholding nuovamente la maschera utilizzata è Aqua. Calcola quindi la coordinata del punto medio x di tutti i pixel mascherati in ogni riga. Questo punto è contrassegnato con White.

  5. linea di regresso attraverso tutti i centri di gravità

    Io uso il mio approximation search per questo, ma è possibile utilizzare qualsiasi regressione che si vuole. La linea regredito è contrassegnata con Red

    ho usato l'equazione linea x=x0+y*dx dove y=<0,pic1.ys>. E cercare la soluzione su intervalli:

    x0=<-pic1.xs,+2*pic1.xs> 
    dx=<-10,+10> 
    

Dove pic1.xs,pic1.ys è la risoluzione dell'immagine. Quindi, come puoi vedere, non copro tutti gli angoli, ma penso che non funzionerebbe comunque su questi casi limite (vicino alle direzioni orizzontali). In questi casi, dovresti farlo sulle linee verticali e usare invece x=y0+x*dy.

final result

Qui C++ fonte ho fatto questo con:

picture pic0,pic1; 
     // pic0 - source img 
     // pic1 - output img 
    int x,y,h,s,v,px,pn,*p; 
    color c; 
    // copy source image to output 
    pic1=pic0; 
    pic1.save("cornbot0.png"); 
    // create brown stuff mask 
    for (y=0;y<pic1.ys;y++)    // scan all H lines 
    for (x=0;x<pic1.xs;x++)   // scan actual H line 
     { 
     c=pic1.p[y][x];     // get pixel color 
     rgb2hsv(c);      // in HSV 
     h=WORD(c.db[picture::_h]); 
     s=WORD(c.db[picture::_s]); 
     v=WORD(c.db[picture::_v]); 
     // Treshold brownish stuff 
     if ((abs(h- 20)<10)&&(abs(s-200)<50)) c.dd=255; else c.dd=0; 
     pic1.p[y][x]=c; 
     } 
    pic1.save("cornbot1.png"); 
    pic1.smooth(10);     // blur a bit to remove small clusters as marked 
    pic1.save("cornbot2.png"); 

    // compute centers of gravity 
    p=new int[pic1.ys];     // make space for points 
    for (y=0;y<pic1.ys;y++)    // scan all H lines 
     { 
     px=0; pn=0;      // init center of gravity (avg point) variables 
     for (x=0;x<pic1.xs;x++)   // scan actual H line 
     if (pic1.p[y][x].dd>=150)  // use marked points only 
      { 
      px+=x; pn++;    // add it to avg point 
      pic1.p[y][x].dd=0x00004080; // mark used points (after smooth) with Aqua 
      } 
     if (pn)       // finish avg point computation 
      { 
      px/=pn; 
      pic1.p[y][px].dd=0x00FFFFFF;// mark it by White 
      p[y]=px;     // store result for line regression 
      } else p[y]=-1;    // uncomputed value 
     } 

    // regress line 
    approx x0,dx; 
    double ee; 
    for (x0.init(-pic1.xs,pic1.xs<<1,100,3,&ee); !x0.done; x0.step()) // search x0 
    for (dx.init(-10.0 ,+10.0  ,1.0,3,&ee); !dx.done; dx.step()) // search dx 
     for (ee=0.0,y=0;y<pic1.ys;y++)         // compute actua solution distance to dataset 
     if (p[y]!=-1)             // ignore uncomputed values (no brown stuff) 
     ee+=fabs(double(p[y])-x0.a-(double(y)*dx.a)); 
    // render regressed line with Red 
    for (y=0;y<pic1.ys;y++) 
    { 
    x=double(x0.aa+(double(y)*dx.aa)); 
    if ((x>=0)&&(x<pic1.xs)) 
    pic1.p[y][x].dd=0x00FF0000; 
    } 
    pic1.save("cornbot2.png"); 
    delete[] p; 

io uso il mio picture classe per le immagini in modo da alcuni membri sono:

  • xs,ys dimensioni immagine in pixel
  • p[y][x].dd è pixel alla (x,y) posizione di 32 bit tipo intero
  • p[y][x].dw[2] è pixel alla (x,y) posizione 2x16 bit tipo integer per 2D campi
  • p[y][x].db[4] è pixel alla (x,y) posizione del tipo di bit 4x8 intero per un facile accesso al canale
  • clear(color) - cancella intera immagine
  • resize(xs,ys) - ridimensiona un'immagine per nuova risoluzione
  • bmp - VCL incapsulato GDI bitmap con accesso Canvas
  • smooth(n) - veloce sfocatura dell'immagine n volte

È possibile migliorare ulteriormente questo con la segmentazione (rimozione di piccoli gruppi) sulla base di area e la posizione. Inoltre puoi ignorare i picchi troppo alti nei punti AVG tra vicini. Inoltre è possibile rilevare il cielo e ignorare l'intera area in cui è presente il cielo.

[edit1] liscio

Questo è come il mio aspetto liscio come:

void picture::smooth(int n) 
    { 
    color *q0,*q1; 
    int  x,y,i,c0[4],c1[4],c2[4]; 
    bool _signed; 
    if ((xs<2)||(ys<2)) return; 
    for (;n>0;n--) 
     { 
     #define loop_beg for (y=0;y<ys-1;y++){ q0=p[y]; q1=p[y+1]; for (x=0;x<xs-1;x++) { dec_color(c0,q0[x],pf); dec_color(c1,q0[x+1],pf); dec_color(c2,q1[x],pf); 
     #define loop_end enc_color(c0,q0[x ],pf); }} 
     if (pf==_pf_rgba) loop_beg for (i=0;i<4;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])>>2; clamp_u8(c0[i]); } loop_end 
     if (pf==_pf_s ) loop_beg     { c0[0]=(c0[0]+c0[0]+c1[0]+c2[0])/ 4; clamp_s32(c0[0]); } loop_end 
     if (pf==_pf_u ) loop_beg     { c0[0]=(c0[0]+c0[0]+c1[0]+c2[0])>>2; clamp_u32(c0[0]); } loop_end 
     if (pf==_pf_ss ) loop_beg for (i=0;i<2;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])/ 4; clamp_s16(c0[i]); } loop_end 
     if (pf==_pf_uu ) loop_beg for (i=0;i<2;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])>>2; clamp_u16(c0[i]); } loop_end 
     #undef loop_beg 
     #define loop_beg for (y=ys-1;y>0;y--){ q0=p[y]; q1=p[y-1]; for (x=xs-1;x>0;x--) { dec_color(c0,q0[x],pf); dec_color(c1,q0[x-1],pf); dec_color(c2,q1[x],pf); 
     if (pf==_pf_rgba) loop_beg for (i=0;i<4;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])>>2; clamp_u8(c0[i]); } loop_end 
     if (pf==_pf_s ) loop_beg     { c0[0]=(c0[0]+c0[0]+c1[0]+c2[0])/ 4; clamp_s32(c0[0]); } loop_end 
     if (pf==_pf_u ) loop_beg     { c0[0]=(c0[0]+c0[0]+c1[0]+c2[0])>>2; clamp_u32(c0[0]); } loop_end 
     if (pf==_pf_ss ) loop_beg for (i=0;i<2;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])/ 4; clamp_s16(c0[i]); } loop_end 
     if (pf==_pf_uu ) loop_beg for (i=0;i<2;i++) { c0[i]=(c0[i]+c0[i]+c1[i]+c2[i])>>2; clamp_u16(c0[i]); } loop_end 
     #undef loop_beg 
     #undef loop_end 
     } 
    } 

Semplicemente peso medio 3 pixel

(x,y)=(2*(x,y)+(x-1,y)+(x,y-1))/4 

e dopo che fanno lo stesso con

(x,y)=(2*(x,y)+(x+1,y)+(x,y+1))/4 

per evitare lo spostamento dell'immagine. Quindi tutta questa faccenda è ripetuta n volte e questo è tutto. Puoi ignorare la pinza e le opzioni in formato pixel in questo caso è pf==_pf_rgba ma usa comunque solo un canale ...dec_color,enc_color è sufficiente decomprimere, raggruppare i canali di colore in/da array di variabili per evitare problemi di troncamento e overflow su canali a 8 bit e anche per formattare/semplificare il codice un po 'meglio (per supporto di diversi formati pixel)

btw base liscia è il stessa di convoluzione con

0.00 0.25 0.00 
0.25 0.50 0.00 
0.00 0.00 0.00 

e

0.00 0.00 0.00 
0.00 0.50 0.25 
0.00 0.25 0.00 
+0

Quale tipo di algoritmo (o libreria) usi per smooth()? –

+0

@SarinSuriyakoon aggiunto edit1 con informazioni regolari e codice – Spektre

+0

Applico la maggior parte dei tuoi suggerimenti e funziona bene come post modificato. –

0

se ho ragione che stai chiedendo circa le porzioni brune che si vedono fuori strada o in altre parti del fondo?

Come hai ottenuto quell'ultima immagine? Immagino tu abbia moltiplicato l'immagine originale con una maschera? Anche se non lo facessi, puoi semplicemente ottenere la maschera dall'immagine selezionando ovunque l'immagine esista (qualsiasi soglia semplice, molto bassa farebbe). (Applica soglie adattive, una versione ancora più precisa dell'originale per ottenere una maschera migliore)

Prendi la maschera e puliscila usando le operazioni morfologiche, nel tuo caso sarebbe sufficiente la chiusura. La morfologia è composta da una pletora di operazioni che possono darti una maschera d'immagine estremamente pulita. Leggi su di loro.