문제

In Matlab, by combining hough transform, houghpeaks and houghlines, it is possible to show the detected lines in the original image.

This can be show in the following image (produced by using a sample code from Matlab's help for houghlines). The green lines are detected. The blue one is the longest one:

output from example code by Mathoworks

I ran cv::HoughLines on a simple synthetic image I generated (several squares etc.). The image is attached here:

my sample image

The relevant code portion is:

cv::vector<cv::Vec2f> lines;
cv::HoughLines(I_BW, lines, 1, CV_PI/180,200);
cv::Mat linesMat ( lines, true );

Viewing the linesMat matrix (I converted it to this form so I can use image watch to view the data) while running a for loop to add a red line over the edge image I see that rho and theta are ordered by the length of the longest line in the image.

My output is:

Showing the 8 strongest lines

The lines are the entire width (or height) of the image. How can I just show the actual lines like in the Matlab example? I can work my way back from rho+theta to x and y, but then I have to somehow link them to the detected edges etc. - maybe there's a simple way to do this which I'm missing?

Thanks!

도움이 되었습니까?

해결책

taoufik is correct and I upvoted his answer. I actually found the answer in the OpenCV 2 Computer Vision Application Programming Cookbook before I read his comment.

I'm selecting my answer as the answer, because it is more complete for future reference.

@taoufik - thanks again, man!

I'll post a code snippet that may be of use to other people (based on a solution I found in the cookbook. I just wrote the short version, not the elegant class implementation from the cookbook).

I also add here a small function I wrote that computes the CDF used to find the high and low threshold for the canny edge detector in the Matlab implementation of Canny which gives good results. Normally I also do a Gaussian blur prior the edge detection (as appears within the canny.m in Matlab) but the attached image is synthetically perfect (no noise) so it's redundant here. I chose a high minimum vote value ('threshold') so only the 4 long lines will be found.

We'll start with the code in the main function:

cv::Mat image = cv::imread("shapes.jpg");
int bins = 256;
cv::Mat cdf = getGrayCDF(image,bins);
cv::Mat diffy = cdf>0.7;
cv::Mat NonZero_Locations;   // output, locations of non-zero pixels 
cv::findNonZero(diffy, NonZero_Locations);
double highThreshold = double((NonZero_Locations.at<cv::Point>(0).y))/bins;
double lowThreshold = 0.4*highThreshold;
cv::Mat contours;
// cv::GaussianBlur( image, contours, cv::Size(7,7),2 ); // NOT REQUIRED HERE. Syhnthetic image
cv::Canny( image, contours, lowThreshold*bins, highThreshold*bins);
std::vector<cv::Vec4i> lines;
double rho = 1; // delta_rho resolution
double theta = CV_PI/180; // delta_theta resolution
int threshold = 300; // threshold number of votes , I SET A HIGH VALUE TO FIND ONLY THE LONG LINES
double minLineLength = 0; // min length for a line
double maxLineGap = 2; // max allowed gap along the line
cv::HoughLinesP(contours,lines, rho, theta, threshold, minLineLength, maxLineGap); // running probabilistic hough line
if (image.channels()!=3) {cv::cvtColor(image,image,CV_GRAY2BGR);} // so we can see the red lines
int line_thickness = 2;
cv::Scalar color=cv::Scalar(0,0,255);
std::vector<cv::Vec4i>::const_iterator iterator_lines = lines.begin();
while (iterator_lines!=lines.end()) {
    cv::Point pt1((*iterator_lines)[0],(*iterator_lines)[1]);
    cv::Point pt2((*iterator_lines)[2],(*iterator_lines)[3]);
    cv::line( image, pt1, pt2, color, line_thickness);
    ++iterator_lines;
}
cv::imshow("found lines", image); cvWaitKey(0); cv::destroyWindow("found lines");

And I'll end with my function for computing a simple grayscale cumulative distribution function:

cv::Mat getGrayCDF(cv::Mat Input, int histSize){
cv::Mat InputGray = Input.clone();
if (InputGray.channels()!=1) {cv::cvtColor(Input,InputGray,CV_BGR2GRAY);}
float range[] = { 0, histSize  } ;
const float* histRange = { range };
bool uniform = true; bool accumulate = false;
cv::Mat hist;
calcHist( &InputGray, 1, 0, cv::Mat(), hist, 1, &histSize , &histRange, uniform, accumulate );
for (int i = 1; i < hist.rows; i++) {
    float* data = hist.ptr<float>(0);
    data[i] += data[i-1];
}
return hist/(InputGray.total()); // WE NOW HAVE A *NORMALIZED* COMPUTED CDF!
}

My solution for the above given snippet is:

shapes with 4 highlighted lines

Hope you find this useful!

다른 팁

What you're looking for is the Probabilistic Hough transform. In OpenCV it is available under HoughLinesP().

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top