最小二乘法拟合圆心与半径

公众号“轻松玩转机器人”,欢迎关注。

1、算法介绍

最小二乘法的目的,通俗来说,就是拟合变量之间的关系。

由于现实世界观测的变量存在噪声,找不到完美、不存在误差的关系,因此我们退而求其次,尽可能减小误差影响。误差有正有负,而我们希望消除正负方向的差异,所以采用了平方的方法,二乘其实是指平方,只比较误差长度。

举个例子,我们通过观测得到一组点(x, y),这些点原则来上说属于一条直线,由于观测噪声的存在,找不到这样一条直线涵盖所有点。但是通过最小二乘法,观测尽可能多的点,可以拟合出较为准确的斜率和截距。

2、算法应用

对于拟合圆心和半径,先写出圆的公式:

​​​​​化简得到:

则有:

设圆上有n个点,则有:

写成矩阵形式:

即:

根据最小二乘法,求得A矩阵:

至此,通过A矩阵即可得到圆心和半径。

如下图所示,通过观测得到的红点拟合出其所在的圆(圆心和半径)。

  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
在上一个问题中,我们已经使用Hough Circle Transform函数检测到了圆,现在我们需要使用最小二乘法拟合圆心最小二乘法是一种常用的拟合方法,可以用来拟合数据点到一个函数或者曲线。在这里,我们可以用最小二乘法拟合圆心。 假设我们已经检测到了n个圆,在检测到的圆中,第i个圆的圆心坐标为(xi, yi),我们需要求出这些圆心坐标的最优拟合圆(也就是最小二乘法拟合的圆)。 最小二乘法拟合圆心的思路如下: 1. 对于每个圆心(xi, yi),我们可以将它表示为(x - xi)^2 + (y - yi)^2 = r^2的形式。 2. 将上式展开,得到x^2 + y^2 - 2xi*x - 2yi*y + (xi^2 + yi^2 - r^2) = 0。 3. 对于每个圆心(xi, yi),我们可以将上式表示为Aix + Biy + Ci = Di^2的形式,其中Ai = -2xi, Bi = -2yi, Ci = xi^2 + yi^2 - r^2, Di = xi^2 + yi^2。 4. 将上述方程组表示成矩阵形式:AX = B,其中X = [a, b, c]T,A为n x 3的矩阵,B为n x 1的矩阵,X为3 x 1的矩阵,T表示矩阵的转置。 5. 使用最小二乘法求解X,即X = (ATA)^-1ATB。 6. 求出a,b,c之后,可以得到最小二乘法拟合圆心为(x0, y0) = (-a/2, -b/2),半径为r = sqrt(a^2 + b^2 - 4c)/2。 下面是一个示例代码,演示如何使用最小二乘法拟合图像中检测到的圆心: ```c++ #include <opencv2/opencv.hpp> #include <iostream> #include <vector> using namespace std; using namespace cv; int main() { Mat image = imread("circles.png", IMREAD_GRAYSCALE); if (image.empty()) { cout << "Could not open or find the image" << endl; return -1; } Mat blurred; GaussianBlur(image, blurred, Size(5, 5), 2); vector<Vec3f> circles; HoughCircles(blurred, circles, HOUGH_GRADIENT, 1, 10, 100, 30, 5, 50); Mat A(circles.size(), 3, CV_32F); Mat B(circles.size(), 1, CV_32F); for (size_t i = 0; i < circles.size(); i++) { float xi = circles[i][0]; float yi = circles[i][1]; float ri = circles[i][2]; A.at<float>(i, 0) = -2 * xi; A.at<float>(i, 1) = -2 * yi; A.at<float>(i, 2) = xi * xi + yi * yi - ri * ri; B.at<float>(i, 0) = xi * xi + yi * yi; } Mat ATA, ATB, X; transpose(A, ATA); ATB = ATA * B; X = (ATA * A).inv() * ATB; float a = X.at<float>(0, 0); float b = X.at<float>(1, 0); float c = X.at<float>(2, 0); Point2f center(-a / 2, -b / 2); float radius = sqrt(a * a + b * b - 4 * c) / 2; // 用红色圆画出最小二乘法拟合圆心 circle(image, center, 3, Scalar(0, 0, 255), -1, 8, 0); // 用蓝色圆画出最小二乘法拟合的圆 circle(image, center, radius, Scalar(255, 0, 0), 3, 8, 0); // 输出最小二乘法拟合圆心半径 cout << "Fitted Circle:" << endl; cout << "Center: (" << center.x << ", " << center.y << ")" << endl; cout << "Radius: " << radius << endl; namedWindow("Fitted Circle", WINDOW_NORMAL); imshow("Fitted Circle", image); waitKey(0); return 0; } ``` 在此示例中,我们使用前面的代码检测到了圆,并将每个圆心(xi, yi)表示为Aix + Biy + Ci = Di^2的形式。然后,我们将这些方程表示为矩阵形式,使用最小二乘法求解出拟合圆的参数a, b, c。最后,我们计算出最小二乘法拟合圆心半径,并在图像上画出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值