Finding strings with a small range of angles in OpenCV

I use Hough's conversion to OpenCV to detect strings. However, I know in advance that I only need lines in a very limited range of angles (about 10 degrees or so). I do this in a very performance-sensitive setting, so I would like to avoid the extra work spent on detecting lines at different angles, the lines that I know in advance, I don't care.

I could extract the Hough source from OpenCV and just hack it to accept the min_rho and max_rho parameters, but I need a less fragile approach (I need to manually update the code with every OpenCV update, etc.).

What is the best approach here?

+4
source share
3 answers

Well, I changed the icvHoughlines function to go to a specific range of angles. I'm sure there are cleaner methods that also play with memory allocation, but I got a gain from 100 ms to 33 ms for an angle range of 180 to 60 degrees, so I'm happy with that.

Note that this code also displays the battery value. In addition, I only output 1 line, because it was consistent with my goals, but there was no gain.

 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 ); } 
+1
source

If you use the Probabilistic Hough transformation, the output will be in the form of cvPoint for lines [0] and lines [1]. We can get the x and y coordinates for each of the two points via pt1.x, pt1.y and pt2.x and pt2.y. Then use a simple formula to find the slope of the line - (y2-y1) / (x2-x1). Taking arctan (tan inverse) from this will give this angle in radians. Then simply filter out the required angles from the values ​​for each resulting hough line.

+3
source

I think it is more natural to use the standard function HoughLines (...), which gives a set of lines directly in terms of rho and theta and selects the necessary range of angles from it, rather than recalculating the angle from the end points of the segment.

0
source

All Articles