2016-05-11 1 views
6

J'ai développé le robot qui peut fonctionner dans la plante de maïs et guidé par des capteurs de boussole mais je veux appliquer la caméra comme l'œil du robot et utiliser le traitement d'image pour détecter l'angle de déplacement.Comment détecter la direction du robot à partir de l'image?

Voici les exemples d'images.

image traitée processed image image brute raw image image segmentée segmented image

J'utilise cette étape suivante

  1. Etape 1: La technique actuelle que j'utilise est convertir co Étape 2: Donc, il va détecter la couleur sélectionnée qui est la couleur brune ou de la saleté puis je recueille le plus à gauche et à droite de la couleur brune ou sélectionnée de chaque rangée d'image en deux tableaux (un point rouge).

  2. Etape 3: I 2 tracer une droite de régression linéaire en tant que point bleu et calcule le point d'intersection comme point rose
  3. Etape 4: tracer la ligne verte pour comparer le point rose avec une autre image. Je ne sais pas quoi faire avec cette ligne verte encore
  4. Le problème est la saleté ou la couleur brune est existe entre la feuille de maïs aussi je fais mon code pour manquer un calcul

La question est de savoir comment filtrer le pixel brun qui se trouve entre la feuille de maïs ou une autre zone qui n'est pas dans le chemin du maïs? Quel algorithme ou méthodologie dois-je étudier ou appliquer dans ce problème?

EDIT1: En utilisant la réponse de Spektre et il semble mieux

Voici le résultat après que je l'applique avec JAVA + Boofcv

  • Étape 1: Thresholding ou couleur Segmentation Thresholding or Color Segmentation

  • Étape 2: Blured (utiliser le filtre gaussien et médian) Blured

  • Étape 3: Terrain de régression linéaire Plot Linear Regression

Plus d'informations

Full Code Here

LinearRegression Class

10 example images with the same process

+0

Je considérerais des questions qui n'ont pas une formulation précise (de nombreux problèmes de vision "/ apprentissage" utiles comme) trop large. Je souhaite qu'il y ait un autre site de réseau dédié à eux, mais je ne peux pas en trouver un. –

+1

un filtre médian de taille décente, comme 9x9 devrait se débarrasser de la plupart des choses. vous pouvez également essayer de combiner les filtres maximum et minimum. – Piglet

+0

@Piglet Merci. J'applique le filtre médian comme suggestion pour me débarrasser des petites particules. Voir le post édité. –

Répondre

3

Pour votre image source

source

Je voudrais:

  1. créer un masque de choses brun

    Juste SEUIL H,S et ignorer V, vous avez déjà. J'utilise un entier 255 au lieu de couleur (Bleu) pour le dernier calcul.

    mask

  2. le masque flou

    Cela permettra d'éliminer les petits groupes de parties mal choisies.Après cela, vous devez à nouveau vérifier le masque car la valeur du masque sera un peu plus petite que 255 sauf si vous avez des zones entièrement sélectionnées. Plus la zone est grande, plus la valeur est grande (plus proche de 255). Je TRESHOLD avec >=150

  3. balayer le masque par des lignes horizontales

  4. pour chaque ligne trouver le centre de gravité de l'ensemble des pixels sélectionnés

    Après flou et seuillage à nouveau le masque utilisé est Aqua. Donc, calculer le point moyen x coordonnée de tous les pixels masqués dans chaque ligne. Ce point est marqué Blanc.

  5. ligne de régression dans tous les centres de gravité

    J'utilise le mien approximation search pour cela, mais vous pouvez utiliser une régression que vous voulez. La ligne est marquée par une régression Red

    je équation de la ligne x=x0+y*dxy=<0,pic1.ys>. Et chercher la solution sur des intervalles:

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

pic1.xs,pic1.ys est la résolution d'image. Donc, comme vous pouvez le voir, je ne couvre pas toute la gamme des angles, mais je pense que cela ne fonctionnerait pas sur ces bords de toute façon (directions horizontales proches). Pour de tels cas, vous devriez le faire sur les lignes verticales à la place et utiliser x=y0+x*dy à la place.

final result

ici source de C++ Je l'ai fait avec:

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; 

-je utiliser ma propre picture classe pour les images si certains membres sont:

  • xs,ys taille image en pixels
  • p[y][x].dd est pixel à (x,y) position de 32 bit type entier
  • p[y][x].dw[2] est pixel à (x,y) position 2x16 type entier de bits pour 2D champs
  • p[y][x].db[4] est pixel à (x,y) position de type entier de bits de 4x8 pour faciliter l'accès de canal
  • clear(color) - efface toute l'image
  • resize(xs,ys) - redimensionne image nouvelle résolution
  • bmp - VCL encapsulé GDI Bitmap avec accès toile
  • smooth(n) - flou rapide l'image n fois

Vous pouvez améliorer encore cette segmentation (suppression de petits groupes) en fonction de la zone et la position. Vous pouvez également ignorer les pics trop importants dans les points avg entre voisins. Vous pouvez également détecter le ciel et ignorer toute la zone où le ciel est présent.

[edit1] lisse

Voici comment mon apparence lisse comme:

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 
     } 
    } 

Il pondèrent simplement 3 pixels moyenne

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

et après que faire la même chose avec

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

pour éviter le décalage de l'image. Ensuite, toute cette chose est bouclée n fois et c'est tout. Vous pouvez ignorer les options de pince et de format de pixel dans ce cas, il est pf==_pf_rgba mais il n'utilise qu'un seul canal de toute façon ...dec_color,enc_color il suffit de déballer, de pack de couleurs dans/de tableau de variables pour éviter les problèmes de troncature et de débordement sur les canaux 8 bits et également pour formater/simplifier le code un peu mieux (pour différents formats de pixels). même que convolution avec

0.00 0.25 0.00 
0.25 0.50 0.00 
0.00 0.00 0.00 

et

0.00 0.00 0.00 
0.00 0.50 0.25 
0.00 0.25 0.00 
+0

Quel type d'algorithme utilisez-vous (ou bibliothèque) pour smooth()? –

+0

@SarinSuriyakoon ajouté edit1 avec des informations lisses et le code – Spektre

+0

J'applique la plupart de votre suggestion et cela fonctionne bien comme post édité. –

0

Si je ne me trompe, vous vous posez sur les parties brunes qui sont vues en erreur ou dans d'autres parties de l'arrière-plan?

Comment avez-vous obtenu cette dernière image? Je suppose que vous avez multiplié l'image originale par un masque? Même si vous n'avez pas, vous pouvez simplement obtenir le masque de l'image en sélectionnant où l'image existe (tout seuil simple, très bas ferait l'affaire). (Appliquer le seuillage adaptatif, une version encore plus précise de l'original pour obtenir un meilleur masque)

Prenez ce masque et nettoyez-le en utilisant des opérations morphologiques, dans votre cas la fermeture suffirait. La morphologie est constituée d'une multitude d'opérations qui peuvent vous donner un masque d'image extrêmement propre. Lisez sur eux.