椭圆

        椭圆(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_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;
        }

从一个椭圆上面获取特定个数的点的函数:

//参数描述:椭圆;输出的点集;欲获取的点的个数
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:椭圆上点的计算方程的更多相关文章

  1. Math.net,.net上的科学计算利器

    F#在科学计算领域的应用,包括部分语法介绍. Math.net,.net上的科学计算利器 摘要: .net上科学计算个人觉得首选numpy和scipy for dotnet.因为这两个库用户数量已经非 ...

  2. hdu 5017 模拟退火/三分求椭圆上离圆心最近的点的距离

    http://acm.hdu.edu.cn/showproblem.php?pid=5017 求椭圆上离圆心最近的点的距离. 模拟退火和三分套三分都能解决 #include <cstdio> ...

  3. LINUX上一个命令计算PI

    Linux上一个命令计算PI – 笑遍世界 http://smilejay.com/2017/11/calculate-pi-with-linux-command/ [root@d1 goEcho]# ...

  4. 开源一个Mac漂亮的小工具 PPRows for Mac, 在Mac上优雅的计算你写了多少行代码

    开源一个Mac漂亮的小工具 PPRows for Mac, 在Mac上优雅的计算你写了多少行代码. 开源地址: https://github.com/jkpang/PPRows

  5. opencv——pcb上寻找mark点(拟合椭圆的方法)

    #include "stdafx.h" // FitCircle.cpp : 定义控制台应用程序的入口 #include "cv.h" #include &qu ...

  6. 【opencv入门篇】 10个程序快速上手opencv【上】

    导言:本系列博客目的在于能够在vs快速上手opencv,理论知识涉及较少,大家有兴趣可以查阅其他博客深入了解相关的理论知识,本博客后续也会对图像方向的理论进一步分析,敬请期待:) PS:官方文档永远是 ...

  7. Android平台上使用气压传感器计算海拔高度

    气压传感器两年前已经开始被手机制造商运用在其设备上,但貌似没有引起开发者足够的重视.像Galaxy S III .Galaxy Note 2和小米2手机上都有,不过大家对于气压传感器比较陌生.其实大气 ...

  8. OpenCV windows 上安装

    1.先按照  Anaconda , 有关教程,可以去其他博客查看 2.傻瓜的装Opencv.(我采用的) 在Anaconda  Prompt中输入: conda install -c https:// ...

  9. OpenCV——轮廓面积及长度计算

    计算轮廓面积: double contourArea(InputArray contour, bool oriented=false ) InputArray contour:输入的点,一般是图像的轮 ...

随机推荐

  1. 分布式服务框架Dubbo入门案例和项目源码

    本项目源代码:http://download.csdn.net/detail/fansunion/9498406 Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案, 是 ...

  2. ClassCastException:ColorDrawable cannot be cast to RoundRectDrawableWithShadow

    错误信息 java.lang.ClassCastException: android.graphics.drawable.ColorDrawable cannot be cast to android ...

  3. log显示error时的堆栈信息理解和分析

    error显示的log堆栈信息,是从最深层(最内层)的堆栈信息开始由内向外打印的. error显示的log堆栈信息,是从最深层(最内层)的堆栈信息开始由内向外打印的. error显示的log堆栈信息, ...

  4. W5500中断寄存器的理解

    W5500中断部分,W5500中文手冊V1.0 写的不够清楚,该文是本人结合中英文手冊及自己理解,整理出有关中断部分的理解,如有不对的请指正. 一:引脚 INTn 为中断输出(Interrupt ou ...

  5. 计算几何 二维凸包问题 Andrew算法

    凸包:把给定点包围在内部的.面积最小的凸多边形. Andrew算法是Graham算法的变种,速度更快稳定性也更好. 首先把全部点排序.依照第一keywordx第二keywordy从小到大排序,删除反复 ...

  6. SpringMVC案例2----基于spring2.5的注解实现

    和上一篇一样,首先看一下项目结构和jar包 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmVuamFtaW5fd2h4/font/5a6L5L2T/fo ...

  7. Codeforces Round #332 (Div. 2)C. Day at the Beach 树状数组

    C. Day at the Beach   One day Squidward, Spongebob and Patrick decided to go to the beach. Unfortuna ...

  8. Linux vs Window

    目前国内Linux更多的是应用于服务器上,而桌面操作系统更多使用的是Window.主要区别如下: 比较 Windows Linux 界面 界面统一,外壳程序固定所有Windows程序菜单几乎一致,快捷 ...

  9. 【BZOJ 2252】 矩阵距离

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2252 [算法] 将所有是”1“的点入队,然后广度优先搜索,即可 [代码] #incl ...

  10. 【POJ 3630】 Phone List

    [题目链接] http://poj.org/problem?id=3630 [算法] 字典树 [代码] #include <algorithm> #include <bitset&g ...