c++ opencv 如何判断approxPolyDP近似折线形成的闭合区域的坐标点是内角点还是外角点;
approxPolyDP函数:
1)输出点集的顺序 和 输入点集的顺序 是一致的嘛?
2)输出点集 是 输入点集的 子集嘛?
3)approxPolyDP函数的算法原理深入理解;
注意,approxPolyDP函数的输出(即点到轮廓的距离或位置关系)与输入轮廓点集的顺序不一致,且不受其影响。
还有approxPolyDP输出点集是输入点集的子集吗?
approxPolyDP函数输出的点集是根据输入点集和逼近精度计算得到的,它可能包含与输入点集不同的点,因此不一定是输入点集的子集。
code
#include <opencv2/opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;
// 计算向量叉积
int crossProduct(Point a, Point b, Point c) {
Point v1 = {b.x - a.x, b.y - a.y};
Point v2 = {c.x - b.x, c.y - b.y};
return v1.x * v2.y - v1.y * v2.x;
}
// 判断角点类型
void detectCornerType(const vector<Point>& points) {
int n = points.size();
for (int i = 0; i < n; i++) {
int prev = (i > 0) ? i - 1 : n - 1;
int next = (i < n - 1) ? i + 1 : 0;
int cp = crossProduct(points[prev], points[i], points[next]);
if (cp > 0) {
cout << "内角点 at: " << points[i] << endl;
} else if (cp < 0) {
cout << "外角点 at: " << points[i] << endl;
} else {
cout << "直线点或平角点 at: " << points[i] << endl;
}
}
}
int main() {
// 加载图像
Mat img = imread("path_to_image");
// 转换为灰度图
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
// 二值化
Mat binary;
threshold(gray, binary, 100, 255, THRESH_BINARY);
// 查找轮廓
vector<vector<Point>> contours;
findContours(binary, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
// 近似多边形
vector<Point> approx;
approxPolyDP(contours[0], approx, arcLength(contours[0], true) * 0.02, true);
// 判断角点类型
detectCornerType(approx);
return 0;
}
View Code
在OpenCV中,可以通过检查顶点相对于其相邻点的方向来判断多边形的顶点是内角点还是外角点。
如果相邻顶点顺时针排列,则该顶点是外角点;如果逆时针排列,则该顶点是内角点。
code
#include <opencv2/opencv.hpp>
#include <vector>
// 检查顶点vertex相对于它的邻居neighbor的方向
bool isInternalAngle(const cv::Point& vertex, const cv::Point& neighbor, const cv::Point& nextNeighbor) {
cv::Point vec1 = neighbor - vertex;
cv::Point vec2 = nextNeighbor - vertex;
// 叉乘判断方向
double crossProduct = vec1.x * vec2.y - vec1.y * vec2.x;
// 如果叉乘结果为负,则neighbor在vertex的顺时针方向
// 如果为正,则neighbor在vertex的逆时针方向
return crossProduct < 0;
}
int main() {
std::vector<cv::Point> polygon = /* 多边形的顶点,例如:{{0,0}, {1,0}, {1,1}, {0,1}} */;
for (size_t i = 0; i < polygon.size(); ++i) {
size_t neighborIndex = (i + 1) % polygon.size();
size_t nextNeighborIndex = (i + 2) % polygon.size();
bool isInternal = isInternalAngle(polygon[i], polygon[neighborIndex], polygon[nextNeighborIndex]);
std::cout << "顶点 " << i << " 是" << (isInternal ? "内角" : "外角") << " 点。" << std::endl;
}
return 0;
}
View Code
判断内角点或外角点
遍历每个点:对于多边形上的每个点,考虑它的前一个点、当前点和后一个点。
计算向量:计算从当前点到前一个点的向量,以及从当前点到后一个点的向量。
计算叉积:计算这两个向量的叉积。叉积的符号(正或负)将告诉你角点的类型:
如果叉积为正,表示该角点是逆时针方向的转折,即外角点。
如果叉积为负,表示该角点是顺时针方向的转折,即内角点。
向量叉积的数值大小的意义
叉积的数值大小实际上表示了这两个向量构成的平行四边形的面积。在判断角点类型的上下文中,我们主要关心叉积的符号,而不是其绝对值。绝对值的大小提供了两个向量构成的平行四边形面积的大小,但在区分内角点和外角点时不重要。
和LJ确定,相邻三个顶点形成的三角形的质心(坐标均值)或者三角形是属于轮廓的,则中间的顶点为凸顶点,否则为凹顶点。