2010-07-16 31 views
8

¿Es posible obtener el valor del acumulador junto con rho y theta de una transformada Hough?OpenCV: ¿obtiene el valor del acumulador Hough?

Lo pregunto porque me gustaría diferenciar entre las líneas que están "bien definidas" (es decir, que tienen un alto valor de acumulación) y las líneas que no están tan bien definidas.

Gracias!

+1

Me pregunto por qué esta funcionalidad no está en la biblioteca OpenCV –

Respuesta

13

Ok, así que mirando el archivo cvhough.cpp, la estructura CvLinePolar solo se define por rho y ángulo.

Esto es todo lo que se devuelve como resultado de nuestra llamada a HoughLines. Estoy en el proceso de modificar el archivo C++ y ver si puedo obtener los votos.

Actualización oct 26: me acabo de dar cuenta de que estas no son realmente respuestas, sino más como preguntas. aparentemente mal visto. Encontré algunas instrucciones para recompilar OpenCV. Supongo que tendremos que ir al código y modificarlo y volver a compilarlo. How to install OpenCV 2.0 on win32

actualización 27 de octubre: bueno, no pude compilar las DLL para OpenCV con mi nuevo código, así que terminé copiando y pegando las partes específicas que deseo modificar en mis propios archivos. Me gusta agregar nuevas funciones para evitar sobrecargar las funciones ya definidas. Hay 4 cosas principales que usted necesita copiar: 1- algunas define al azar

#define hough_cmp_gt(l1,l2) (aux[l1] > aux[l2]) 
static CV_IMPLEMENT_QSORT_EX(icvHoughSortDescent32s, int, hough_cmp_gt, const int*) 

2- redefinición de la estructura de la línea de parámetros

typedef struct CvLinePolar2 
{ 
    float rho; 
    float angle; 
    float votes; 
} 
CvLinePolar2; 

3- la función principal que se ha modificado

static void 
icvHoughLinesStandard2(const CvMat* img, float rho, float theta, 
         int threshold, CvSeq *lines, int linesMax) 
{ 
    cv::AutoBuffer<int> _accum, _sort_buf; 
    cv::AutoBuffer<float> _tabSin, _tabCos; 

    const uchar* image; 
    int step, width, height; 
    int numangle, numrho; 
    int total = 0; 
    float ang; 
    int r, n; 
    int i, j; 
    float irho = 1/rho; 
    double scale; 

    CV_Assert(CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1); 

    image = img->data.ptr; 
    step = img->step; 
    width = img->cols; 
    height = img->rows; 

    numangle = cvRound(CV_PI/theta); 
    numrho = cvRound(((width + height) * 2 + 1)/rho); 

    _accum.allocate((numangle+2) * (numrho+2)); 
    _sort_buf.allocate(numangle * numrho); 
    _tabSin.allocate(numangle); 
    _tabCos.allocate(numangle); 
    int *accum = _accum, *sort_buf = _sort_buf; 
    float *tabSin = _tabSin, *tabCos = _tabCos; 

    memset(accum, 0, sizeof(accum[0]) * (numangle+2) * (numrho+2)); 

    for(ang = 0, n = 0; n < numangle; ang += theta, n++) 
    { 
     tabSin[n] = (float)(sin(ang) * irho); 
     tabCos[n] = (float)(cos(ang) * irho); 
    } 

    // stage 1. fill accumulator 
    for(i = 0; i < height; i++) 
     for(j = 0; j < width; j++) 
     { 
      if(image[i * step + j] != 0) 
       for(n = 0; n < numangle; n++) 
       { 
        r = cvRound(j * tabCos[n] + i * tabSin[n]); 
        r += (numrho - 1)/2; 
        accum[(n+1) * (numrho+2) + r+1]++; 
       } 
     } 

    // stage 2. find local maximums 
    for(r = 0; r < numrho; r++) 
     for(n = 0; n < numangle; n++) 
     { 
      int base = (n+1) * (numrho+2) + r+1; 
      if(accum[base] > threshold && 
       accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] && 
       accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2]) 
       sort_buf[total++] = base; 
     } 

    // stage 3. sort the detected lines by accumulator value 
    icvHoughSortDescent32s(sort_buf, total, accum); 

    // stage 4. store the first min(total,linesMax) lines to the output buffer 
    linesMax = MIN(linesMax, total); 
    scale = 1./(numrho+2); 
    for(i = 0; i < linesMax; i++) 
    { 
     CvLinePolar2 line; 
     int idx = sort_buf[i]; 
     int n = cvFloor(idx*scale) - 1; 
     int r = idx - (n+1)*(numrho+2) - 1; 
     line.rho = (r - (numrho - 1)*0.5f) * rho; 
     line.angle = n * theta; 
     line.votes = accum[idx]; 
     cvSeqPush(lines, &line); 
    } 

    cvFree((void**)&sort_buf); 
    cvFree((void**)&accum); 
    cvFree((void**)&tabSin); 
    cvFree((void**)&tabCos); 

} 

4- la función que llama a esa función

CV_IMPL CvSeq* 
cvHoughLines3(CvArr* src_image, void* lineStorage, int method, 
       double rho, double theta, int threshold, 
       double param1, double param2) 
{ 
    CvSeq* result = 0; 

    CvMat stub, *img = (CvMat*)src_image; 
    CvMat* mat = 0; 
    CvSeq* lines = 0; 
    CvSeq lines_header; 
    CvSeqBlock lines_block; 
    int lineType, elemSize; 
    int linesMax = INT_MAX; 
    int iparam1, iparam2; 

    img = cvGetMat(img, &stub); 

    if(!CV_IS_MASK_ARR(img)) 
     CV_Error(CV_StsBadArg, "The source image must be 8-bit, single-channel"); 

    if(!lineStorage) 
     CV_Error(CV_StsNullPtr, "NULL destination"); 

    if(rho <= 0 || theta <= 0 || threshold <= 0) 
     CV_Error(CV_StsOutOfRange, "rho, theta and threshold must be positive"); 

    if(method != CV_HOUGH_PROBABILISTIC) 
    { 
     lineType = CV_32FC3; 
     elemSize = sizeof(float)*3; 
    } 
    else 
    { 
     lineType = CV_32SC4; 
     elemSize = sizeof(int)*4; 
    } 

    if(CV_IS_STORAGE(lineStorage)) 
    { 
     lines = cvCreateSeq(lineType, sizeof(CvSeq), elemSize, (CvMemStorage*)lineStorage); 
    } 
    else if(CV_IS_MAT(lineStorage)) 
    { 
     mat = (CvMat*)lineStorage; 

     if(!CV_IS_MAT_CONT(mat->type) || (mat->rows != 1 && mat->cols != 1)) 
      CV_Error(CV_StsBadArg, 
      "The destination matrix should be continuous and have a single row or a single column"); 

     if(CV_MAT_TYPE(mat->type) != lineType) 
      CV_Error(CV_StsBadArg, 
      "The destination matrix data type is inappropriate, see the manual"); 

     lines = cvMakeSeqHeaderForArray(lineType, sizeof(CvSeq), elemSize, mat->data.ptr, 
             mat->rows + mat->cols - 1, &lines_header, &lines_block); 
     linesMax = lines->total; 
     cvClearSeq(lines); 
    } 
    else 
     CV_Error(CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*"); 

    iparam1 = cvRound(param1); 
    iparam2 = cvRound(param2); 

    switch(method) 
    { 
    case CV_HOUGH_STANDARD: 
      icvHoughLinesStandard2(img, (float)rho, 
       (float)theta, threshold, lines, linesMax); 
      break; 

    default: 
     CV_Error(CV_StsBadArg, "Unrecognized method id"); 
    } 

    if(mat) 
    { 
     if(mat->cols > mat->rows) 
      mat->cols = lines->total; 
     else 
      mat->rows = lines->total; 
    } 
    else 
     result = lines; 

    return result; 
} 

Y supongo que podría desinstalar opencv para que elimine todas esas configuraciones automáticas de ruta y recompilarlo usted mismo usando el método CMake y luego el OpenCV es realmente lo que sea que haga.

+1

jaja, eso es bastante dulce. No creo que pueda usarlo, pero espero que alguien lo haga. –

2

Aunque esta es una vieja pregunta, tuve el mismo problema, así que bien podría poner mi solución. El umbral en houghlines() devuelve 1 para cualquier punto que eliminó el umbral de votos. La solución es ejecutar houghlines() para cada valor de umbral (hasta que no haya más votos) y sumar los votos en otra matriz. En python (tal vez con otros idiomas también) cuando no tienes más votos, arroja un error, así que usa try/except.

Aquí hay un ejemplo en python. La matriz que utilicé fue para valores rho de -199 a 200 con un voto máximo de menos de 100. Puede jugar con esas constantes para satisfacer sus necesidades. Es posible que deba agregar una línea para convertir la imagen de origen a escala de grises.

import matplotlib.pyplot as plt 

import cv2 

import math 



############ make houghspace array ############ 

houghspace = [] 

c = 0 

height = 400 

while c <= height: 

    houghspace.append([]) 

    cc = 0 

    while cc <= 180: 

     houghspace[c].append(0) 

     cc += 1 

    c+=1 



############ do transform ############ 


degree_tick = 1 #by how many degrees to check 

total_votes = 1 #votes counter 

highest_vote = 0 #highest vote in the array 



while total_votes < 100: 

    img = cv2.imread('source.pgm') 

    edges = cv2.Canny(img,50,150,apertureSize = 3) 

    lines = cv2.HoughLines(edges,1,math.pi*degree_tick/180,total_votes) 



    try: 

     for rho,theta in lines[0]: 





      a = math.cos(theta) 

      b = math.sin(theta) 

      x1 = int((a*rho) + 1000*(-b)) 

      y1 = int((b*rho) + 1000*(a)) 

      x2 = int((a*rho) - 1000*(-b)) 

      y2 = int((b*rho) - 1000*(a)) 

      cv2.line(img,(x1,y1),(x2,y2),(50,200,255),2) 

     #################add votes into the array################ 

     deradian = 180/math.pi #used to convert to degrees 

     for rho,theta in lines[0]: 

      degree = int(round(theta*deradian)) 

      rho_pos = int(rho - 200) 

      houghspace[rho_pos][degree] += 1 
    #when lines[0] has no votes, it throws an error which is caught here 

    except:  

     total_votes = 999 #exit loop 


    highest_vote = total_votes 

    total_votes += 1 
    del lines 



########### loop finished ############################### 
print highest_vote 



############################################################# 

################### plot the houghspace ################### 


maxy = 200 #used to offset the y-axis 

miny = -200 #used to offset the y-axis 

#the main graph 

fig = plt.figure(figsize=(10, 5)) 

ax = fig.add_subplot(111) 

ax.set_title('Houghspace') 

plt.imshow(houghspace, cmap='gist_stern') 

ax.set_aspect('equal') 

plt.yticks([0,-miny,maxy-miny], [miny,0,maxy]) 

#the legend 
cax = fig.add_axes([0, 0.1, 0.78, 0.8]) 

cax.get_xaxis().set_visible(False) 

cax.get_yaxis().set_visible(False) 

cax.patch.set_alpha(0) 

cax.set_frame_on(False) 

plt.colorbar(orientation='vertical') 

#plot 

plt.show() 
+1

No votaría por esta solución porque crea una gran sobrecarga de cómputo. Además, los bucles de salida con excepciones son una mala práctica, las excepciones son muy caras y se inventaron para otros fines. –

Cuestiones relacionadas