OpenCV C++ 学习笔记(六):绘制文本、几何绘图、查找/绘制轮廓

文章目录


绘制文字putText()

cpp 复制代码
void cv::putText(
    Mat& img,              // 目标图像
    const string& text,    // 待绘制的文本字符串
    Point org,             // 文本字符串左下角所在位置
    int fontFace,          // 字体类型
    double fontScale,      // 字体缩放系数(相对于默认大小)
    Scalar color,          // 文本颜色 (B,G,R)
    int thickness = 1,     // 线条宽度
    int lineType = LINE_8, // 线型
    bool bottomLeftOrigin = false // 当值为 true 时,原点位于左下角,否则在左上角
);

/** @brief Draws a text string.

The function cv::putText renders the specified text string in the image. Symbols that cannot be rendered
using the specified font are replaced by question marks. See #getTextSize for a text rendering code
example.

@param img Image.
@param text Text string to be drawn.
@param org Bottom-left corner of the text string in the image.
@param fontFace Font type, see #HersheyFonts.
@param fontScale Font scale factor that is multiplied by the font-specific base size.
@param color Text color.
@param thickness Thickness of the lines used to draw a text.
@param lineType Line type. See #LineTypes
@param bottomLeftOrigin When true, the image data origin is at the bottom-left corner. Otherwise,
it is at the top-left corner.
 */
  • img: 输入/输出图像,即要在其上绘制文字的图像。
  • text: 要绘制的文本字符串。
  • org: 指定文本起始点的坐标。这个点是文本字符串中第一个字符的左下角(如果 bottomLeftOrigin=false)或者左上角(如果 bottomLeftOrigin=true)的位置。
  • fontFace: 字体类型,支持以下几种:
    • FONT_HERSHEY_SIMPLEX, FONT_HERSHEY_PLAIN
    • FONT_HERSHEY_DUPLEX, FONT_HERSHEY_COMPLEX
    • FONT_HERSHEY_TRIPLEX, FONT_HERSHEY_COMPLEX_SMALL
    • FONT_HERSHEY_SCRIPT_SIMPLEX, FONT_HERSHEY_SCRIPT_COMPLEX
  • fontScale: 字体的比例因子。可以根据需要放大或缩小字体大小。
  • color: 字体颜色,使用 Scalar 对象表示,格式为 (B, G, R)。
  • thickness: 字体线条的厚度。默认值为 1。
  • lineType: 线条类型。通常使用 LINE_8LINE_AA(抗锯齿)。LINE_4 和 LINE_AA 也是可选项。
  • bottomLeftOrigin: 如果此参数设置为 true,则文本的原点将位于左下角;否则,默认情况下,它位于左上角。
cpp 复制代码
cv::Mat image = cv::Mat::zeros(cv::Size(300, 300), CV_8UC3);

// 定义文本和字体属性
std::string text = "Hello, OpenCV!";
cv::Point position(50, 150); // 文字起始位置
int fontFace = cv::FONT_HERSHEY_SIMPLEX;
double fontScale = 1.0; // 字体大小
int thickness = 2; // 字体线条厚度

// 在图像上绘制文本
cv::putText(image, text, position, fontFace, fontScale, cv::Scalar(255, 0, 0), thickness);

// 显示结果图像
cv::imshow("Image with Text", image);

绘制直线line()

cpp 复制代码
void cv::line(
    Mat& img,              // 目标图像
    Point pt1,             // 直线起点
    Point pt2,             // 直线终点
    const Scalar& color,   // 线条颜色 (B,G,R)
    int thickness = 1,     // 线条宽度,默认为1
    int lineType = LINE_8, // 线型,默认为8连通
    int shift = 0          // 坐标点的小数位数,默认为0
);
  • lineType: 线条类型,可以选择以下几种之一:
    • LINE_4: 4连通线段。
    • LINE_8: 8连通线段(默认)。
    • LINE_AA: 抗锯齿线段,提供更平滑的效果。
cpp 复制代码
cv::Mat image = cv::Mat::zeros(cv::Size(300, 300), CV_8UC3);

// 定义直线的起点和终点
cv::Point startPoint(50, 50);
cv::Point endPoint(250, 250);

// 定义线条的颜色和粗细
cv::Scalar lineColor(0, 255, 0); // 绿色
int thickness = 2;               // 粗细为2个像素
int lineType = cv::LINE_AA;      // 使用抗锯齿线条

// 在图像上绘制直线
cv::line(image, startPoint, endPoint, lineColor, thickness, lineType);

绘制矩形rectangle()

cpp 复制代码
void cv::rectangle(
    Mat& img,                      // 输入/输出图像
    Point pt1,                     // 矩形左上角坐标
    Point pt2,                     // 矩形右下角坐标
    const Scalar& color,           // 颜色 (B, G, R)
    int thickness = 1,             // 线条粗细,默认为1
    int lineType = LINE_8,         // 线型,默认为LINE_8
    int shift = 0                  // 坐标精度位数,默认为0
);

void cv::rectangle(
    Mat& img,
    Rect rec,                      // 使用 Rect 定义矩形区域
    const Scalar& color,
    int thickness = 1,
    int lineType = LINE_8,
    int shift = 0
);
cpp 复制代码
cv::Mat image = cv::Mat::zeros(cv::Size(300, 300), CV_8UC3); // 黑色背景图

cv::Point topLeft(50, 50);
cv::Point bottomRight(250, 250);

cv::rectangle(image, topLeft, bottomRight, cv::Scalar(0, 255, 0), 2, cv::LINE_AA);

// 或
cv::rectangle(image, cv::Rect(50, 50, 200, 200), cv::Scalar(255, 0, 0), 2);

// 绘制实心矩形(填充)
cv::rectangle(image, cv::Rect(50, 50, 100, 100), cv::Scalar(0, 0, 255), cv::FILLED);

使用 thickness=cv::FILLED-1 实现实心效果。

绘制圆circle()

cpp 复制代码
void cv::circle(
    Mat& img,                     // 输入/输出图像阵列,可以是8位或32位浮点型。
    Point center,                 // 圆心坐标 (x, y)。
    int radius,                   // 圆的半径。
    const Scalar& color,          // 圆的颜色。在BGR格式下表示为Scalar(blue, green, red)。
    int thickness = 1,            // 组成圆的线条的粗细程度。如果为负值,例如 FILLED,则会填充圆形内部。
    int lineType = LINE_8,        // 圆边界的类型。默认是8连接线。
    int shift = 0                 // 圆心坐标和半径值的小数位数。
);

thickness 正值表示绘制空心圆,而负值(如 FILLED)则表示绘制实心圆。

cpp 复制代码
cv::Mat image = cv::Mat::zeros(cv::Size(600, 400), CV_8UC3);

// 定义圆心位置和半径
cv::Point center = cv::Point(300, 200); // 圆心位于图像中央
int radius = 100; // 半径为100像素

// 绘制红色的实心圆
cv::circle(image, center, radius, cv::Scalar(0, 0, 255), -1, cv::LINE_AA);

绘制椭圆或部分弧线ellipse()

cpp 复制代码
void cv::ellipse(
    Mat& img,                         // 输入/输出图像阵列,可以是8位或32位浮点型。
    Point center,                     // 椭圆中心的位置 (x, y)。
    Size axes,                        // 椭圆主轴和次轴的长度。
    double angle,                     // 椭圆相对于x轴旋转的角度(以度为单位)。
    double startAngle,                // 椭圆弧起始角度(以度为单位)。
    double endAngle,                  // 椭圆弧结束角度(以度为单位)。
    const Scalar& color,              // 椭圆的颜色。在BGR格式下表示为Scalar(blue, green, red)。
    int thickness = 1,                // 组成椭圆的线条的粗细程度。如果为负值,例如 FILLED,则会填充椭圆内部。
    int lineType = LINE_8,            // 椭圆边界的类型。默认是8连接线。
    int shift = 0                     // 中心坐标和轴数值的小数位数。
);
cpp 复制代码
cv::Mat image = cv::Mat::zeros(cv::Size(600, 400), CV_8UC3);

// 定义椭圆中心位置、轴长和旋转角度
cv::Point center(300, 200); // 椭圆中心位于图像中央
cv::Size axes(100, 50);     // 椭圆的主轴和次轴长度
double angle = 30;          // 相对x轴顺时针旋转30度
double startAngle = 0;      // 椭圆弧起始角度
double endAngle = 360;      // 椭圆弧结束角度

// 绘制蓝色的空心椭圆
cv::ellipse(image, center, axes, angle, startAngle, endAngle, cv::Scalar(255, 0, 0), 2, cv::LINE_AA);

绘制多边形/折线polylines()

cpp 复制代码
void cv::polylines(
    Mat& img,                         // 输入/输出图像阵列,可以是8位或32位浮点型。
    const Point* pts,                 // 指向要绘制的多边形顶点数组的指针。
    const vector<Point>& pts,         // 或者使用Point类型的vector容器代替。
    bool isClosed,                    // 标志表示所绘制的折线是否闭合。如果为true,则连接最后一个点与第一个点。
    const Scalar& color,              // 多边形的颜色。在BGR格式下表示为Scalar(blue, green, red)。
    int thickness = 1,                // 组成多边形的线条的粗细程度。默认值为1。
    int lineType = LINE_8,            // 线段端点的类型。可选值有LINE_4, LINE_8 (default), LINE_AA(抗锯齿)。
    int shift = 0                     // 顶点坐标的小数位数。默认值为0。
);

// 更常用的重载版本接受一个 vector<vector<Point>> 类型的参数,以便一次绘制多个轮廓

void cv::polylines(
    Mat& img,                                 // 输入/输出图像阵列,可以是8位或32位浮点型。
    const vector<vector<Point>>& pts,        // 包含每个多边形或折线顶点集合的vector容器。
    bool isClosed,                           // 标志表示所绘制的折线是否闭合。如果为true,则每个轮廓的最后一个点与第一个点相连。
    const Scalar& color,                     // 多边形的颜色。在BGR格式下表示为Scalar(blue, green, red)。
    int thickness = 1,                       // 组成多边形的线条的粗细程度。默认值为1。
    int lineType = LINE_8,                   // 线段端点的类型。可选值有LINE_4, LINE_8 (default), LINE_AA(抗锯齿)。
    int shift = 0                            // 顶点坐标的小数位数。默认值为0。
);
cpp 复制代码
cv::Mat image = cv::Mat::zeros(cv::Size(600, 400), CV_8UC3);

// 定义多边形顶点
std::vector<std::vector<cv::Point>> contours;
contours.push_back({{100, 100}, {150, 50}, {200, 100}}); // 三角形
contours.push_back({{300, 200}, {350, 150}, {400, 200}, {350, 250}}); // 四边形

// 绘制蓝色的闭合多边形
cv::polylines(image, contours, true, cv::Scalar(255, 0, 0), 2, cv::LINE_AA);

填充多边形fillPoly()

cpp 复制代码
void cv::fillPoly(
    Mat& img,                                // 输入/输出图像阵列,可以是8位或32位浮点型。
    const Point** pts,                       // 指向要填充的多边形顶点数组的指针。
    const vector<Point>& pts,                // 或者使用Point类型的vector容器代替。
    const vector<vector<Point>>& pts,        // 包含每个多边形顶点集合的vector容器。
    const int npts[],                        // 每个多边形顶点数的数组。
    int contours,                            // 要绘制的多边形数量。
    const Scalar& color,                     // 多边形的颜色。在BGR格式下表示为Scalar(blue, green, red)。
    int lineType = LINE_8,                   // 线段端点的类型。可选值有LINE_4, LINE_8 (default), LINE_AA(抗锯齿)。
    int shift = 0                            // 顶点坐标的小数位数。默认值为0。
);

void cv::fillPoly(
    Mat& img,                                // 输入/输出图像阵列,可以是8位或32位浮点型。
    const vector<vector<Point>>& pts,        // 包含每个多边形或折线顶点集合的vector容器。
    const Scalar& color,                     // 多边形的颜色。在BGR格式下表示为Scalar(blue, green, red)。
    int lineType = LINE_8,                   // 线段端点的类型。可选值有LINE_4, LINE_8 (default), LINE_AA(抗锯齿)。
    int shift = 0,                           // 顶点坐标的小数位数。默认值为0。
    Point offset = Point()                   // 可选的偏移量,应用于所有顶点。
);
cpp 复制代码
cv::Mat image = cv::Mat::zeros(cv::Size(600, 400), CV_8UC3);

// 定义多边形顶点
std::vector<std::vector<cv::Point>> contours;
contours.push_back({{100, 100}, {150, 50}, {200, 100}}); // 三角形
contours.push_back({{300, 200}, {350, 150}, {400, 200}, {350, 250}}); // 四边形

// 填充红色的三角形和蓝色的四边形
cv::fillPoly(image, contours, cv::Scalar(0, 0, 255), cv::LINE_8, 0, cv::Point());
cv::fillPoly(image, contours, cv::Scalar(255, 0, 0), cv::LINE_8, 0, cv::Point(200, 100)); // 注意第二个图形需要调整偏移以避免覆盖第一个图形

查找轮廓findContours()

用于在二值图像中查找轮廓。轮廓可以简单地理解为连接具有相同颜色或强度的所有连续点(沿着边界)的曲线。它常被用于形状分析、对象检测和识别等领域。

cpp 复制代码
void cv::findContours(
    InputOutputArray image, // 输入/输出图像,必须是二值图像,非零像素被视为1,0像素保持不变。
    OutputArrayOfArrays contours, // 检测到的轮廓,每个轮廓存储为一个点向量。
    OutputArray hierarchy, // 可选输出变量,包含图像拓扑信息的向量。
    int mode, // 轮廓检索模式。
    int method, // 轮廓近似方法。
    Point offset = Point() // 可选偏移量,指定每个轮廓点的可选增量。
);
  • image: 输入的单通道、8位二值图像。在函数执行过程中,这个图像可能会被修改。为了保留原图,建议传入图像的副本。
  • contours: 输出参数,存储所有找到的轮廓。每个轮廓是一个点(x,y坐标)的列表,这些点定义了轮廓的形状。
  • hierarchy: 输出参数,每个轮廓对应的层次结构信息。每个轮廓都有一个与之关联的信息:下一个轮廓、前一个轮廓、第一个子轮廓和父轮廓的索引。
  • mode: 轮廓检索模式,决定了函数如何检索轮廓:
    • RETR_EXTERNAL: 只检索最外层的轮廓。
    • RETR_LIST: 检索所有轮廓并将它们组成一个没有层次结构的列表。
    • RETR_CCOMP: 检索所有轮廓并将它们组织成两级结构:顶层为连通域,第二层为孔洞。
    • RETR_TREE: 检索所有轮廓并重建嵌套轮廓的完整层级结构。
  • method: 轮廓近似方法,指定了如何近似轮廓:
    • CHAIN_APPROX_NONE: 将轮廓中的所有点都存储下来,不进行压缩。
    • CHAIN_APPROX_SIMPLE: 压缩水平、垂直和对角线方向上的点,仅保留它们的端点。
    • CHAIN_APPROX_TC89_L1, CHAIN_APPROX_TC89_KCOS: 使用Teh-Chin链逼近算法的一种。
  • offset: 可选参数,指定轮廓点的增量。对于ROI处理非常有用。

绘制轮廓drawContours()

cpp 复制代码
void cv::drawContours(
    Mat& image,                        // 输入/输出图像
    const vector<vector<Point>>& contours,  // 轮廓列表(由 findContours 提取)
    int contourIdx,                    // 要绘制的轮廓索引(-1 表示全部绘制)
    const Scalar& color,              // 轮廓颜色 (B, G, R)
    int thickness = 1,                // 线宽或填充标志
    int lineType = LINE_8,            // 线型:LINE_4 / LINE_8 / LINE_AA
    const vector<Vec4i>& hierarchy = vector<Vec4i>(), // 可选的层级结构
    int maxLevel = INT_MAX,           // 绘制的最大层级(配合 hierarchy 使用)
    Point offset = Point()            // 可选偏移量,平移所有轮廓点
);
  • image 输入/输出图像,轮廓会直接绘制在该图像上
  • contours 轮廓列表,是一个 vector<vector<cv::Point>> 类型
  • contourIdx 指定要绘制的第几个轮廓,从0开始计数;设为 -1 表示绘制所有轮廓
  • color 轮廓的颜色,使用 Scalar(B, G, R) 格式指定
  • thickness 线条粗细。若为负值(如 cv::FILLED),则填充轮廓内部
  • lineType 线型类型,推荐使用 LINE_AA(抗锯齿)
  • hierarchy 层级结构,与 findContours 返回的层级结构一致
  • maxLevel 最大绘制层级,用于控制嵌套轮廓的绘制深度
  • offset 偏移量,可对所有轮廓点进行整体位移
cpp 复制代码
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
    Mat src = imread("path_to_image", IMREAD_COLOR);
    if (src.empty()) {
        cout << "Could not open or find the image" << endl;
        return -1;
    }

    Mat gray, binary;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    threshold(gray, binary, 128, 255, THRESH_BINARY);

    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);

    // 绘制轮廓
    Mat drawing = Mat::zeros(binary.size(), CV_8UC3);
    for (size_t i = 0; i < contours.size(); i++) {
        Scalar color = Scalar(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
        drawContours(drawing, contours, (int)i, color, 2, LINE_8, hierarchy, 0);
    }

    imshow("Contours", drawing);
    waitKey(0);
    return 0;
}

首先读取一张图片,并将其转换为灰度图,然后通过阈值处理得到二值图像。接着使用 findContours 在二值图像中查找轮廓,并将这些轮廓drawContours()绘制在一个新的图像上。

cpp 复制代码
// 只绘制第一个轮廓
cv::drawContours(src, contours, 0, cv::Scalar(255, 0, 0), 2); // 蓝色轮廓
cpp 复制代码
// 填充所有轮廓
cv::drawContours(src, contours, -1, cv::Scalar(0, 255, 0), cv::FILLED);
cpp 复制代码
// 只绘制最外层轮廓(层级为0)
cv::drawContours(src, contours, -1, cv::Scalar(255, 0, 0), 2, cv::LINE_AA, hierarchy, 0);
  • 如果只想显示某个对象的轮廓,可以结合掩膜(mask)操作。
  • 若想绘制带透明度的轮廓,可以使用 addWeighted() 实现半透明效果。
相关推荐
Lenyiin2 小时前
《 C++ 点滴漫谈: 四十 》文本的艺术:C++ 正则表达式的高效应用之道
c++·正则表达式·lenyiin
yxc_inspire4 小时前
基于Qt的app开发第十三天
c++·qt·app·tcp·面向对象
jndingxin4 小时前
OPenCV CUDA模块目标检测----- HOG 特征提取和目标检测类cv::cuda::HOG
人工智能·opencv·目标检测
虾球xz4 小时前
CppCon 2015 学习:Concurrency TS Editor’s Report
开发语言·c++·学习
潇-xiao4 小时前
Qt 按钮类控件(Push Button 与 Radio Button)(1)
c++·qt
板鸭〈小号〉4 小时前
命名管道实现本地通信
开发语言·c++
清醒的兰5 小时前
OpenCV 图像像素的逻辑操作
人工智能·opencv·计算机视觉
YKPG6 小时前
C++学习-入门到精通【14】标准库算法
c++·学习·算法
zm6 小时前
极限复习c++
开发语言·c++
程序猿本员7 小时前
线程池精华
c++·后端