简体   繁体   English

使用OpenCV C ++从黑白图像中提取四角形的角(极端角点)

[英]Extract corner (extreme corner points) of quadrangle from black/white image using OpenCV C++

As part of a bigger project, I need to extract the extreme bottom corners of a quadrangle. 作为更大项目的一部分,我需要提取四边形的底角。 I have an image and a corresponding binary Mat with 1s where the image is white (the image) and 0 where black (the background). 我有一个图像和一个对应的二进制Mat,其中1s是白色(图像),0是黑色(背景)。

I've found ways to find the extreme left, right, bottom and top points but they may not give the points I want as the quadrangles are not perfectly rectangular. 我已经找到了找到最左,最右,最底和最顶点的方法,但是它们可能无法给出我想要的点,因为四边形并不是完美的矩形。

https://www.pyimagesearch.com/2016/04/11/finding-extreme-points-in-contours-with-opencv/ https://www.pyimagesearch.com/2016/04/11/finding-extreme-points-in-contours-with-opencv/

Finding Top Left and Bottom Right Points (C++) 查找左上角和右下角(C ++)

Finding extreme points in contours with OpenCV C++ 使用OpenCV C ++查找轮廓中的极点

The only way I can think of doing it is not very good. 我能想到的唯一方法不是很好。 I'm hoping you guys can think of a better way than to just cycle though the matrix for the most bottom row then most left point and then keep points within a certain radius from that most bottom and left point. 我希望你们能想到一种更好的方法,而不是仅循环通过最底行然后最左点的矩阵,然后将点保持在距最底点和最左点一定的半径内。

And the same for the right, but this is not very computationally efficient. 正确的做法是相同的,但是计算效率不是很高。

示例四边形

This is an example quadruple and the corners of interest. 这是一个示例,是四个角落和四个角落。

The ideal output is two Mats, similar to the original one, that have 1s only in the region of interest and 0s everywhere. 理想的输出是两个Mats,与原始Mats相似,它们仅在感兴趣区域中具有1s,而在各处均具有0s。

Any and all help will be greatly appreciated!! 任何和所有帮助将不胜感激!

There are at least two possible approaches. 至少有两种可能的方法。 Both assume that you've extracted the corners: 两者都假设您已经提取了角落:

  1. Use approxPolyDP function to approximate the contour and get 4 vertices of a quadrangle. 使用approxPolyDP函数近似轮廓,并获得一个四边形的4个顶点。

2.Fit rectangle to the contour and then find nearest points in your contour to the bottom vertices of this rectangle. 2.使矩形适合轮廓,然后在轮廓中找到该矩形底部顶点的最近点。

// bin -  your binarized image
std::vector<std::vector<cv::Point2i>> contours;
cv::findContours(bin, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
int biggestContourIdx = -1;
double biggestContourArea = 0;
for (int i = 0; i < contours.size(); ++i)
{
    auto area = cv::contourArea(contours[i]);
    if (area > biggestContourArea)
    {
        biggestContourArea = area;
        biggestContourIdx = i;
    }
}
//first solution:
std::vector<cv::Point2i> approx;
cv::approxPolyDP(contours[biggestContourIdx], approx, 30, true);
auto mean = cv::mean(approx);
std::vector<cv::Point2i> bottomCorners;

for (auto p : approx)
{
    if (p.y > mean[1]) bottomCorners.push_back(p);
}

//second solution:
auto rect = cv::minAreaRect(cv::Mat(contours[biggestContourIdx]));
auto center = rect.center;
Point2f rect_points[4];
rect.points(rect_points);
std::vector<cv::Point2i> bottomRectCorners;
std::vector<double> distances(2, std::numeric_limits<double>::max());
for (int i = 0; i < 4; ++i)
{
    if (rect_points[i].y > center.y)
        bottomRectCorners.push_back(rect_points[i]);
}
bottomCorners.clear();
bottomCorners.resize(2);
for (auto p : contours[biggestContourIdx])
{
    for (int i = 0; i < distances.size(); ++i)
    {
        auto dist = cv::norm(p - bottomRectCorners[i]);
        if (dist < distances[i])
        {
            distances[i] = dist;
            bottomCorners[i] = p;
        }
    }
}

Results of both approaches: red - first method, green second 两种方法的结果:红色-第一种方法,绿色第二种 两种方法的结果

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM