实际应用中,往往需要三点确定一个圆。
例如,在机器人视觉标定中,为了能不用手工创建工具坐标,就可以通过三点定圆的方式算出工具坐标的中心在哪里。
我们知道,如果三点不共线的情况下是可以产生一个圆的,有关的公式推导见下面的贴子。
这里勇哥提供公式的实现代码:
private Tuple<PointF, double> drawCircle3P(PointF pt1, PointF pt2, PointF pt3)
{
double x1 = pt1.X, x2 = pt2.X, x3 = pt3.X;
double y1 = pt1.Y, y2 = pt2.Y, y3 = pt3.Y;
double a = x1 - x2;
double b = y1 - y2;
double c = x1 - x3;
double d = y1 - y3;
double e = ((x1 * x1 - x2 * x2) + (y1 * y1 - y2 * y2)) / 2.0;
double f = ((x1 * x1 - x3 * x3) + (y1 * y1 - y3 * y3)) / 2.0;
double det = b * c - a * d;
if(Math.Abs(det)<1e-5)
{
return new Tuple<PointF, double>(new PointF(0, 0), -1);
}
double x0 = -(d * e - b * f) / det;
double y0 = -(a * f - c * e) / det;
var radius = Math.Sqrt((x1 - x0)*(x1 - x0)+(y1 - y0)* (y1 - y0));
return new Tuple<PointF, double>(new PointF((float)x0,(float)y0), radius);
}
private static PointF FitCenter(List<PointF> pts, double epsilon = 0.1)
{
try
{
double totalX = 0, totalY = 0;
int setCount = 0;
for (int i = 0; i < pts.Count; i++)
{
for (int j = 1; j < pts.Count; j++)
{
for (int k = 2; k < pts.Count; k++)
{
double delta = (pts[k].X - pts[j].X) * (pts[j].Y - pts[i].Y) - (pts[j].X - pts[i].X) * (pts[k].Y - pts[j].Y);
if (Math.Abs(delta) > epsilon)
{
double ii = Math.Pow(pts[i].X, 2) + Math.Pow(pts[i].Y, 2);
double jj = Math.Pow(pts[j].X, 2) + Math.Pow(pts[j].Y, 2);
double kk = Math.Pow(pts[k].X, 2) + Math.Pow(pts[k].Y, 2);
double cx = ((pts[k].Y - pts[j].Y) * ii + (pts[i].Y - pts[k].Y) * jj + (pts[j].Y - pts[i].Y) * kk) / (2 * delta);
double cy = -((pts[k].X - pts[j].X) * ii + (pts[i].X - pts[k].X) * jj + (pts[j].X - pts[i].X) * kk) / (2 * delta);
totalX += cx;
totalY += cy;
setCount++;
}
}
}
}
if (setCount == 0)
{
return PointF.Empty;
}
return new PointF((float)totalX / setCount, (float)totalY / setCount);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return PointF.Empty;
}
}
private void button6_Click(object sender, EventArgs e)
{
//px:=[191,198,190]
//py:=[191, 228, 260]
var ary1=drawCircle3P(new Point(191, 191), new Point(198,228), new Point(190,260));
var ary2 = FitCenter(new List<PointF>() { new PointF(191, 191), new PointF(198, 228), new PointF(190, 260) });
}这里勇哥提了两个实现,函数FitCenter只不过比drawCircle3P计算精度要高一点。因为PointF只能保存float型,因此小数字点后只有4位。
两个函数的运行结果如下:
x= 115.6615, Y=224.4154
X = 115.661537 Y = 224.41539
勇哥随便用halcon验证了一下,证明结果正确。

---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!


少有人走的路


















