如何从嵌套矩形的二进制图像中提取内部矩形?

时间:2018-11-01 15:53:14

标签: c++ opencv image-processing

我正在尝试将LCD定位在一组图像中,但是目前在此过程中处于某个位置。这是感兴趣区域的二进制图像,如何从中提取内部矩形-或边界内角的坐标。

binary image of LCD

我尝试了以下方法, 使用Canny()查找图像中的边缘,使用findContours()查找轮廓。从轮廓列表中,我遇到了两个问题,

  1. 要选择哪个轮廓?
  2. 从此图像中,我得到了10个以上的轮廓,只有外部矩形是一个完整的矩形。其余所有轮廓都是不相交的线,它们一起构成了内部矩形

这是我的代码,

// threshold
Mat im1_thresh;
threshold(im1, im1_thresh, 100, 200, THRESH_BINARY);        

// find edges
Mat im1_canny;
Canny(im1_thresh, im1_canny, 50, 100);

// find contours
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(im1_canny, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

// draw contours
RNG rng;
vector<Rect> boundRect(contours.size());
Mat im1_contours = Mat::zeros(im1_thresh.size(), CV_8UC3);
for (int i = 0; i < contours.size(); i++) {
    // draw each contour in a different color
    Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
    drawContours(im1_contours, contours, i, color, 2, 8, hierarchy, 0, Point());

    // draw bounding boxes around each contour in original image
    boundRect[i] = boundingRect(Mat(contours[i]));
    rectangle(im1, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0);
}

问题:如何从上面的二进制图像中定位内部矩形?

3 个答案:

答案 0 :(得分:0)

为解决轮廓不连续的问题-我调整了阈值,直到轮廓平滑为止。有时模糊也有帮助。之后,选择最里面的轮廓。

我在上面的代码中使用了hierarchy数组来选择相关的轮廓,并在原始图像上使用它创建一个边界框。层次结构数组是N * 4矩阵,其中N是轮廓数。对于每个轮廓,hierarchy包含与相关轮廓有关的信息,例如[previous, next, child, parent]。如果没有相关的轮廓,则可以看到值-1

这是相关图像的层次结构矩阵,

  

[-1,-1,1,-1]
  [-1,-1,2,0]
  [-1,-1,3,1]
  [-1,-1,-1,2]

我对最后的轮廓感兴趣。它没有孩子,并且以2为父。 这是我的实现,

Rect boundRect;

// loop through the contours/hierarchy
for (int i = 0; i<contours.size(); i++) {
    // hierarchy is (previous, next, child, parent)
    // look for innermost -- no child but a parent exists
    if (hierarchy[i][2] == -1 && hierarchy[i][3] != -1) {
        // draw contour
        Scalar color = Scalar(255,0,0);
        drawContours(im1_contours, contours, i, color);

        // draw a bounding rectangle around original image
        boundRect = boundingRect(Mat(contours[i]));
        rectangle(im1, boundRect.tl(), boundRect.br(), color);
    }
}

// subset the image
Mat im1_roi;
im1_roi = im1(boundRect);

答案 1 :(得分:0)

要找到最矩形的轮廓,可以运行minAreaRect以适合旋转的矩形,然后将结果与原始轮廓进行比较。

每个区域的面积比例可能足够,具体取决于噪声等。

一旦选择了最矩形的轮廓,使用approxPoly减少到4个点应该可以很好地近似屏幕矩形。

答案 2 :(得分:0)

  

从此图像中,我得到了10个以上的轮廓,只有外部矩形是一个完整的矩形。其余所有轮廓都是不相交的线,它们一起构成了内部矩形

您使用默认的Canny孔径= 3,尝试将其增大到5或7,它将检测到内部轮廓为一个,而不是多个小轮廓。试试这个:

int apertureSize = 5;
Canny(im1_thresh, im1_canny, 50, 100, apertureSize);
  

昨晚我碰到另一个问题,如果屏幕上有一个坏点,它也会出现在轮廓列表中。

检查每个轮廓的面积,以确保其大于最小可接受面积。您提供的图片尺寸为250x450,内部矩形尺寸为〜170x380。因此,您可以将minArea设置为170x380的80%(= 0.8 * 64600)。例如,在绘制之前将此检查添加到循环中。

float minArea = 0.8 * 64600;   
if (boundRect[i].area() > minArea ){
    rectangle(im1, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0);
}