【问题标题】:OpenCV: get Hough accumulator value?OpenCV:获取霍夫累加器值?
【发布时间】:2010-07-16 14:40:37
【问题描述】:

是否可以通过霍夫变换获得累加器值以及 rhotheta

我问是因为我想区分“定义明确”的行(即具有高累加器值的行)和定义不明确的行。

谢谢!

【问题讨论】:

  • 我想知道为什么 OpenCV 库中没有这个功能
  • 只是一个更新给所有仍然解决这个问题的人:已添加沿 rho 和 theta 检索累加器值的选项,请参阅github.com/opencv/opencv/issues/4303

标签: opencv


【解决方案1】:

好的,所以查看cvhough.cpp文件,结构CvLinePolar只有rho和angle定义。

这是我们调用 HoughLines 后传回的全部内容。我正在修改c++文件,看看能不能把票拿出来。

10 月 26 日更新:刚刚意识到这些并不是真正的答案,而更像是问题。显然不屑一顾。我找到了一些关于重新编译 OpenCV 的说明。我想我们必须进入代码并修改它并重新编译。 How to install OpenCV 2.0 on win32

10 月 27 日更新:好吧,我无法用我的新代码为 OpenCV 编译 dll,所以我最终将我想要修改的特定部分复制粘贴到我自己的文件中。 我喜欢添加新函数以避免重载已经定义的函数。 您需要复制以下 4 项主要内容: 1- 一些随机定义

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

2- 重新定义行参数的结构

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

3-修改的主要功能

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- 调用该函数的函数

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

我猜你可以卸载 opencv,这样它就可以取消所有那些自动路径设置并使用 CMake 方法自己重新编译它,然后 OpenCV 真的是你所做的。

【讨论】:

  • 哈哈,太甜了。我不认为我可以使用它,但希望有人会。
【解决方案2】:

虽然这是一个老问题,但我也遇到了同样的问题,所以我不妨提出我的解决方案。 houghlines() 中的阈值对于清除投票阈值的任何点返回 1。解决方案是为每个阈值运行 houghlines() (直到没有更多选票)并将选票添加到另一个数组中。在python中(可能还有其他语言)当你没有更多的票时,它会抛出一个错误,所以使用try/except。

这里是python中的一个例子。我使用的数组用于 rho 值 -199 到 200,最大投票数小于 100。您可以使用这些常量来满足您的需要。您可能需要添加一条线来将源图像转换为灰度。

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

【讨论】:

  • 我不会投票支持这个解决方案,因为它会产生巨大的计算开销。此外,带有异常的退出循环是不好的做法 - 异常非常昂贵,而且它们是为其他目的而发明的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-12
  • 2012-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多