如何从OpenCV for Android中的每个轮廓中提取线条?

Sai*_*iph 5 android opencv

我想检查每个Canny检测到的边缘并查找其中的主线(检查它们是否看起来形成一个矩形,例如,如果2对线是平行的等等).

Imgproc.HoughLinesP做我想要的,但它给出了整个图像的线条,我想知道哪些线条来自相同的边缘.

我也尝试使用FindContours,并使用approxPolyDP在每个轮廓中寻找主线,但这看起来并不适合,因为Canny检测到的边缘经常存在间隙.这给出了边缘的轮廓而不是边缘本身.

这是一个测试图像示例:

在此输入图像描述

在此输入图像描述

如何为每个形状获得一组线?

Sai*_*iph 2

根据 Miki 的回答,这是我所做的:

  • 精明的
  • HoughLinesP(或 LineSegmentDetector,根据需要):检测线
  • ConnectedComponents:在 Canny 图像中查找 Canny“轮廓”。
  • 使用 3x3 内核进行扩张(见下文)
  • 对于每条霍夫线:从该线上取出一些像素并查找最常见的值(忽略 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 所属轮廓的颜色来“标记”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's 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);
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述