实际应用中,往往需要三点确定一个圆。
例如,在机器人视觉标定中,为了能不用手工创建工具坐标,就可以通过三点定圆的方式算出工具坐标的中心在哪里。
我们知道,如果三点不共线的情况下是可以产生一个圆的,有关的公式推导见下面的贴子。
这里勇哥提供公式的实现代码:
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
版权声明:本文为博主原创文章,转载请附上博文链接!

