OpenCv:椭圆上点的计算方程
橢圓
??????? 橢圓(Ellipse)是平面內到定點F1、F2的距離之和等于常數(大于|F1F2|)的動點P的軌跡,F1、F2稱為橢圓的兩個焦點。其數學表達式為:???????????????????????????????????????????????????????????????????????????????????????????????????????????????? |PF1|+|PF2|=2a(2a>|F1F2|)。[1]? ??????? 橢圓是圓錐曲線的一種,即圓錐與平面的截線。[2]?橢圓在開普勒行星運行三定律中扮演了重要角色,即恒星是橢圓兩焦點中的一個,是數學科重點研究的一個項目。[3]?標準方程:
??????
??????? 橢圓的標準方程共分兩種情況: ?????????????? 當焦點在x軸時,橢圓的標準方程是:x^2/a^2+y^2/b^2=1,(a>b>0); ??????????????當焦點在y軸時,橢圓的標準方程是:y^2/a^2+x^2/b^2=1,(a>b>0); ????????????????????????????????????????????????? 其中a^2-c^2=b^2參數方程:
?????? 橢圓上點的參數方程為:
???????????? y = a *sin(? alp )?
???????????? x=? a *cos( alp )? (a>b>0);
?此時的角度alp不是中心點到橢圓上點的角度,而是橢圓的仿射圓上的點到圓心的角度,計算角度應考慮到壓縮。
壓縮方向:
?????? ? Height方向拉伸;
?????? ? 計算變化后的beta;
???? ? ? 計算坐標:
???????????? y = a *sin(? beta )?
???????????? x=? a *cos( beta )? (a>b>0);
???? ??? Height方向壓縮;?????????????? y = a *sin(? beta ) *(b/a)
?????????????? x=? a *cos( beta )?????????????????? (a>b>0);
?????? 計算距離。
橢圓上點的計算方程:
??????? 對于 (a>b>0);
?????????????? 對應的圓的方程: R = a;
?????????????? 圓上的點的坐標: x2 = R * sin(Beta)??? y2 = R * cos(beta);
?????????????? 不變性:? alp = beta ????????????????
?????????????
?????? 對應橢圓點的坐標:
?????????????? 角度:? alp = beta
?????????????? 角度:? alp = beta
??????????????
計算橢圓上點的代碼:
???? 代碼是錯誤的,不能把點壓縮到橢圓上
//調整橢圓邊緣到標準橢圓;在角度方向上進行拉伸//angleOfDip 為橢圓的偏斜角,弧度值!//增加邊界檢查template <class T1,class T2>float AdjustEllipseEdge(std::vector<std::pair< T1, T2 > > &closeEdgeIn,std::vector<std::pair< T1, T2 > > &closeEdgeOut,const cv::RotatedRect &ecf,const cv::Point2f &rfCentroidS,const double angleOfDipSrc,const int ww,const int hh){assert(closeEdgeIn.size() == closeEdgeOut.size() );int w = ww -1;int h = hh -1;const cv::Point2f rfCentroid = ecf.center;//cv::Point2f rfCentroid(0,0);std::vector< double > angleListS;//為點橢圓角度,用于求取 橢圓點到中心的距離angleListS.resize( closeEdgeIn.size() );int vOrH = 0;//水平或者豎直?vOrH = ecf.size.width > ecf.size.height? 0:1;//若0,則為V;或者為1,水平double angleOfDip = 0;if (0 == vOrH ){//若為水平//width 的傾角angleOfDip = angleOfDipSrc; } else{angleOfDip = angleOfDipSrc - PI_1_2; }double a = max(ecf.size.height/2.0,ecf.size.width /2.0);//長軸//固定后使用方程double b = min(ecf.size.height/2.0,ecf.size.width /2.0);#ifdef SHOW_TEMPcv::Mat canvasSrc = cv::Mat::zeros(200,200,CV_8UC3);cv::bitwise_not(canvasSrc,canvasSrc);cv::ellipse(canvasSrc,ecf,cv::Scalar(0,0,255),1,8); #endif//在此測試,cos計算的代碼 #ifdef SHOW_TEMPcv::RotatedRect ecT = RotatedRect(Point2f(100,100), Size2f(50,100), 30);std::vector<std::pair< cv::Point2f, double > > PointCosTest(0);cvWish::polygon::GetElipseEdge(ecT, PointCosTest, (ecT.size.height + ecT.size.height)/5.0 );cv::ellipse(canvasSrc, ecT, cv::Scalar(0,0,255), 1, 8);for ( int i=0; i< PointCosTest.size(); ++i){cv::circle( canvasSrc, PointCosTest[i].first, 1, cv::Scalar(255,0,0), 1, 8, 0 );double af = cvWish::cosCv(ecT.center,PointCosTest[i].first);//cosCv出現計算問題std::cout<< "Cos:" << af<< std::endl;std::cout<< "Angle:" << PointCosTest[i].second << std::endl;cv::imshow("PointCosTest",canvasSrc);cv::waitKey(1);}#endiffor ( int i=0; i<closeEdgeIn.size(); ++i ){closeEdgeIn[i].second = cvWish::cosCv( rfCentroid, closeEdgeIn[i].first );angleListS[i] = closeEdgeIn[i].second;angleListS[i] -= angleOfDip;//旋轉angleListS[i] = angleListS[i]> PI_4_2 ? angleListS[i] - PI_4_2:angleListS[i];//探測距離double disPC = cvWish::disCv(rfCentroid,closeEdgeIn[i].first);double alp = angleListS[i];//alp = alp *180/M_PI;double disShould = sqrt( b*sin(alp ) *b*sin(alp ) + a*cos(alp) *a*cos(alp) );//公式無誤,角度出現問題?//sqrt( b*cos(alp ) *b*cos(alp ) + a*sin(alp) *a*sin(alp) );//公式無誤,角度出現問題?//可能問題,方向角度出現往長軸極點的方向進行壓縮,導致生成距離變大。//double disShould = sqrt( // ecf.size.width*cos(angleListS[i]) *ecf.size.width*cos(angleListS[i]) /4// + ecf.size.height*sin(angleListS[i]) *ecf.size.height*sin(angleListS[i])/4 );std::cout<< alp << std::endl;std::cout<< cos(alp) << std::endl;std::cout<<"disPc:" <<disPC << std::endl;std::cout<< "disShould:" << disShould << std::endl;#ifdef SHOW_TEMP//cv::Mat canvasSrc(100,100,CV_8UC3);cv::circle(canvasSrc,closeEdgeIn[i].first,1,cv::Scalar(255,0,0),1,8,0);cv::imshow("edgeEvolution",canvasSrc);cv::waitKey(1); #endif//調整點到橢圓上//adjustPoint2Elipse();//根據距離 往角度方向上拉伸點//角度其實產生了偏離//偏角使用圖片偏角cvWish::PullPoint2Out( closeEdgeIn[i].first, closeEdgeIn[i].second, ( disPC - disShould ) ); closeEdgeOut[i].first = closeEdgeIn[i].first;已確認大于0,此時確認不超邊界closeEdgeOut[i].first.x = min(closeEdgeOut[i].first.x,w);closeEdgeOut[i].first.y = min(closeEdgeOut[i].first.y,h);closeEdgeOut[i].second = closeEdgeIn[i].second; #ifdef SHOW_TEMPcv::circle(canvasSrc,closeEdgeOut[i].first,1,cv::Scalar(0,255,0),1,8,0);cv::imshow("edgeEvolution",canvasSrc);cv::waitKey(1); #endif}return 1.0;}
代碼修改:
???? 使用一個仿射變換
//調整橢圓邊緣到標準橢圓;在角度方向上進行拉伸//angleOfDip 為橢圓的偏斜角,弧度值!//增加邊界檢查template <class T1,class T2>float AdjustEllipseEdge(std::vector<std::pair< T1, T2 > > &closeEdgeIn,std::vector<std::pair< T1, T2 > > &closeEdgeOut,const cv::RotatedRect &ecf,const cv::Point2f &rfCentroidS,const double angleOfDipSrc,const int ww,const int hh){assert(closeEdgeIn.size() == closeEdgeOut.size() );int w = ww -1;int h = hh -1;const cv::Point2f rfCentroid = ecf.center;//cv::Point2f rfCentroid(0,0);std::vector< double > angleListS;//為點橢圓角度,用于求取 橢圓點到中心的距離angleListS.resize( closeEdgeIn.size() );int vOrH = 0;//水平或者豎直?vOrH = ecf.size.width > ecf.size.height? 0:1;//若0,則為V;或者為1,水平double angleOfDip = 0;if (0 == vOrH ){//若為水平//width 的傾角angleOfDip? = angleOfDipSrc; } else{angleOfDip? = angleOfDipSrc - PI_1_2; }//double a = max(ecf.size.height/2.0,ecf.size.width /2.0);//長軸//固定后使用方程//double b = min(ecf.size.height/2.0,ecf.size.width /2.0);double b = ecf.size.height/2.0//長軸//固定后使用方程double a = ecf.size.width /2.0;double compressFactor = b /a ;//壓縮或者縮放因子#ifdef SHOW_TEMPcv::Mat canvasSrc = cv::Mat::zeros(200,200,CV_8UC3);cv::bitwise_not(canvasSrc,canvasSrc);cv::ellipse(canvasSrc,ecf,cv::Scalar(0,0,255),1,8); #endif//在此測試,cos計算的代碼 #ifdef SHOW_TEMPcv::RotatedRect ecT = RotatedRect(Point2f(100,100), Size2f(50,100), 30);std::vector<std::pair< cv::Point2f, double > >? PointCosTest(0);cvWish::polygon::GetElipseEdge(ecT, PointCosTest, (ecT.size.height + ecT.size.height)/5.0 );cv::ellipse(canvasSrc, ecT, cv::Scalar(0,0,255), 1, 8);for ( int i=0; i< PointCosTest.size(); ++i){cv::circle( canvasSrc, PointCosTest[i].first, 1, cv::Scalar(255,0,0), 1, 8, 0 );double af = cvWish::cosCv(ecT.center,PointCosTest[i].first);//cosCv出現計算問題std::cout<< "Cos:" << af<< std::endl;std::cout<< "Angle:" << PointCosTest[i].second << std::endl;cv::imshow("PointCosTest",canvasSrc);cv::waitKey(1);}#endiffor ( int i=0; i<closeEdgeIn.size(); ++i ){closeEdgeIn[i].second? = cvWish::cosCv( rfCentroid, closeEdgeIn[i].first );//壓縮方向angleListS[i]? = closeEdgeIn[i].second;angleListS[i] -= angleOfDip;//旋轉angleListS[i]? = angleListS[i]> PI_4_2 ? angleListS[i] - PI_4_2:angleListS[i];//探測距離double disPC??? = cvWish::disCv(rfCentroid,closeEdgeIn[i].first);//double alp =? angleListS[i];//alp =? alp *180/M_PI;//double disShould = sqrt( b*sin(alp ) *b*sin(alp ) + a*cos(alp) *a*cos(alp) );//公式無誤,角度出現問題?//可能問題,方向角度出現往長軸極點的方向進行壓縮,導致生成距離變大。//計算對應仿射圓的角度double xDeta =? closeEdgeIn[i].first.x - rfCentroid.x;double yDeta =? closeEdgeIn[i].first.y - rfCentroid.y;yDeta /= compressFactor;//計算角度double beta = cvWish::cosCv( rfCentroid, cv::Point2f( rfCentroid.x + xDeta, rfCentroid.y+ yDeta ) );double r = a;?????????????????????????????????????????????????????????????? ?xDeta? =? r* cos(beta);yDeta? =? r* sin(beta);yDeta *= compressFactor;//直接計算距離double disShould = sqrt( xDeta*xDeta + yDeta*yDeta );//公式無誤,角度出現問題?std::cout<<"disPc:" <<disPC << std::endl;std::cout<< "disShould:" << disShould << std::endl;#ifdef SHOW_TEMP//cv::Mat canvasSrc(100,100,CV_8UC3);cv::circle(canvasSrc,closeEdgeIn[i].first,1,cv::Scalar(255,0,0),1,8,0);cv::imshow("edgeEvolution",canvasSrc);cv::waitKey(1); #endif//調整點到橢圓上//adjustPoint2Elipse();//根據距離 往角度方向上拉伸點//角度其實產生了偏離//偏角使用圖片偏角cvWish::PullPoint2Out( closeEdgeIn[i].first, closeEdgeIn[i].second, ( disPC - disShould ) );?? ?closeEdgeOut[i].first? = closeEdgeIn[i].first;已確認大于0,此時確認不超邊界closeEdgeOut[i].first.x = min(closeEdgeOut[i].first.x,w);closeEdgeOut[i].first.y = min(closeEdgeOut[i].first.y,h);closeEdgeOut[i].second = closeEdgeIn[i].second; #ifdef SHOW_TEMPcv::circle(canvasSrc,closeEdgeOut[i].first,1,cv::Scalar(0,255,0),1,8,0);cv::imshow("edgeEvolution",canvasSrc);cv::waitKey(1); #endif}return 1.0;}從一個橢圓上面獲取特定個數的點的函數:
//參數描述:橢圓;輸出的點集;欲獲取的點的個數int polygon::GetElipseEdge(const cv::RotatedRect &ecf, std::vector<std::pair< cv::Point2f, double > > &ellipseEdge,const int numPs,cv::Rect &roiRestrict,bool openEdgeRestrict ){if ( numPs == 0 ){return numPs;}else{ellipseEdge.resize( numPs );}//對橢圓進行劃分const double angleGap = PI_4_2/numPs;const double cx = ecf.center.x;const double cy = ecf.center.y;const float angleOfDip = PI_1_2 + ecf.angle*3.1415926 /180.0;//為何偏移了 半個pi//const double angleOfDip =0- ecf.angle*3.1415926 /180.0;//double w = ecf.size.width /2.0;double h = ecf.size.height/2.0;for (int i=0 ;i< numPs;++i ){double as = i*angleGap ;double a = as ;a += angleOfDip;a = a>PI_4_2? a-PI_4_2:a;double y = (w) *sin( a );double x = (h) *cos( a );//旋轉float xDeta = x*cos( angleOfDip ) - y*sin( angleOfDip );float yDeta = x*sin( angleOfDip ) + y*cos( angleOfDip );cv::Point2f p( cx+xDeta, cy+yDeta);//ellipseEdge[i] = (std::pair< T1, T2 >)(std::make_pair( p,as ) );//ellipseEdge[i] = (std::pair< cv::Point2f, double >)(std::make_pair( p,as ) );//此處代碼只為運行于GCC修改,有問題,模板庫不能使用!!!wishchin!!!ellipseEdge[i].first.x = p.x;ellipseEdge[i].first.y = p.y;ellipseEdge[i].second = as;}if (openEdgeRestrict){float x,y;float xS(roiRestrict.x), yS(roiRestrict.y), xE(roiRestrict.x+roiRestrict.width), yE(roiRestrict.y+roiRestrict.height );for (int i=0 ;i< numPs;++i ){x = ellipseEdge[i].first.x;y = ellipseEdge[i].first.y;x = (std::min)( (std::max)(x,xS),xE );y = (std::min)( (std::max)(y,yS),yE );//ellipseEdge[i].first = cv::Point2f(x,y);ellipseEdge[i].first.x = x;ellipseEdge[i].first.y = y;}} else{}return 1;}
?結果顯示:
?????? 原始結果:??????????????????????????????????????????????????????????????????????????????????? 修改后結果:
?????????????????????????????????????????????????????????
??? ?????
總結
以上是生活随笔為你收集整理的OpenCv:椭圆上点的计算方程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win7打印机提示错误0x0000000
- 下一篇: win10无法安装打印机错误代码0x00