OpenCV.js 图像轮廓特征全解:cv.moments、轮廓面积、周长、凸包与最小外接拟合
OpenCV 的 imgproc 模块提供了一组围绕轮廓(contour)提取形状特征的核心 API,覆盖质心与矩、面积、周长、多边形逼近、凸包、包围盒以及直线/椭圆拟合等常用操作。本文以 OpenCV.js 官方教程 Contour Features(教程源文件)为主体,逐一讲解 cv.moments、cv.contourArea、cv.arcLength、cv.approxPolyDP、cv.convexHull 等 10 个函数的参数含义、使用方式与底层实现原理,读完即可在前端环境中对任意轮廓完成从特征提取到几何拟合的完整分析。
1. 矩(Moments):提取质心与面积的第一站
图像矩(Image Moments)是计算物体重心(center of mass)、面积等特征的基础数学工具。OpenCV 中对应函数为 cv.moments(array, binaryImage = false):
| 参数 | 说明 |
|---|---|
array |
光栅图像(单通道、8 位或浮点 2D 数组),或一个 2D 点数组(1×N 或 N×1) |
binaryImage |
为 true 时,图像中所有非零像素均按 1 处理。该参数仅对图像输入有效 |
函数返回一个 Moments 对象 M,其中包含 M.m00、M.m10、M.m01 等元素。质心(centroid)由矩的比值给出:
对应 JS 代码(继承自原文档示例):
let M = cv.moments(cnt, true);
let cx = M.m10 / M.m00;
let cy = M.m01 / M.m00;
官方提供的交互式演示页面 js_contour_features_moments.html 在浏览器中加载 OpenCV.js 后对输入图像调用该函数,实时显示计算出的矩与质心坐标,可直接在页面上验证上述公式。
2. 轮廓面积:cv.contourArea
轮廓面积可以直接由矩得到(即 M.m00),但 OpenCV 提供了专门的函数 cv.contourArea(contour, oriented = false):
| 参数 | 说明 |
|---|---|
contour |
输入 2D 点向量(轮廓顶点) |
oriented |
有向面积标志。为 true 时返回带符号的面积值,符号取决于轮廓方向(顺时针或逆时针),因此可通过面积符号判断轮廓的绕行方向;默认 false,返回面积的绝对值 |
交互式示例见 js_contour_features_area.html。从源码结构看,该函数与 moments、arcLength 等轮廓特征计算均实现于 imgproc 模块的 modules/imgproc/src/ 目录下,属于 C/C++ 内核能力,OpenCV.js 通过 JS 绑定层 将其暴露给浏览器端使用。
3. 轮廓周长(弧长):cv.arcLength
周长也称弧长(arc length),由 cv.arcLength(curve, closed) 计算:
| 参数 | 说明 |
|---|---|
curve |
输入 2D 点向量 |
closed |
标志位,指示曲线是否闭合。轮廓一般应传 true,否则首尾顶点之间的这段距离不会计入 |
交互式示例见 js_contour_features_perimeter.html。典型用法是 cv.arcLength(cnt, true),返回值是首尾相邻顶点间欧氏距离的累加。
4. 轮廓逼近:cv.approxPolyDP
cv.approxPolyDP(curve, approxCurve, epsilon, closed) 按指定精度将轮廓逼近为顶点更少的形状,其算法实现是 Douglas-Peucker(Ramer-Douglas-Peucker)折线简化算法:
| 参数 | 说明 |
|---|---|
curve |
存储 2D 点序列的输入(cv.Mat) |
approxCurve |
逼近结果,类型需与输入曲线一致 |
epsilon |
逼近精度参数,即原始曲线与其逼近之间的最大允许距离 |
closed |
为 true 时逼近后的曲线闭合(首尾顶点相连) |
epsilon 越小,逼近结果保留的细节越多、顶点越密集;epsilon 越大,轮廓被简化得越厉害。该算法在 OpenCV C++ 内核中的实现可参考 contours_approx.cpp。浏览器端交互演示见 js_contour_features_approxPolyDP.html。
一个常见的实战模式是:先 findContours,再对每个轮廓做 approxPolyDP,最后统计顶点数——三角形约 3 个、矩形 4 个,从而做多边形分类。
5. 凸包与凸性缺陷:cv.convexHull
凸包(Convex Hull)在外观上与轮廓逼近相似,但二者原理完全不同(个别情况下结果可能相同)。cv.convexHull(points, hull, clockwise = false, returnPoints = true) 会检查曲线的凸性缺陷并加以修正:
| 参数 | 说明 |
|---|---|
points |
输入 2D 点集 |
hull |
输出的凸包 |
clockwise |
方向标志。为 true 时输出顺时针方向的凸包,否则为逆时针。约定的坐标系 X 轴向右、Y 轴向上 |
returnPoints |
操作标志。当输出为矩阵时,true 返回凸包点本身,false 返回凸包点在输入点集中的索引 |
凸曲线总是向外凸出或至少是平的;向内凹陷的部分称为凸性缺陷(convexity defects),即凸包与轮廓之间的局部最大偏差。原文档以手部图像为例:红色折线勾勒出手的凸包,双向箭头标出的正是各指缝处的凸性缺陷。交互式示例见 js_contour_features_convexHull.html。
需要区分的是:cv.convexHull 负责“求出凸包”,而缺陷的深度分析(cv.convexityDefects)属于后续教程 More functions 的范畴,可在 同系列的 next 教程 之后继续查阅。
6. 检查凸性:cv.isContourConvex
判断一条曲线是否凸出,只需调用 cv.isContourConvex(contour),返回布尔值:
cv.isContourConvex(cnt); // true 或 false
原文档对此的评价是“很简单,没什么大不了的”——它正是轮廓过滤中最轻量的谓词,例如在目标检测后快速剔除严重退化的非凸碎片。
7. 包围盒(Bounding Rectangle)
OpenCV 提供两种包围矩形,适用于不同场景。
7.a. 轴对齐矩形:cv.boundingRect
cv.boundingRect(points)(points 为输入 2D 点集)返回一个与坐标轴平行的矩形。它不考虑物体旋转,因此其面积通常不是最小的。当物体基本正放时,它计算最快、语义最直观。交互演示:js_contour_features_boundingRect.html。
7.b. 旋转矩形:cv.minAreaRect
cv.minAreaRect(points) 返回面积最小的旋转包围盒(cv.RotatedRect),其中包含矩形中心、宽高等尺寸与旋转角度。当目标存在明显倾斜时,minAreaRect 给出的贴合度显著优于 boundingRect,常用于倾斜文档检测、倾斜矫正前的角度估计等。交互演示:js_contour_features_minAreaRect.html。
8. 最小外接圆:cv.minEnclosingCircle
cv.minEnclosingCircle(points) 求出一个能完全覆盖点集且面积最小的圆(circumcircle),返回圆心与半径。绘制时用 cv.circle(img, center, radius, color, thickness = 1, lineType = cv.LINE_8, shift = 0):
| 参数 | 说明 |
|---|---|
img |
绘制目标图像 |
center |
圆心 |
radius |
半径 |
color |
圆的颜色 |
thickness |
轮廓线宽;为负值时绘制实心圆 |
lineType |
圆边界的线型 |
shift |
圆心坐标与半径中的小数位数(fractional bits) |
交互演示:js_contour_features_minEnclosingCircle.html。最小外接圆在缺陷检测(判断零件近似度)、ROI 快速估计等场景中很常用。
9. 椭圆拟合:cv.fitEllipse
cv.fitEllipse(points) 对点集拟合椭圆,返回内接于一个旋转矩形的椭圆表示(cv.RotatedRect)。绘制使用 cv.ellipse(img, box, color, thickness = 1, lineType = cv.LINE_8):
| 参数 | 说明 |
|---|---|
img |
图像 |
box |
以 RotatedRect 表示的椭圆,函数绘制内接于该旋转矩形的椭圆 |
color |
椭圆颜色 |
thickness |
椭圆弧线线宽;为负值时绘制实心椭圆扇区 |
lineType |
椭圆边界线型 |
注意输入点集至少需要 5 个点,否则拟合无意义。交互演示:js_contour_features_fitEllipse.html。椭圆拟合典型用途包括:倾斜圆形目标的角度估计、镜头畸变下的圆形分析等。
10. 直线拟合:cv.fitLine
cv.fitLine(points, line, distType, param, reps, aeps) 对点集做直线最小二乘/鲁棒拟合:
| 参数 | 说明 |
|---|---|
points |
输入 2D 点集 |
line |
输出直线参数,4 元素的 Mat [vx, vy, x0, y0]:[vx, vy] 是共线单位向量,[x0, y0] 是线上一点 |
distType |
M-估计器使用的距离类型(见 cv.DistanceTypes,如 cv.DIST_L2、cv.DIST_L1、cv.DIST_HUBER、cv.DIST_FAIR) |
param |
部分距离类型的数值参数 C;为 0 时选取最优值 |
reps |
半径(坐标原点到直线的距离)的足够精度 |
aeps |
角度的足够精度 |
原文档建议 reps 与 aeps 的默认值取 0.01。绘制直线用 cv.line(img, pt1, pt2, color, thickness = 1, lineType = cv.LINE_8, shift = 0),其中 pt1、pt2 为线段端点,shift 为点坐标的小数位数。得到 [vx, vy, x0, y0] 后,可沿方向向量向两端延伸足够长度,构造 pt1 = (x0 - 100*vx, y0 - 100*vy)、pt2 = (x0 + 100*vx, y0 + 100*vy) 再调用 cv.line。交互演示:js_contour_features_fitLine.html。
源码层面:这些函数在 OpenCV 中的位置
- 上述轮廓特征 API 的 C++ 声明位于 imgproc 模块头文件 imgproc.hpp,实现集中于 modules/imgproc/src/(其中
contours_approx.cpp承载了approxPolyDP等多边形逼近相关实现,contours_*.cpp系列则是轮廓查找内核)。 - OpenCV.js 并不是重新实现这些算法,而是通过 WASM 将同一套 C++ 内核编译到浏览器。绑定与加载逻辑可参考 core_bindings.cpp 与 loader.js,因此浏览器端教程中的每个“Try it”页面都运行与桌面版一致的算法代码。
- 同一套 API 在 Python 教程中有平行版本,参数说明完全一致(
cv2.moments、cv2.contourArea、cv2.approxPolyDP等),可对照 py_contour_features.markdown 学习,便于前后端代码互译。
参数速查表
| 函数 | 输入 | 关键输出 | 适用场景 |
|---|---|---|---|
cv.moments |
单通道图像或点集,binaryImage 标志 |
各阶矩;质心 = m10/m00、m01/m00 |
质心、面积、形状矩 |
cv.contourArea |
轮廓点集,oriented 标志 |
面积(可带符号) | 轮廓大小、方向判断 |
cv.arcLength |
曲线点集,closed 标志 |
周长 | 圆度、边界复杂度 |
cv.approxPolyDP |
曲线、epsilon、closed |
简化后的多边形 | 形状分类、降噪 |
cv.convexHull |
点集、clockwise、returnPoints |
凸包点或索引 | 缺陷分析、外形包络 |
cv.isContourConvex |
轮廓 | 布尔值 | 快速过滤 |
cv.boundingRect |
点集 | 轴对齐矩形 | 快速 ROI |
cv.minAreaRect |
点集 | 最小旋转矩形 | 倾斜目标定位 |
cv.minEnclosingCircle |
点集 | 圆心 + 半径 | 圆形 ROI、近似度判断 |
cv.fitEllipse |
点集(≥5 点) | RotatedRect 表示的椭圆 | 角度估计 |
cv.fitLine |
点集 + M-估计器参数 | [vx, vy, x0, y0] |
边缘/直线提取 |
小结
本文覆盖的 10 个函数构成了 OpenCV 轮廓特征提取的标准工具箱:矩负责描述性统计,contourArea/arcLength 给出尺度特征,approxPolyDP 做形状简化,convexHull 与 isContourConvex 处理凸性,boundingRect/minAreaRect/minEnclosingCircle 提供三类包围几何,fitEllipse/fitLine 完成参数化拟合。所有函数在 OpenCV.js 中的行为与桌面版 C++/Python API 一一对应,交互式演示页面(js_assets 目录 下的 js_contour_features_*.html)可直接在浏览器中打开验证,是学习轮廓特征最快捷的路径。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0626
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00