最近研究了一下梯度下降法,所以写了个拟合圆的方法。拟合圆属于非线性拟合。网上的最小二乘法拟合圆公式并不是误差的平方,而是4次方(为了去掉公式里的开方)。一般可以先用网上的公式得到一个初始解,然后再用梯度下降法继续求精。下述代码基于VS2017、Qt5.9和OpenCV430,通过了验证。代码中为了加速收敛限制了迭代的最小步长为0.005。如果步长小于它则会放大步长,因此该程序的求解精度约为5‰。代码如下:
void main() { vector<Point2f> points = { { -1, -1 }, { 1, 1 }, { 1, -1 } }; Matx13f resolve = Matx13f::zeros(); for (int loop = 0; loop < 50; loop++) { float dex = 0; float dey = 0; float der = 0; for (auto pt : points) { float dx = pt.x - resolve(0); float dy = pt.y - resolve(1); float g = sqrtf(dx * dx + dy * dy); float f = g - resolve(2); dex += -2 * f / g * dx; dey += -2 * f / g * dy; der += -2 * f; } dex /= points.size(); dey /= points.size(); der /= points.size(); dex *= 0.1f; dey *= 0.1f; der *= 0.1f; float maxv = std::max({ fabs(dex), fabs(dey), fabs(der) }); if (maxv < 0.005f) { dex = dex / maxv * 0.005f; dey = dey / maxv * 0.005f; der = der / maxv * 0.005f; } resolve(0) -= dex; resolve(1) -= dey; resolve(2) -= der; qDebug() << dex << dey << der; } qDebug() << resolve(0) << resolve(1) << resolve(2) << "-<"; }
标签:dex,dey,resolve,梯度,der,float,例子,拟合 From: https://www.cnblogs.com/mengxiangdu/p/17293027.html