最近深度学习项目需要自己设计标注软件,主要针对规则几何图形缺失部分信息时,要求定位的中心是原始图形的几何中心,而不是外接矩形框中心。
考虑到实际采图时还要考虑旋转角度,因此标注软件就要设计在特定矩形框内生成不同旋转角度的椭圆,对套接缺失圆或者椭圆。自己算了两天,思路对了就是不会化简求解,在知乎查找到求解方案。
数学求解
部分参考:知乎链接,我的实际是根据theta角度来生成不同椭圆,有所不同
在MFC绘制时,发现上图最终求解的方式绘制图像,相切得不是很好,且偏转角度较大时,完全乱了。
我觉得可能是求得p,q值后再进行多次运算求A,B,C,再求细分线段下的y时计算精度不断丢失了。
最终采用的方式时,求出p,q后,在偏转的坐标系求出细分线段后再转换至无偏转的坐标系。这样效果就可以了。还有就是一个问题是45度时,上面的方法无法求解p,q,以后再处理。
相关代码
double A, B, C, p, q,a,b,deltax,tmp;
CPoint up1, up2, low1, low2,transup1, transup2, translow1, translow2;
a = fabs(lt.x - rb.x);
b = fabs(lt.y - rb.y);
double CX = (lt.x + rb.x) / 2.0;
double CY = (lt.y + rb.y) / 2.0;
p = sqrt((pow(a*cos(gl_rotate),2)- pow(b*sin(gl_rotate), 2))/(4*cos(2*gl_rotate)));
//q = sqrt((pow(b*cos(gl_rotate), 2) - pow(a*sin(gl_rotate), 2)) / (4 * cos(2 * gl_rotate)));
//p = sqrt((pow(a, 2) - pow(b*tan(gl_rotate), 2)) /(4 *(1-pow(tan(gl_rotate),2))));
q = sqrt((a*a + b * b) / 4 - p * p);
#if 1
//先在偏转坐标系求各细分线段,再转换至标准坐标系
deltax = 2.0*p / 200;
low1 = up1 = CPoint(-p,0);
for (int i=1;i<201;i++)
{
if(i!=200)up2.x = low2.x = -p + i * deltax;
else up2.x = low2.x = p;
up2.y = q * sqrt(1 - pow(up2.x / p, 2));//由椭圆方程求解y坐标
low2.y = -up2.y;
//转换至标准坐标系
transup1.x = int(up1.x*cos(gl_rotate) - up1.y*sin(gl_rotate)+0.5);
transup2.x = int(up2.x*cos(gl_rotate) - up2.y*sin(gl_rotate)+0.5);
transup1.y = int(up1.y*cos(gl_rotate) + up1.x*sin(gl_rotate)+0.5);
transup2.y = int(up2.y*cos(gl_rotate) + up2.x*sin(gl_rotate)+0.5);
translow1.x = int(low1.x*cos(gl_rotate) - low1.y*sin(gl_rotate)+0.5);
translow2.x = int(low2.x*cos(gl_rotate) - low2.y*sin(gl_rotate)+0.5);
translow1.y = int(low1.y*cos(gl_rotate) + low1.x*sin(gl_rotate)+0.5);
translow2.y = int(low2.y*cos(gl_rotate) + low2.x*sin(gl_rotate)+0.5);
pMemDc->MoveTo(CPoint(transup1.x + CX, transup1.y + CY)); pMemDc->LineTo(CPoint(transup2.x + CX, transup2.y + CY));
pMemDc->MoveTo(CPoint(translow1.x + CX, translow1.y + CY)); pMemDc->LineTo(CPoint(translow2.x + CX, translow2.y + CY));
up1 = up2;
low1 = low2;
}
#else
//这种方式误差大
A = pow(cos(gl_rotate), 2) / pow(p, 2) + pow(sin(gl_rotate), 2) / pow(q, 2);
B = pow(sin(gl_rotate), 2) / pow(p, 2) + pow(cos(gl_rotate), 2) / pow(q, 2);
C = sin(2 * gl_rotate)*(1 / pow(p, 2) - 1 / pow(q, 2));
deltax = a / 200;
up1.x = low1.x = lt.x-CX;
up1.y = low1.y = int(-C * up1.x / B+0.5);//中心在原点
for (int i=1;i<201;i++)
{
if (i == 200) { low2.x = up2.x = rb.x-CX; }
else { low2.x = up2.x = int(lt.x - CX + i * deltax + 0.5); }
tmp = sqrt(pow(C*low2.x, 2) - B * (A*pow(low2.x, 2) - 1));
low2.y = int((-C* low2.x - tmp) / B + 0.5);
up2.y = int((-C * up2.x + tmp) / B + 0.5);
pMemDc->MoveTo(CPoint(up1.x+CX, up1.y + CY)); pMemDc->LineTo(CPoint(up2.x + CX, up2.y + CY));
pMemDc->MoveTo(CPoint(low1.x + CX, low1.y + CY)); pMemDc->LineTo(CPoint(low2.x + CX, low2.y + CY));
up1 = up2;
low1 = low2;
}
#endif
最终效果图,勉强满足需求。