21.OpenCV获取图像轮廓信息

OpenCV获取图像轮廓信息

在计算机视觉领域,识别和分析图像中的对象形状是一项基本任务。OpenCV 库提供了一个强大的工具——轮廓检测(Contour Detection),它能够帮助我们精确地定位对象的边界。这篇博文将带你入门 OpenCV 的轮廓检测,理解其原理,并学会如何在 C++ 中使用它。

1.什么是轮廓?

简单来说,轮廓可以看作是一条连接所有具有相同颜色或灰度值的连续点(沿着边界)的曲线。

更准确地说,轮廓是图像中强度或颜色发生显著变化的区域的边界。在 OpenCV 中,轮廓检测通常作用于二值图像(只有黑色和白色像素的图像)。算法会寻找白色(或非零)区域的边界,并将这些边界表示为一系列点的坐标。

通过检测轮廓,我们可以实现目标分割、形状分析、物体计数、特征提取及对象检测和识别等任务。

轮廓介绍

如上图1,2,3 轮廓还有层次,有最外的轮廓1依次往里包括2,3轮廓。

2. OpenCV 轮廓检测函数

2.1 findContours 函数

findContours 是 OpenCV 中最常用的轮廓检测函数,其函数原型如下:

void findContours(InputArray image, OutputArrayOfArrays contours, OutputArray hierarchy,
                  int mode, int method, Point offset = Point());
  • image:输入的二值图像(非零值表示前景)。
  • contours:输出轮廓,存储为 std::vector<std::vector<Point>>
  • hierarchy:输出轮廓的层级信息,描述轮廓之间的嵌套关系。
  • mode:轮廓检索模式,如 RETR_EXTERNAL(只检测最外层轮廓)、RETR_LIST(检测所有轮廓但不建立层级关系)、RETR_TREE(检测所有轮廓并重构完整的层级结构)。
  • method:轮廓近似方法,如 CHAIN_APPROX_SIMPLE(压缩水平、垂直和对角冗余点)和 CHAIN_APPROX_NONE(存储所有点)。
  • offset:可选参数,用于给输出轮廓的所有点加上偏移值。

2.3 drawContours 函数

drawContours 函数用于在图像上绘制检测到的轮廓。它可以帮助直观展示轮廓检测和形状分析的结果。函数原型如下:

void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx,
                  const Scalar& color, int thickness = 1, int lineType = LINE_8,
                  InputArray hierarchy = noArray(), int maxLevel = INT_MAX, Point offset = Point());

  • image:输入输出图像,即在该图像上绘制轮廓。
  • contours:轮廓集合,通常由 findContours 得到,类型为 std::vector<std::vector<Point>>
  • contourIdx:指定绘制哪一个轮廓;若设为 -1,则绘制所有轮廓。
  • color:绘制轮廓的颜色,如 Scalar(0,255,0) 表示绿色。
  • thickness:轮廓线的粗细;若为负值,则填充轮廓内部。
  • lineType:线型,默认 LINE_8
  • hierarchy:轮廓的层级信息,可选。
  • maxLevel:绘制轮廓的最大层级,默认 INT_MAX
  • offset:绘制时添加的偏移量。

drawContours 常用于可视化轮廓检测结果,结合 findContours 使用可以将检测到的目标区域在图像上直观标记出来。

2.3 轮廓检测的基本步骤

使用 OpenCV C++ 进行轮廓检测通常遵循以下步骤:

  1. 读取图像 (Read Image): 使用 cv::imread 加载你想要处理的源图像到 cv::Mat 对象。
  2. 转换为灰度图 (Convert to Grayscale): 使用 cv::cvtColor 将彩色图像转换为灰度图,以简化图像信息。
  3. 二值化 (Thresholding): 使用 cv::threshold 将灰度图像转换为二值图像。这是轮廓检测的关键步骤,因为 findContours 函数通常需要二值图像作为输入。
  4. 查找轮廓 (Find Contours): 使用 cv::findContours() 函数来检测图像中的所有轮廓。
  5. 绘制轮廓 (Draw Contours): (可选)使用 cv::drawContours() 函数将检测到的轮廓绘制在原始图像或新的画布上,以便可视化。

2.4 参考代码

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

int main() {
    // 读取灰度图像
    Mat src = imread("E:/image/test.png");
    if (src.empty()) {
        cerr << "图像加载失败!" << endl;
        return -1;
    }
    Mat gray;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    GaussianBlur(gray, gray, Size(5, 5), 0);

    Mat binary;
    double otsu_thresh_val = threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
    cout << "Otsu 自动选择的阈值为:" << otsu_thresh_val << endl;

    imshow("原始灰度图像", gray);
    imshow("otsu 二值化", binary);
	//查找轮廓
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
    cout << hierarchy.size();

	//绘制所有轮廓
    Mat contourImage = src.clone();
    drawContours(contourImage, contours, -1, Scalar(0, 0, 255), 1);
  
    imshow("contour", contourImage);
    waitKey(0);
    destroyAllWindows();
    return 0;
}

轮廓检测结果

如果只想要最外面的轮廓只需要把参数RETR_TREE改为**RETR_EXTERNAL**

3. 计算并绘制轮廓几何特征

在检测到轮廓后,我们可以计算并绘制轮廓的几何特征,例如:

  • 面积 (contourArea)
  • 周长 (arcLength)
  • 重心
  • 最小外接矩形 (boundingRect)
  • 最小外接圆 (minEnclosingCircle)

3.1 参考代码

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
    // 读取图像并转换为灰度图
    Mat src = imread("E:/image/test1.png");
    if (src.empty()) {
        cerr << "图像加载失败!" << endl;
        return -1;
    }
    Mat gray;
    cvtColor(src, gray, COLOR_BGR2GRAY);

    // 应用阈值处理得到二值图像
    Mat binary;
    threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);

    // 检测轮廓
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(binary, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    // 创建用于显示轮廓的图像
    Mat contourImage = src.clone();

    for (size_t i = 0; i < contours.size(); i++) {
        // 绘制轮廓
        drawContours(contourImage, contours, static_cast<int>(i), Scalar(0, 255, 0), 2);

        // 计算轮廓面积和周长
        double area = contourArea(contours[i]);
        double perimeter = arcLength(contours[i], true);
        if (area < 500) continue;

        // 计算重心
        Moments M = moments(contours[i]);
        int cx = static_cast<int>(M.m10 / M.m00);
        int cy = static_cast<int>(M.m01 / M.m00);
        circle(contourImage, Point(cx, cy), 5, Scalar(255, 0, 0), -1);

        // 计算外接矩形
        Rect boundingBox = boundingRect(contours[i]);
        rectangle(contourImage, boundingBox, Scalar(0, 0, 255), 2);
		//最小外接矩形
        RotatedRect box2 = minAreaRect(contours[i]);
        Point2f vertices[4];
        box2.points(vertices);
        for (int j = 0; j < 4; j++) {
            line(contourImage, vertices[j], vertices[(j + 1) % 4], Scalar(0, 255, 255), 1);
        }

        // 计算最小外接圆
        Point2f center;
        float radius;
        minEnclosingCircle(contours[i], center, radius);
        circle(contourImage, center, static_cast<int>(radius), Scalar(255, 255, 0), 2);

        // 在图像上标注几何特征
        putText(contourImage, "Area: " + to_string(static_cast<int>(area)),
            Point(boundingBox.x, boundingBox.y - 10), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 255), 1);
        putText(contourImage, "Perimeter: " + to_string(static_cast<int>(perimeter)),
            Point(boundingBox.x, boundingBox.y + boundingBox.height + 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 255), 1);
    }

    // 显示结果
    imshow("轮廓检测与几何特征", contourImage);
    waitKey(0);
    return 0;
}

代码简介

  1. 轮廓检测:使用 findContours 提取二值图像中的所有轮廓。
  2. 绘制轮廓:使用 drawContours 绘制检测到的轮廓。
  3. 计算几何特征
    • 面积和周长:使用 contourAreaarcLength 计算。
    • 重心:通过 moments 计算轮廓的中心点,并用 circle 绘制。
    • 最小外接矩形:使用 boundingRect 计算,并用 rectangle 绘制。
    • 最小外接圆:使用 minEnclosingCircle 计算,并用 circle 绘制。
  4. 标注特征信息:使用 putText 在图像上显示面积和周长。
  5. 面积筛选:代码中过滤不显示面积小于500的轮廓
    获取轮廓信息

4. 应用场景

轮廓检测技术在多个领域都有广泛应用,包括但不限于:

  • 目标分割和计数

    利用轮廓检测可以分割图像中的独立目标,并统计数量,如细胞计数、车牌识别等。

  • 形状分析

    分析轮廓的几何特征(如周长、面积、凸包、旋转角度等),用于目标识别和匹配。

  • 运动跟踪

    在视频处理中,通过检测运动目标的轮廓,进一步实现对象跟踪和行为分析。

  • OCR 前处理

    对文档图像进行轮廓检测,提取文字区域,为光学字符识别(OCR)提供准备工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值