OpenCV坐标计算辅助,其它情况可修改数点(cv::Point)数据类型以适用。
用于一些坐标计算的辅助类,算法来源于初高中数学老师和互联网,后期整理出处。
头信息
#include <vector>
#include <opencv2/core/types.hpp>
namespace CVG {
...
}
角度(三点两线段角度计算)
/**
角度
@param pt1 端点
@param pt2 端点
@param pt0 交点
@return 角度
*/
double CVG::angle(cv::Point pt1, cv::Point pt2, cv::Point pt0) {
double dx1 = pt1.x - pt0.x;
double dy1 = pt1.y - pt0.y;
double dx2 = pt2.x - pt0.x;
double dy2 = pt2.y - pt0.y;
return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}
中心点(线段中心点)
/**
中心点
@param pt0 端点
@param pt1 端点
@return 端点
*/
cv::Point CVG::center(cv::Point pt0, cv::Point pt1) {
cv::Point pt;
pt.x = (pt0.x+pt1.x)/2 + 0.5;
pt.y = (pt0.y+pt1.y)/2 + 0.5;
return pt;
}
距离(线段长度)
/**
距离长度
@param pt0 端点
@param pt1 端点
@return 距离长度
*/
double CVG::length( cv::Point pt0, cv::Point pt1) {
double dist_x = pt0.x - pt1.x;
double dist_y = pt0.y - pt1.y;
return sqrt(pow(dist_x, 2)+pow(dist_y, 2));
}
多边形中心点(重心)
/**
多边形中心点
@param pts 多边形坐标,环形分布
@return 中心点
*/
cv::Point CVG::center(std::vector<cv::Point> &pts) {
long n = pts.size();
cv::Point pt_c;
if (n==0) {
return pt_c;
}
long sum_x = 0, sum_y = 0;
for (int i = 0; i < n; i ++) {
cv::Point pt = pts[i];
sum_x += pt.x;
sum_y += pt.y;
}
pt_c.x = (int)(sum_x / n + 0.5);
pt_c.y = (int)(sum_y / n + 0.5);
return pt_c;
}
两线段交点(不存在返回极大值点)
/**
两线段交点
@param l0p0 线段0端点
@param l0p1 线段0端点
@param l1p0 线段1端点
@param l1p1 线段1端点
@return 交点
*/
cv::Point CVG::intersects(cv::Point l0p0, cv::Point l0p1, cv::Point l1p0, cv::Point l1p1) {
int delta, r, u;
cv::Point p;//交点
delta = (l0p1.x - l0p0.x) * (l1p0.y - l1p1.y) - (l1p0.x - l1p1.x) * (l0p1.y - l0p0.y);
if(delta == 0) {
p.x = INT_MAX;
p.y = INT_MAX;
} else {
r = ((l1p0.x - l0p0.x) * (l1p0.y - l1p1.y) - (l1p0.x - l1p1.x) * (l1p0.y - l0p0.y)) / delta;
u = ((l0p1.x - l0p0.x) * (l1p0.y - l0p0.y) - (l1p0.x - l0p0.x) * (l0p1.y - l0p0.y)) / delta;
if((r >= 0 && r <= 1) && (u >= 0 && u <= 1)) {
p.x = l0p0.x + r*(l0p1.x - l0p0.x);
p.y = l0p0.y + r*(l0p1.y - l0p0.y);
} else {
p.x = INT_MAX;
p.y = INT_MAX;
}
}
return p;
}
线段延长点(from 到 to方向上扩张dist距离,返回新的to坐标)
/**
线段延长点
@param from 线段开始
@param to 线段结束
@param dist 延长距离
@return 新的结束点
*/
cv::Point CVG::lineExp(cv::Point from, cv::Point to, double dist) {
double dist_x = to.x - from.x;
double dist_y = to.y - from.y;
double s = dist/sqrt(pow(dist_x, 2)+pow(dist_y, 2))+1;
cv::Point p;
p.x = s*(dist_x)+from.x;
p.y = s*(dist_y)+from.y;
return p;
}
多边形扩张(凹边形未验证)以重心为原点向各个顶点方向进行扩张
/**
多边形扩张
@param pts 多边形坐标,环形分布
@param dist 扩张距离(中心点方向)
@return 新坐标
*/
std::vector<cv::Point> CVG::shapeExp(std::vector<cv::Point> &pts, double dist) {
cv::Point pt_c = CVG::center(pts);
std::vector<cv::Point> pts_n;
for (int i = 0; i < pts.size(); i ++) {
cv::Point pt = cv::Point(pts[i].x, pts[i].y);
double dist_x = pt.x - pt_c.x;
double dist_y = pt.y - pt_c.y;
double ratio = dist/sqrt(pow(dist_x, 2)+pow(dist_y, 2))+1;
pt.x = ratio * (dist_x)+0.5 + pt_c.x;
pt.y = ratio * (dist_y)+0.5 + pt_c.y;
pts_n.push_back(pt);
}
return pts_n;
}
多边形平移(对于矫正前的平移处理可能需要进行多次)
/**
多边形平移
@param pts 多边形坐标,环形分布
@param offset 偏移量
@return 新坐标
*/
std::vector<cv::Point> CVG::shapeMove(std::vector<cv::Point> &pts, cv::Point offset) {
std::vector<cv::Point> pts_n;
for (int i = 0; i<pts.size(); i++) {
cv::Point pt = pts[i];
cv::Point pt_n;
pt_n.x = pt.x+offset.x;
pt_n.y = pt.y+offset.y;
pts_n.push_back(pt_n);
}
return pts_n;
}
多边形旋转(以重心为原点对各个顶点坐标进行旋转,旋转角度:a/180.0*M_PI )
/**
多边形旋转
@param pts 多边形坐标,环形分布
@param angle 旋转角度(正逆时针,负顺时针)
@return 新坐标
点(x,y)绕(x0,y0)逆时针旋转a角后变成(x',y'),则
x'-x0=(x-x0)cosa-(y-y0)sina
y'-y0=(x-x0)sina+(y-y0)cosa
*/
std::vector<cv::Point> CVG::shapeRotate(std::vector<cv::Point> &pts, double angle) {
cv::Point pt_c = CVG::center(pts);
std::vector<cv::Point> pts_n;
double sa = sin(angle);
double ca = cos(angle);
for (int i = 0; i<pts.size(); i++) {
cv::Point pt = pts[i];
cv::Point pt_n;
pt_n.x = pt_c.x + ((pt.x-pt_c.x)*ca - (pt.y-pt_c.y)*sa);
pt_n.y = pt_c.y + ((pt.x-pt_c.x)*sa + (pt.y-pt_c.y)*ca);
pts_n.push_back(pt_n);
}
return pts_n;
}
多边形凹凸性检查
/**
多边形凹凸性检查
@param pts 多边形坐标,环形分布
@return -1 凸集, 1凹集, 0 不合法
*/
int CVG::shapeConvex(std::vector<cv::Point> &pts) {
long i,j,k;
int flag = 0;
int z;
long n = pts.size();
if (n < 3)
return 0;
for (i=0;i<n;i++){
j = (i + 1) % n;
k = (i + 2) % n;
z = (pts[j].x - pts[i].x) * (pts[k].y - pts[j].y);
z -= (pts[j].y - pts[i].y) * (pts[k].x - pts[j].x);
if(z<0)
flag |= 1;
else if (z > 0)
flag |= 2;
if (flag==3)
return -1;//凸集
}
if (flag != 0) //凹集
return 1;
else
return 0; //不合法
}
点与多边形关系,采用铅垂线法
/**
点与多边形关系
@param pts 多边形坐标,环形分布
@param pt 点
@return true多边形上, fale多边形外
*/
bool CVG::inside(std::vector<cv::Point> &pts, cv::Point pt) {
int n = 0;
int min_y = INT_MAX;
for (int i = 0; i<pts.size(); i++) {
min_y = cv::min(min_y, pts[i].y);
}
cv::Point pt_min = cv::Point(pt.x, min_y-10);
for (int i = 0; i<pts.size(); i++) {
cv::Point pt0 = pts[i];
cv::Point pt1 = pts[(i+1)%pts.size()];
if ((pt.x>=pt0.x && pt.x<=pt1.x) || (pt.x>=pt1.x && pt.x<=pt0.x)) {
cv::Point pi = CVG::intersects(pt, pt_min, pt0, pt1);
if (pi.x != INT_MAX && pi.y != INT_MAX) {
n++;
}
}
}
return n%2 != 0;
}
来一个今天新写的函数(有bug请留言)
统计多边形凹点坐标
/**
多边形凹点下标
@param pts 多边形坐标,环形分布
@return 凹点下标
*/
std::vector<long> CVG::pits(std::vector<cv::Point> &pts) {
int min_y = INT_MAX;
for (int i = 0; i<pts.size(); i++) {
min_y = cv::min(min_y, pts[i].y);
}
min_y -= 10;
std::vector<long> ipts;
long ct = pts.size();
for (long i = 0; i < ct; i++) {
long i_2 = i+2;
if (i_2 >= ct) {
i_2 -= ct;
}
cv::Point pt = CVG::center(pts[i], pts[i_2]);
CVG::inside(pts, pt);
cv::Point pt_min = cv::Point(pt.x, min_y);
int ipt_ct = 0;
for (int i = 0; i<pts.size(); i++) {
cv::Point pt0 = pts[i];
cv::Point pt1 = pts[(i+1)%pts.size()];
if ((pt.x>=pt0.x && pt.x<=pt1.x) || (pt.x>=pt1.x && pt.x<=pt0.x)) {
cv::Point pi = CVG::intersects(pt, pt_min, pt0, pt1);
if (pi.x != INT_MAX && pi.y != INT_MAX) {
ipt_ct++;
}
}
}
if (ipt_ct%2 == 0) {
long ipt_idx = i+1;
if (ipt_idx >= ct) {
ipt_idx -= ct;
}
ipts.push_back(ipt_idx);
}
}
return ipts;
}
其它常用计算发掘中,欢迎各位提供其它计算方式,一起整合资源。
函数计算有误或精度误差的还请留言提醒,不胜感激!
网友评论