OpenCV: get Hough accumulator value?

Ok, so looking at the cvhough.cpp file, the structure CvLinePolar is only defined by rho and angle.

This is all that is passed back as a result of our call to HoughLines. I am in the process of modifying the c++ file and see if i can get the votes out.

Update oct 26: just realized these are not really answers but more like questions. apparently frowned upon. I found some instructions on recompiling OpenCV. I guess we'll have to go in the code and modify it and recompile. How to install OpenCV 2.0 on win32

update Oct 27: well, i failed at compiling the dlls for OpenCV with my new code so I ended up copy-pasting the specific parts I want to modify into my own files. I like to add new functions so to avoid overloading the already defined functions. There are 4 main things you need to copy over: 1- some random defines

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

2- redefining the struct for line parameters

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

3- the main function that was modified

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- the function that calls that function

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

And i guess you could uninstall opencv so it takes off all those automatic path setting and recompile it yourself using the CMake method and then the OpenCV is really whatever you make it.


Although this is an old question, I had the same problem, so I might as well put up my solution. The threshold in houghlines() returns 1 for any point that cleared the threshold for votes. The solution is to run houghlines() for every threshold value (until there are no more votes) and add up the votes in another array. In python (maybe with other languages too) when you have no more votes, it throws an error, so use try/except.

Here is an example in python. The array I used was for rho values of -199 to 200 with a max vote of less than 100. You can play around with those constants to suit your needs. You may need to add a line to convert the source image to grayscale.

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()

Tags:

Opencv