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

时间:2019-07-19 15:33:11

标签: c++ opencv computer-vision

作为较大项目的一部分,我需要提取四边形的底角。我有一个图像和一个对应的二进制Mat,其中1s是白色(图像),0是黑色(背景)。

我已经找到了找到最左,最右,最底和最顶点的方法,但是它们可能无法给出我想要的点,因为四边形并不是完美的矩形。

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

Finding Top Left and Bottom Right Points (C++)

Finding extreme points in contours with OpenCV C++

我能想到的唯一方法不是很好。我希望你们能想到一种更好的方法,而不是仅循环通过最底行然后最左点的矩阵,然后将点保持在距最底点和最左点一定的半径内。

与右边相同,但这在计算效率上不是很有效。

example quadrangle

这是一个示例四边形和四角。

理想的输出是两个Mat,与原始Mat相似,它们仅在感兴趣区域具有1s,而在各处均具有0s。

任何人和所有帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

至少有两种可能的方法。两者都假设您已经提取了角落:

  1. 使用approxPolyDP函数逼近轮廓并获得四边形的4个顶点。

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