标准方程:
参数方程:
椭圆上点的参数方程为:
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_TEMP cv::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_TEMP cv::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); } #endif for ( 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_TEMP cv::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_TEMP cv::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_TEMP cv::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); } #endif for ( 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_TEMP cv::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; }
结果显示:
原始结果: 修改后结果: