2010-10-18 12 views
6

Tengo una imagen donde quiero encontrar contornos pero los "contornos" en mi imagen no tienen esquinas. ¿Hay algunos trucos que pueda usar para ayudar a encontrar los rectángulos que están implicados en las líneas de esta imagen? Pensé en extender todas las líneas para formar las esquinas, pero me preocupan las líneas que se cruzan desde otros contornos y cómo determinar en qué intersecciones estoy interesado. Soy muy nuevo en opencv y no sé mucho sobre el procesamiento de imágenes. Gracias por cualquier ayuda que pueda dar. alt textBuscar rectángulos sin esquinas usando opencv

Respuesta

4

Terminé implementando mi propia solución. No es muy elegante, pero hace el trabajo bien. Me interesaría saber acerca de las mejoras. HoughLines2 no siempre me dio buenos resultados para encontrar segmentos de línea y tuve que meterme mucho con el valor de umbral para diferentes escenarios. En cambio, opté por FindCountours, donde tomé contornos con dos elementos, se me debería garantizar líneas de 1 píxel de ancho. Después de encontrar las líneas, las repetí y las tracé para encontrar los rectángulos.

Dónde puntos es un CvSeq * de la línea de puntos finales

while(points->total>0){ 
    if(p1.x==-1&&p1.y==-1){ 
    cvSeqPopFront(points,&p1); 
    cvSeqPopFront(points,&p2); 
    } 

    if((pos=findClosestPoint(&p1,&p2, points,maxDist))>=0){ 
    p3 = (CvPoint*)cvGetSeqElem(points,pos); 
    pos2 = (pos%2==0)?pos+1:pos-1; //lines are in pairs of points 
    p4 = (CvPoint*)cvGetSeqElem(points,pos2); 

    if(isVertical(&p1,&p2) && isHorizontal(p3,p4)){ 
     printf("found Corner %d %d\n",p2.x,p3->y); 
    } else if(isHorizontal(&p1,&p2) && isVertical(p3,p4)){ 
     printf("found Corner %d %d\n",p3->x,p2.y); 
    } 

    memcpy(&p1,p3,sizeof(CvPoint)); 
    memcpy(&p2,p4,sizeof(CvPoint)); 
    cvSeqRemove(points, (pos>pos2)?pos:pos2); 
    cvSeqRemove(points, (pos>pos2)?pos2:pos); 
    } else { 
    p1.x=-1; 
    p1.y=-1; 
    } 
} 

int findClosestPoint (CvPoint *p1, CvPoint *p2, CvSeq *points, int maxDist) { 
    int ret = -1,i; 
    float dist, minDist = maxDist; 
    CvPoint* test; 
    int (*dirTest)(CvPoint *,CvPoint *); 

    if(isVertical(p1,p2)){ //vertical line 
     if(p2->y > p1->y) {//going down 
     dirTest = isBelow; 
     } else { // going up 
     dirTest = isAbove; 
     } 
    } else if (isHorizontal(p1,p2)){ //horizontal line 
     if(p2->x > p1->x) {//going right 
     dirTest = isRight; 
     } else { //going left 
     dirTest = isLeft; 
     } 
    } 

    for(i = 0; i < points->total; i++) 
    { 
     test = (CvPoint*)cvGetSeqElem(points, i); 
     if(dirTest(p2,test)){ //only test points in the region we care about 
     dist = sqrt(pow(test->x - p2->x,2)+pow(test->y - p2->y,2)); 
     if(dist<minDist){ 
      minDist = dist; 
      ret = i; 
     } 
     } 
    } 
    return ret; 
} 

int isVertical(CvPoint *p1, CvPoint *p2){ 
    return p1->x == p2->x; 
} 
int isHorizontal(CvPoint *p1, CvPoint *p2){ 
    return p1->y == p2->y; 
} 
int isRight(CvPoint *pt1, CvPoint *pt2){ 
    return pt2->x > pt1->x; 
} 
int isLeft(CvPoint *pt1, CvPoint *pt2){ 
    return pt2->x < pt1->x; 
} 
int isBelow(CvPoint *pt1, CvPoint *pt2){ 
    return pt2->y > pt1->y; 
} 
int isAbove(CvPoint *pt1, CvPoint *pt2){ 
    return pt2->y < pt1->y; 
} 
+0

¿Cómo funciona esto? Supongo que encuentra el punto más cercano y los vincula. Y utilizando las funciones isVertical/etc, comprueba si es una línea vertical o no. –

+0

Básicamente, recorro las líneas encontradas por FindContours. Para la primera línea, determino su dirección, así que digamos que va de izquierda a derecha. Luego busco el punto más cercano en las líneas restantes que estarían a la derecha del punto más derecho de mi primera línea. El punto más cercano será un punto final de una línea, encontraré el otro y luego determinaré la dirección de esta nueva línea. Si la nueva línea es perpendicular a mi primera línea, encontré una esquina si no es así, entonces sigo encontrando más líneas que inevitablemente estarán más a la derecha. Cuando encuentro líneas, las saco de la lista. – john

+0

En el ejemplo anterior, una vez que encuentro una línea perpendicular, me moveré en una dirección diferente. Así que puedo moverme de izquierda a derecha y luego de abajo hacia arriba donde solo encontraría puntos sobre mi línea, etc. Eventualmente findClosest ya no encontrará puntos ya que especifico una distancia máxima y me moveré a otro segmento de línea de inicio encontrado en FindContours – john

4

Ajuste las líneas en su imagen binaria con el Hough transform y ajuste los rectángulos a las líneas que se cruzan ortogonalmente.

+0

Jacob, gracias por la respuesta rápida. Estoy familiarizado con houghlines2 pero en realidad estoy usando cvFindContours para contornos con 2 puntos. Houghlines no siempre dieron buenos resultados y tuve que meterme demasiado con el umbral. Creo que el verdadero problema es adaptar los rectángulos, no pude encontrar un buen método, pero inventé algo que publicaré. – john

0

Usando el hough transform podrá extraer líneas. Luego puede calcular las intersecciones de estas líneas para estimar la posición de los rectángulos.

+0

Pensé en tomar las líneas y extenderlas y encontrar intersecciones, pero esto me deja con algunos rectángulos falsos que tendría que sacrificar. Empeoraría con más rectángulos. Hice una solución personalizada que no es muy elegante pero la publicaré. – john

1

También puede probar que presenta como problema de optimización. Rectángulo se define como vector de estado 4D (x, w, ancho, alto) o vector 5D si incluye rotación (x, y, ancho, alto, rotación). Para su estado actual, podría hacer un descenso de gradiente hacia el resultado de las líneas Hough para converger al estado óptimo. Otra opción es usar mínimos cuadrados lineales: http://people.inf.ethz.ch/arbenz/MatlabKurs/node88.html