[opencv][cpp] 学习手册3:多边形拟合

[opencv][cpp] 学习手册3:多边形拟合




1. 多边形拟合示例:approxPolyDP

原理
图像截取自课件视频
在这里插入图片描述
目的:需要拟合红色的曲线

  1. 连接曲线首尾两端(S0,E)
  2. 对曲线上的每一个点做直线的垂线(取一个方向,比如从起始 S0 点到终点 E)
  3. 每一个垂线都有长度L,当某一个曲线上的点对应的 L 大于阈值 T,那么就记录下这个点 {Sn}
  4. 以这个点 Sn 为新的起点,连接 E,重复 1
  5. 得到了 {Sn} = {S1, S2, … ,Sn} 以及 E,这些点既是曲线的拟合点。
  6. T 越小,拟合越精准。

代码

/**
Created by jacob on 12/31/20.
*/

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/utils/logger.hpp>

using namespace std;
using namespace cv;

namespace cvlog = cv::utils::logging;


int main() {

    cvlog::setLogLevel(cvlog::LOG_LEVEL_INFO);

    string filename = "../img/book.jpg";
    Mat src = imread(filename, IMREAD_COLOR);
	resize(src, src, Size(src.cols / 2, src.rows / 2));

    // 1.将彩色图像转成灰度图像
    Mat grayImg;
    cvtColor(src, grayImg, COLOR_BGR2GRAY);
    imshow("grayImg", grayImg);

    // 2. 转成二值图(黑底白字,白底黑字有不同的处理方式)
    Mat binary;
    threshold(grayImg, binary, 0, 255, THRESH_BINARY | THRESH_TRIANGLE);
    imshow("binary1", binary);

    // 膨胀操作(可选)
    Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
    dilate(binary, binary, kernel, Point(-1, -1), 4);
    erode(binary, binary, kernel, Point(-1, -1), 4);
    bitwise_not(binary, binary);
    imshow("binary dilate", binary);

    // 定义一个画布,用于保存最大轮廓图像
    Mat maxImg = cv::Mat::zeros(src.size(), CV_8UC3);

    // 3. 找出工牌的轮廓
    vector<vector<Point>> contours;
    vector<cv::Vec4i> hierarchy;
    findContours(binary, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    CV_LOG_INFO(NULL, "contours size: " << contours.size())

    // 定义一个变量,存储所有多边形轮廓
    vector<vector<Point>> polyContours;
    for (int i = 0; i < contours.size(); ++i) {
        // 当前的轮廓所有的点
        vector<Point> contour = contours[i];
//        CV_LOG_INFO(NULL, "contour: [" << i << "]\n" << contour)

        // 计算面积
        double area = contourArea(contour);
        if (area > 10000) {
            // 在一个空白的图像中画出轮廓
            drawContours(maxImg, contours, i, Scalar(0, 0, 255), 3);

            // 根据轮廓,拟合出多边形出来
            vector<Point> polyPoint;
            approxPolyDP(contour, polyPoint, 100, true);

            CV_LOG_INFO(NULL, "拟合结果点的数量:" << polyPoint.size())

            polyContours.push_back(polyPoint);

            drawContours(maxImg, polyContours, -1, Scalar(0, 255, 255), 1);
            drawContours(src, polyContours, -1, Scalar(0, 255, 255), 1);
        }
    }

    // 输出四边形拟合点
    vector<Point> polyPoint = polyContours[0];

    for (int j = 0; j < polyPoint.size(); ++j) { // 左上角: 1, 右上角 0 左下角 2 右下角3
        cout << "点:" << polyPoint[j] << endl;
    }

    // 使用霍夫直线
    Mat maxGrayImg;
    cvtColor(maxImg, maxGrayImg, COLOR_BGR2GRAY);

    // 4. 找到边缘的交点
    vector<Point2f> sourcePoints = {polyPoint[1], polyPoint[0], polyPoint[2], polyPoint[3]};
    vector<Point2f> targetPoints = {Point2f(0, 0), Point2f(480, 0), Point2f(0, 640), Point2f(480, 640)};

    // 5. 运用透视变换
    Mat m = getPerspectiveTransform(sourcePoints, targetPoints);

    Mat dst;
    warpPerspective(src, dst, m, Size(480, 640));

    imshow("maxImg", maxImg);
    imshow("src", src);
    imshow("dst", dst);

    waitKey(0);
    return 0;
}

运行结果
在这里插入图片描述


2. 心得

  1. 没有标准化的处理方法
  2. 要对图像进行预处理,resize,dilate,erode,开闭处理等
  3. 此示例中对于白底黑字,黑底白字的处理方式不同,前者在预处理后应该需要进行一次二值图反转操作 bitwise_not

&&_参考

链接:opencv对二值图像进行颜色反色操作


&&_问题解决

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
你可以使用OpenCV中的`cv2.approxPolyDP()`函数来进行多边形拟合。该函数可接受一个轮廓作为输入,并根据指定的精度将其拟合多边形。 下面是一个使用`cv2.approxPolyDP()`函数进行多边形拟合的示例代码: ```python import cv2 import numpy as np # 读取图像并转换为灰度图像 image = cv2.imread('image.jpg') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 对图像进行阈值处理或边缘检测,得到轮廓 # 例如,可以使用cv2.Canny()函数进行边缘检测 edges = cv2.Canny(gray,100, 200) # 查找轮廓,假设只有一个轮廓 contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 进行多边形拟合 epsilon = 0.01 * cv2.arcLength(contours[0], True) approx = cv2.approxPolyDP(contours[0], epsilon, True) # 在原始图像上绘制拟合多边形 cv2.drawContours(image, [approx], 0, (0, 255, 0), 2) # 显示结果图像 cv2.imshow('Approximated Polygon', image) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在上述示例中,我们首先读取一张图像并将其转换为灰度图像。然后,我们使用边缘检测(例如Canny算子)获取图像的边缘。接下来,我们使用`cv2.findContours()`函数找到图像中的轮廓。假设我们只有一个轮廓,所以我们选择了列表中的第一个轮廓。 然后,我们使用`cv2.approxPolyDP()`函数进行多边形拟合。在这个函数中,我们需要提供一个轮廓、拟合精度和一个布尔值参数(如果为True,则表示该轮廓是封闭的)。 最后,我们使用`cv2.drawContours()`函数将拟合多边形绘制在原始图像上,并显示结果图像。请注意,`cv2.drawContours()`函数需要传入一个轮廓列表(即使只有一个轮廓)。 希望这个示例对你有帮助!如果你有任何其他问题,请随时问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值