函数概述
arcLength是OpenCV中用于计算轮廓或曲线长度的函数。它可以计算轮廓的周长或者任意曲线的长度。
函数原型
cpp
double arcLength(InputArray curve, bool closed)
参数说明
-
curve:输入的点集,可以是向量或Mat
-
通常是通过
findContours找到的轮廓点 -
数据类型:
vector<Point>或vector<Point2f>
-
-
closed:标志位,指示曲线是否闭合
-
true:假设曲线是闭合的(计算周长) -
false:假设曲线是开放的(计算长度)
-
返回值
- 返回曲线的长度(双精度浮点数)
工作原理
arcLength通过计算连续点之间的欧几里得距离来工作:
-
闭合曲线:计算所有相邻点之间的距离,包括最后一个点到第一个点的距离
-
开放曲线:只计算相邻点之间的距离,不连接首尾点
数学公式:
cpp
长度 = Σ√[(xᵢ₊₁ - xᵢ)² + (yᵢ₊₁ - yᵢ)²]
使用示例
示例1:计算轮廓周长
cpp
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
using namespace cv;
using namespace std;
int main() {
// 创建一个黑色图像
Mat image = Mat::zeros(400, 400, CV_8UC1);
// 画一个矩形
rectangle(image, Point(50, 50), Point(200, 150), Scalar(255), 2);
// 查找轮廓
vector<vector<Point>> contours;
findContours(image, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
if (!contours.empty()) {
// 计算轮廓周长
double perimeter = arcLength(contours[0], true);
cout << "轮廓周长: " << perimeter << " 像素" << endl;
// 在图像上绘制轮廓
Mat result;
cvtColor(image, result, COLOR_GRAY2BGR);
drawContours(result, contours, 0, Scalar(0, 255, 0), 2);
// 显示结果
putText(result, "Perimeter: " + to_string(perimeter),
Point(10, 30), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(0, 0, 255), 2);
imshow("轮廓周长计算", result);
waitKey(0);
}
return 0;
}
示例2:计算多边形面积与周长比
cpp
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
using namespace cv;
using namespace std;
int main() {
// 创建一个黑色图像
Mat image = Mat::zeros(400, 400, CV_8UC3);
// 定义一个多边形
vector<Point> polygon = {
Point(100, 100), Point(200, 50), Point(300, 100),
Point(250, 200), Point(150, 250), Point(50, 200)
};
// 在图像上绘制多边形
vector<vector<Point>> contours = {polygon};
drawContours(image, contours, 0, Scalar(255, 0, 0), -1); // 填充
// 计算周长和面积
double perimeter = arcLength(polygon, true);
double area = contourArea(polygon);
// 计算紧凑度(周长²/面积)
double compactness = (perimeter * perimeter) / area;
cout << "多边形信息:" << endl;
cout << "周长: " << perimeter << " 像素" << endl;
cout << "面积: " << area << " 像素²" << endl;
cout << "紧凑度: " << compactness << endl;
// 显示信息
putText(image, "Perimeter: " + to_string(int(perimeter)),
Point(10, 30), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(255, 255, 255), 2);
putText(image, "Area: " + to_string(int(area)),
Point(10, 60), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(255, 255, 255), 2);
putText(image, "Compactness: " + to_string(int(compactness)),
Point(10, 90), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(255, 255, 255), 2);
imshow("多边形分析", image);
waitKey(0);
return 0;
}
示例3:形状识别应用
cpp
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
using namespace cv;
using namespace std;
void detectAndClassifyShapes(Mat& image) {
Mat gray, binary;
cvtColor(image, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 127, 255, THRESH_BINARY);
vector<vector<Point>> contours;
findContours(binary, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
for (size_t i = 0; i < contours.size(); i++) {
// 计算周长和面积
double perimeter = arcLength(contours[i], true);
double area = contourArea(contours[i]);
// 计算圆形度
double circularity = 4 * CV_PI * area / (perimeter * perimeter);
// 根据圆形度分类形状
string shapeType;
Scalar color;
if (circularity > 0.85) {
shapeType = "Circle";
color = Scalar(0, 255, 0); // 绿色
} else if (circularity > 0.7) {
shapeType = "Square";
color = Scalar(0, 0, 255); // 红色
} else {
shapeType = "Irregular";
color = Scalar(255, 0, 0); // 蓝色
}
// 绘制轮廓和标签
drawContours(image, contours, i, color, 2);
// 计算中心点
Moments m = moments(contours[i]);
Point center(m.m10 / m.m00, m.m01 / m.m00);
// 显示形状信息
string info = shapeType + " C:" + to_string(circularity).substr(0, 4);
putText(image, info, center, FONT_HERSHEY_SIMPLEX, 0.5, color, 2);
}
}
int main() {
// 创建一个包含不同形状的图像
Mat image = Mat::zeros(400, 600, CV_8UC3);
// 绘制各种形状
circle(image, Point(100, 100), 50, Scalar(255, 255, 255), -1);
rectangle(image, Point(200, 50), Point(300, 150), Scalar(255, 255, 255), -1);
vector<Point> triangle = {Point(400, 50), Point(350, 150), Point(450, 150)};
fillConvexPoly(image, triangle, Scalar(255, 255, 255));
// 检测和分类形状
detectAndClassifyShapes(image);
imshow("形状识别", image);
waitKey(0);
return 0;
}
实际应用场景
1. 轮廓分析与形状识别
-
计算轮廓的周长用于形状特征提取
-
结合
contourArea计算形状的紧凑度、圆形度等特征
2. 图像测量与尺寸计算
cpp
// 实际尺寸测量(需要标定)
double pixelToMM = 0.1; // 假设1像素=0.1mm
double realWorldLength = perimeter * pixelToMM;
3. 轮廓近似
cpp
// 使用周长进行轮廓近似
vector<Point> approx;
double epsilon = 0.02 * perimeter; // 基于周长的近似精度
approxPolyDP(contour, approx, epsilon, true);
4. 运动分析与跟踪
cpp
// 跟踪物体尺寸变化
vector<Point> previousContour, currentContour;
double lengthChange = arcLength(currentContour, true) - arcLength(previousContour, true);
注意事项
-
精度问题:
-
对于浮点坐标(
Point2f),计算更精确 -
对于整数坐标(
Point),存在量化误差
-
-
轮廓质量:
-
轮廓点应该有序排列
-
噪声会影响长度计算的准确性
-
-
闭合标志:
-
确保正确设置
closed参数 -
闭合轮廓通常用于计算周长
-
开放曲线用于计算路径长度
-
-
性能考虑:
-
对于复杂轮廓,计算可能较慢
-
可先对轮廓进行近似以提高性能
-