OpenCV: get Hough accumulator value?

前端 未结 2 2054
野性不改
野性不改 2020-12-30 08:33

Is it possible to get the accumulator value along with rho and theta from a Hough transform?

I ask because I\'d like to differentiate betwe

相关标签:
2条回答
  • 2020-12-30 08:49

    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()
    
    0 讨论(0)
  • 2020-12-30 08:56

    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.

    0 讨论(0)
提交回复
热议问题