Поиск линий с небольшим диапазоном углов в OpenCV - PullRequest
4 голосов
/ 10 августа 2010

Я использую преобразование Хафа в OpenCV для обнаружения линий. Однако я заранее знаю, что мне нужны только линии в очень ограниченном диапазоне углов (около 10 градусов или около того). Я делаю это в очень чувствительной к производительности настройке, поэтому я хотел бы избежать дополнительной работы, затрачиваемой на обнаружение линий под другими углами, линий, которые я знаю заранее, мне все равно.

Я мог бы извлечь источник Hough из OpenCV и просто взломать его, чтобы получить параметры min_rho и max_rho, но я бы хотел использовать менее хрупкий подход (придется вручную обновлять мой код с каждым обновлением OpenCV и т. Д.).

Какой лучший подход здесь?

Ответы [ 3 ]

3 голосов
/ 05 февраля 2011

Если вы используете вероятностное преобразование Хафа, то выходные данные будут представлены в виде cvPoint для параметров lines [0] и lines [1].Мы можем получить координаты x и y для каждой из двух точек с помощью pt1.x, pt1.y и pt2.x и pt2.y.Затем воспользуйтесь простой формулой для нахождения наклона прямой - (y2-y1) / (x2-x1).Если взять arctan (tan обратный), то получим этот угол в радианах.Затем просто отфильтруйте нужные углы по значениям для каждой полученной линии.

2 голосов
/ 03 ноября 2010

Ну, я изменил функцию icvHoughlines, чтобы перейти к определенному диапазону углов.Я уверен, что есть более чистые способы, которые играют и с распределением памяти, но я получил прирост скорости от 100 мс до 33 мс для диапазона углов от 180 до 60 градусов, поэтому я доволен этим.

Обратите внимание , что этот код также выводит значение аккумулятора.Кроме того, я вывела только 1 строку, потому что это соответствовало моим целям, но там не было никакого усиления.

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

    // find n and ang limits (in our case we want 60 to 120
    float limit_min = 60.0/180.0*PI;
    float limit_max = 120.0/180.0*PI;

    //num_steps = (limit_max - limit_min)/theta;
    int start_n = floor(limit_min/theta);
    int stop_n = floor(limit_max/theta);

    for( ang = limit_min, n = start_n; n < stop_n; 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 = start_n; n < stop_n; n++ )
                {
                    r = cvRound( j * tabCos[n] + i * tabSin[n] );
                    r += (numrho - 1) / 2;
                    accum[(n+1) * (numrho+2) + r+1]++;
                }
        }



    int max_accum = 0;
    int max_ind = 0;

    for( r = 0; r < numrho; r++ )
    {
        for( n = start_n; n < stop_n; n++ )
        {
            int base = (n+1) * (numrho+2) + r+1;
            if (accum[base] > max_accum)
            {
                max_accum = accum[base];
                max_ind = base;
            }
        }
    }   

    CvLinePolar2 line;
    scale = 1./(numrho+2);
    int idx = max_ind;
    n = cvFloor(idx*scale) - 1;
    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 );

}
0 голосов
/ 19 января 2015

Я думаю, что более естественно использовать стандартную функцию HoughLines (...), которая выдает коллекцию линий непосредственно в терминах rho и theta и выбирает из нее необходимый диапазон углов, а не пересчитывает угол из конечных точек сегмента.

...