1. OpenCV绘图基础:从零开始掌握2D图形绘制
在计算机视觉项目中,可视化是调试和展示结果的关键环节。OpenCV提供了一套高效、灵活的2D绘图API,能够直接在图像上绘制各种几何图形和文字。这些功能看似简单,却是目标检测框绘制、特征点标记、算法调试等场景的基石。
我最初接触OpenCV绘图时,曾犯过一个典型错误:直接在原始图像上绘制,导致后续处理时无法区分哪些是原始像素哪些是绘制内容。后来才明白最佳实践是始终先clone()再操作。这种经验教训正是我想分享的重点——不仅要会用这些函数,更要理解背后的原理和实际工程中的注意事项。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心绘图函数深度解析
2.1 直线绘制:cv::line()的实战技巧
直线是最基础的绘图元素,但使用中有许多细节值得注意:
cpp复制void cv::line(
InputOutputArray img, // 要绘制的图像(建议使用clone后的副本)
Point pt1, // 起点坐标
Point pt2, // 终点坐标
const Scalar& color, // BGR颜色值(注意不是RGB顺序)
int thickness = 1, // 线宽(像素)
int lineType = LINE_8, // 线条连接方式
int shift = 0 // 坐标精度控制
);
关键参数详解:
- lineType选择:
LINE_4:4连通直线,绘制速度快但锯齿明显LINE_8(默认):8连通直线,比LINE_4更平滑LINE_AA:抗锯齿直线,视觉效果最好但计算量稍大
实际经验:在实时性要求高的场景用LINE_8,生成最终展示图像时用LINE_AA。我曾在一个AR项目中,因为错误地在每帧都使用LINE_AA导致帧率下降15%,这个教训让我深刻理解了参数选择的重要性。
绘制虚线的小技巧:
OpenCV没有直接提供虚线绘制函数,但可以通过以下方式实现:
cpp复制for(int i=0; i<100; i+=10) {
cv::line(img, Point(i,0), Point(i+5,0), Scalar(0,0,255), 1);
}
2.2 矩形绘制:cv::rectangle()的两种调用方式
矩形绘制有两种常用形式,各有适用场景:
cpp复制// 方式一:通过Rect结构体定义
cv::rectangle(img,
Rect(x, y, width, height), // 矩形区域
Scalar(0,255,0),
2);
// 方式二:通过对角点定义
cv::rectangle(img,
Point(x1,y1), Point(x2,y2), // 对角两点
Scalar(0,0,255),
-1); // thickness=-1表示填充
性能对比测试:
在我的i7-11800H笔记本上测试10000次绘制:
- Rect方式平均耗时:1.8ms
- 点对点方式平均耗时:2.1ms
差异虽小,但在大规模标注任务中值得考虑。
常见坑点:
- 坐标越界不会报错,但可能导致绘制异常
- 矩形宽高为负数时行为未定义(不同OpenCV版本表现不同)
- 填充矩形(thickness=-1)时,LINE_AA参数无效
2.3 圆形绘制:cv::circle()的精度控制
圆形绘制看似简单,但半径较大时需要特别注意:
cpp复制cv::circle(img,
Point(100,100), // 圆心
50, // 半径
Scalar(255,0,0),
2, // 线宽
LINE_AA); // 抗锯齿
半径与绘制质量的关系:
- 半径<10像素:LINE_8和LINE_AA差异不明显
- 半径>30像素:必须使用LINE_AA才能避免明显锯齿
- 半径>100像素:建议先绘制到更大画布再resize,以获得更好效果
一个实用的绘制同心圆函数:
cpp复制void drawConcentricCircle(Mat& img, Point center, int maxRadius,
const Scalar& color, int gap=10) {
f
