How to extract lines from each circuit in OpenCV for Android?

I would like to examine each detected Canny front and look for the main lines in it (to check if they appear to be a rectangle, for example, if two pairs of lines are parallel, etc.).

Imgproc.HoughLinesP does what I want, but it gives lines from the whole image, and I want to know which lines come from the same edges.

I also tried FindContours and searched for the main lines in each loop with approxPolyDP, but this does not look adapted because edges are found in Canny. This gives the contours of the ribs, not the ribs themselves.

Here is an example of a test image:

enter image description here

enter image description here

How can I get a rowset for each shape?

+4
source share
2 answers

Based on Miki's answer, here is what I did:

  • Canny
  • HoughLinesP ( LineSegmentDetector, ):
  • ConnectedComponents: Canny "" Canny.
  • Dilate 3x3 (. )
  • Hough: ( 0). , {p1 , 0.75*p1 + 0.25*p2, 0.5*p1 + 0.5*p2, 0.25*p1 + 0.75*p2, p2}, , {1,2,0,2,2}, 2. , 1 ( , ).

"" HoughLines , .

Imgproc, OpenCV 3.0 .

:

// open image
File root = Environment.getExternalStorageDirectory();
File file = new File(root, "image_test.png");

Mat mRGBA = Imgcodecs.imread(file.getAbsolutePath());
Imgproc.cvtColor(mRGBA, mRGBA,  Imgproc.COLOR_BGR2RGB);

Mat mGray = new Mat();
Imgproc.cvtColor(mRGBA, mGray, Imgproc.COLOR_RGBA2GRAY);

Imgproc.medianBlur(mGray, mGray, 7);

/* Main part */

Imgproc.Canny(mGray, mGray, 50, 60, 3, true);

Mat aretes = new Mat();
Imgproc.HoughLinesP(mGray, aretes, 1, 0.01745329251, 30, 10, 4);

/**
 * Tag Canny edges in the gray picture with indexes from 1 to 65535 (0 = background)
 * (Make sure there are less than 255 components or convert mGray to 16U before)
 */
int nb = Imgproc.connectedComponents(mGray,mGray,8,CvType.CV_16U);

Imgproc.dilate(mGray, mGray, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3,3)));


// for each Hough line
for (int x = 0; x < aretes.rows(); x++) {
     double[] vec = aretes.get(x, 0);
     double x1 = vec[0],
            y1 = vec[1],
            x2 = vec[2],
            y2 = vec[3];

     /**
      * Take 5 points from the line
      *
      *   x----x----x----x----x
      *   P1                  P2
      */
        double[] pixel_values = new double[5];
        pixel_values[0] = mGray.get((int) y1, (int) x1)[0];
        pixel_values[1] = mGray.get((int) (y1*0.75 + y2*0.25), (int) (x1*0.75 + x2*0.25))[0];
        pixel_values[2] = mGray.get((int) ((y1 + y2) *0.5), (int) ((x1 + x2) *0.5))[0];
        pixel_values[3] = mGray.get((int) (y1*0.25 + y2*0.75), (int) (x1*0.25 + x2*0.75))[0];
        pixel_values[4] = mGray.get((int) y2, (int) x2)[0];

        /**
         * Look for the most frequent value
         * (To make it readable, the following code accepts the line only if there are at
         * least 3 good pixels)
         */
        double value;
        Arrays.sort(pixel_values);

        if (pixel_values[1] == pixel_values[3] || pixel_values[0] == pixel_values[2] || pixel_values[2] == pixel_values[4]) {
            value = pixel_values[2];
        }
        else {
            value = 0;
        }

        /**
         * Now value is the index of the connected component (or 0 if it a bad line)
         * You can store it in an other array, here I'll just draw the line with the value
         */
        if (value != 0) {
            Imgproc.line(mRGBA,new Point(x1,y1),new Point(x2,y2),new Scalar((value * 41 + 50) % 255, (value * 69 + 100) % 255, (value * 91 + 60) % 255),3);
        }
}

Imgproc.cvtColor(mRGBA, mRGBA, Imgproc.COLOR_RGB2BGR);
File file2 = new File(root, "image_test_OUT.png");
Imgcodecs.imwrite(file2.getAbsolutePath(), mRGBA);

enter image description here

+1

OpenCV 3.0.0, LineSegmentDetector "AND" .

. ++ ( ), Java. , , LineSegmentDetector . .

#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

int main()
{
    RNG rng(12345);
    Mat3b img = imread("path_to_image");
    Mat1b gray;
    cvtColor(img, gray, COLOR_BGR2GRAY);

    Mat3b result;
    cvtColor(gray, result, COLOR_GRAY2BGR);

    // Detect lines
    Ptr<LineSegmentDetector> detector = createLineSegmentDetector();
    vector<Vec4i> lines;
    detector->detect(gray, lines);

    // Draw lines
    Mat1b lineMask(gray.size(), uchar(0));
    for (int i = 0; i < lines.size(); ++i)
    {
        line(lineMask, Point(lines[i][0], lines[i][1]), Point(lines[i][2], lines[i][3]), Scalar(255), 2);
    }

    // Compute edges
    Mat1b edges;
    Canny(gray, edges, 200, 400);

    // Find contours
    vector<vector<Point>> contours;
    findContours(edges.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

    for (int i = 0; i < contours.size(); ++i)
    {
        // Draw each contour
        Mat1b contourMask(gray.size(), uchar(0));
        drawContours(contourMask, contours, i, Scalar(255), 2); // Better use 1 here. 2 is just for visualization purposes

        // AND the contour and the lines
        Mat1b bor;
        bitwise_and(contourMask, lineMask, bor);

        // Draw the common pixels with a random color
        vector<Point> common;
        findNonZero(bor, common);

        Vec3b color = Vec3b(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
        for (int j = 0; j < common.size(); ++j)
        {
            result(common[j]) = color;
        }
    }


    imshow("result", result);
    waitKey();

    return 0;
}

enter image description here

+1

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


All Articles