OpenCV Line Detection

I am trying to find the edges of a centered frame in this image: black and white box

I tried using HoughLines using dRho = img_width / 1000, dTheta = pi / 180, and threshold = 250 It works fine on this image, scales to 1/3 of the size, but on a full-sized image it just gets lines everywhere in every direction .. .

What can I do to customize this to be more accurate?

+2
source share
3 answers

The code to achieve the result below is a small modification of the one presented in this answer: how to determine the square :

enter image description here

The original program can be found inside OpenCV, it is called squares.cpp . The code below was modified to search for squares only in the first color plane, but since it still detects many squares, at the end of the program I drop all of them except the first, and then call draw_squares() to show what was detected. You can change this easilly to draw them all and see everything that has been discovered.

Now you can do all kinds of things, including setting the region of interest (ROI) to extract the region that is inside the square (ignore everything else around it).

You can see that the detected rectangle is not quite aligned with the lines in the image. You must perform some preprocessing operations (erode?) On the image to reduce line thickness and improve detection. But from here everything is on you:

 #include <cv.h> #include <highgui.h> using namespace cv; double angle( cv::Point pt1, cv::Point pt2, cv::Point pt0 ) { double dx1 = pt1.x - pt0.x; double dy1 = pt1.y - pt0.y; double dx2 = pt2.x - pt0.x; double dy2 = pt2.y - pt0.y; return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10); } void find_squares(Mat& image, vector<vector<Point> >& squares) { // TODO: pre-processing // blur will enhance edge detection Mat blurred(image); medianBlur(image, blurred, 9); Mat gray0(blurred.size(), CV_8U), gray; vector<vector<Point> > contours; // find squares in the first color plane. for (int c = 0; c < 1; c++) { int ch[] = {c, 0}; mixChannels(&blurred, 1, &gray0, 1, ch, 1); // try several threshold levels const int threshold_level = 2; for (int l = 0; l < threshold_level; l++) { // Use Canny instead of zero threshold level! // Canny helps to catch squares with gradient shading if (l == 0) { Canny(gray0, gray, 10, 20, 3); // // Dilate helps to remove potential holes between edge segments dilate(gray, gray, Mat(), Point(-1,-1)); } else { gray = gray0 >= (l+1) * 255 / threshold_level; } // Find contours and store them in a list findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); // Test contours vector<Point> approx; for (size_t i = 0; i < contours.size(); i++) { // approximate contour with accuracy proportional // to the contour perimeter approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true); // Note: absolute value of an area is used because // area may be positive or negative - in accordance with the // contour orientation if (approx.size() == 4 && fabs(contourArea(Mat(approx))) > 1000 && isContourConvex(Mat(approx))) { double maxCosine = 0; for (int j = 2; j < 5; j++) { double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1])); maxCosine = MAX(maxCosine, cosine); } if (maxCosine < 0.3) squares.push_back(approx); } } } } } void draw_squares(Mat& img, vector<vector<Point> > squares) { for (int i = 0; i < squares.size(); i++) { for (int j = 0; j < squares[i].size(); j++) { cv::line(img, squares[i][j], squares[i][(j+1) % 4], cv::Scalar(0, 255, 0), 1, CV_AA); } } } int main(int argc, char* argv[]) { Mat img = imread(argv[1]); vector<vector<Point> > squares; find_squares(img, squares); std::cout << "* " << squares.size() << " squares were found." << std::endl; // Ignore all the detected squares and draw just the first found vector<vector<Point> > tmp; if (squares.size() > 0) { tmp.push_back(squares[0]); draw_squares(img, tmp); } //imshow("squares", img); //cvWaitKey(0); imwrite("out.png", img); return 0; } 
+5
source

Try using a pre-treatment pass with an erosion filter. This will give you the same effect as zooming out - the lines will become thinner and won't disappear at the same time.

The Blur filter is also a good idea, as chaiy says.

This method (with blurring) will become something like http://www.ic.uff.br/~laffernandes/projects/kht/index.html (kernel based conversion)

+3
source

when resizing an image, the image is usually first blurred by a filter, for example. Gauss to get rid of high frequencies. Probably the fact that the size has changed is better, because your original image is somehow noisy.

Try blurring the image first, for example. with cv::GaussianBlur(src, target, Size(0,0), 1.5) , then it should be equivalent to resizing. (He forgot the theory, if it doesn't work, try 3 and 6)

+3
source

Source: https://habr.com/ru/post/918900/


All Articles