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

Posted

技术标签:

【中文标题】使用 OpenCV C++ 从黑白图像中提取四边形的角(极端角点)【英文标题】:Extract corner (extreme corner points) of quadrangle from black/white image using OpenCV C++ 【发布时间】:2019-07-19 15:33:11 【问题描述】:

作为更大项目的一部分,我需要提取四边形的最底角。我有一个图像和一个相应的二进制 Mat,其中图像为白色(图像)为 1,黑色(背景)为 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++

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

右边也一样,但是计算效率不是很高。

这是一个示例四边形和感兴趣的角。

理想的输出是两个 Mats,类似于原始的一个,只在感兴趣的区域有 1,而到处都是 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;
        
    

两种方法的结果:红色 - 第一种方法,绿色第二种

【讨论】:

以上是关于使用 OpenCV C++ 从黑白图像中提取四边形的角(极端角点)的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV EqualizeHist() 从彩色图像创建黑白图像

无法使用 C++ 和 OpenCV 从视频中提取帧

从黑色背景OpenCV C++中提取对象

OpenCV 例程200篇223. 特征提取之多边形拟合(cv.approxPolyDP)

OpenCV 例程200篇223. 特征提取之多边形拟合(cv.approxPolyDP)

从黑白位图图像中提取路径信息