OpenCV:簡單計算曲線弧度-弓形弧度
阿新 • • 發佈:2018-12-17
在判斷曲線擬合度時候,需要進行曲線曲率計算。本文中使用根據弦的方法計算曲線弧度半徑,得到曲率。
首先判定是否為弧:
簡單判定:不要選取較多的點,若線段不是偏向一個方向,則不為弧
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方法粗糙,但簡單直觀