OpenCV:简单计算曲线弧度-弓形弧度
在判断曲线拟合度时候,需要进行曲线曲率计算。本文中使用根据弦的方法计算曲线弧度半径,得到曲率。
首先判定是否为弧:
简单判定:不要选取较多的点,若线段不是偏向一个方向,则不为弧
bool isArcCurve( std::vector<cv::Point> &curve ) { bool isArc = false; cv::Point ps, pe,vec; ps = cv::Point(curve[0]); pe = cv::Point(curve[curve.size() - 1]); double angle0 = colorWish::arccos(ps, pe); std::vector<double > rls;//左侧还是右侧 for (int i = 1; i < curve.size() - 1; ++i) { double angle1 = colorWish::arccos( ps, curve[i] ); rls.push_back( angle1 ); } //若出现一次反转,则判定为否,以此保证曲线的单方向 std::vector<bool > rlbs; for ( int i = 0; i < rls.size() ; ++i ) { bool isRight = false; if ( rls[i]>angle0 ){ isRight = true; } else{ isRight = false; } rlbs.push_back( isRight ); } //若出现一次反转,则判定为否,以此保证曲线的单方向 bool isSinVec = false; bool isRight = false; if ( rlbs.size()>0 ){ isRight = rlbs[0]; for (int i = 1; i < rlbs.size(); ++i){ if ( isRight!= rlbs[i]){ isSinVec = true; } } }else{ } isArc = isSinVec; return isArc; }
double colorWish::dis2(double x1, double y1, double x2, double y2) { return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); } // 计算两点的坐标夹角,360度余弦值 double colorWish::arccos(double x0, double y0, double x1, double y1) { double angle = 0; double l = dis2(x0, y0, x1, y1); l = sqrt(l); if (y1 - y0 > 0) { angle = acos((x1 - x0) / l); } else { angle = 3.141592653 + 3.141592653 - acos((x1 - x0) / l); } //std::cout << (angle) << " "; return angle; }//arccos double colorWish::arccos(cv::Point cneter, cv::Point p) { return arccos(double(cneter.x), double(cneter.y), double(p.x), double(p.y)); }
计算弧度值:
计算弓形曲率,使用遍历方法找弓形高(曲线上任一点),根据海伦公式计算出高
//计算弓形的曲率-此方法仍然只保证对连续点集确定有效 //计算方法:两端长度为弦长,高度为弓形高,以此计算曲率 double getArcCurvity( std::vector<cv::Point> &curve ) { double curvity = 0; if ( curve.size()<4 ){ return 0; } cv::Point ps, pe; ps = cv::Point( curve[0] ); pe = cv::Point( curve[curve.size()-1] ); double lArc = disCv( ps, pe );//弦长 double hArc = 0; for ( int i=1;i<curve.size()-1;++i ){ double h = p2Line( curve[i],ps,pe );//点到直线的距离 if (hArc<h){ hArc = h; } } //曲率公式-使用R^2 = L^2 +(R-H)^2即 R= ( L^2/H +H)/2 double R = 0.5*( lArc*lArc/hArc +hArc ); curvity = 1 / R; return curvity; }
//点 p 到线段(p1,p2)的距离-只计算三角形情况,且只计算垂直距离 //使用海伦公式 double p2Line(const cv::Point &p0,const cv::Point &p1, const cv::Point &p2) { double dis = 0; double a, b, c, p, S,h; a = disCv(p0, p1); b = disCv(p0, p2); c = disCv(p1, p2); p = (a + b + c)/2; S = sqrt(p*(p-a)*(p - b)*(p - c) ); h = S * 2 / a; dis = h ; return dis; }
double disCv(const cv::Point2f &p1, const cv::Point2f &p2) { double dis = 0; dis = sqrt((p2.x - p1.x)*(p2.x - p1.x) + (p2.y - p1.y)*(p2.y - p1.y)); return dis; }
弓形弧度半径公式:
double R = 0.5*( lArc*lArc/hArc +hArc ); double curvity = 1 / R;
此种方法,比使用houghCircle方法粗糙,但简单直观。
寻找结果图像: