日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

【数学和算法】最小二乘法理论(附c++代码)

發布時間:2025/3/21 c/c++ 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【数学和算法】最小二乘法理论(附c++代码) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
插值:是給出一些點,求出這些點的表達式,表達式一定經過這些點,然后利用表達式就可以得到某點的值。

插值應用場景:在數據點稀少的時候,也可以用來插值,使得數據點密集。


擬合:是給出一些點,求出最接近這些點的曲線表達式,表達式不要求穿過這些點,只要求最貼合這些點,這就是擬合。

擬合應用場景:用來使得這些點的曲線更平滑。


注意多項式插值與多項式擬合的區別:

  • 多項式插值的話不需要用到最小二乘法,比如三次多項式插值,你只需要四個點,四個方程,組成由4個多項式系數作為未知數的四元一次方程組,就可以求出三次多項式的四個系數;
  • 多項式擬合,例如三次多項式擬合,可能會給你幾十個幾百個上千個點,然后使用最小二乘法,求出最貼合這些點的曲線來擬合這些點。

看了上面的區別,應該很明了了,如果使用多項式插值,每增加一個點,多項式次數就會增加,就需要重新計算,而且次數也并非越大越好,會有龍格現象,在實際工程中,這顯然不合理,所以多項式插值一般只是理論中一帶而過。實際工程中我們通常使用多項式擬合。當數據點本身很多的話,多項式插值則次數很高,龍格現象會造成不準確插值。當然這一點可以通過分段低次插值克服,而不會直接用到高次數的多項式插值。


下面只介紹擬合中最常用的最小二乘法,理論部分直接參考知乎大佬的博客: 最小二乘法

1.最小二乘法 理論部分

知乎大佬的博客中講到了最小二乘法推導,以及選擇算術平均數、一次多項式曲線、二次多項式曲線等進行擬合的效果。

  • 如果使用算術平均數來擬合,得到的擬合曲線的所有點的y值都相等,即平行于x軸的直線(斜率為0);
  • 如果使用一次多項式來擬合,得到的擬合曲線的所有點的y值不相等,即一條斜率不為0的直線;
  • 如果使用二次多項式來擬合,得到的擬合曲線是一個二次函數的曲線;
  • 如果使用n次多項式來擬合,得到的擬合曲線是一個n次函數的曲線;

也就是說,給你一系列可能是曲線的點,你可以選擇不同的函數來擬合這些點,得到擬合曲線函數。


注意看,上面兩個偏導=0的方程組求解,是把所有樣本代入進去進行求和:并不是一個樣本代入一個方程,而是所有樣本一起代入。

上面就是使用一次多項式曲線,注意,不是二次多項式,因為最小二乘法就是求距離的平方和最小值,所以接了個平方。


只需要記住,最小二乘法是用來求多項式的系數,所以求導是分別求平方和對各個系數的偏導,令偏導為0,就得到了方程組,把各個點的(xi,yi)一起代入方程組進行求解,就得到了多項式的系數。不過這個方程組可以使用矩陣的形式A*X=B來求解,利用opencv中的cv::solve函數可以求解。cv::solve函數可參考這篇博客:https://blog.csdn.net/nienelong3319/article/details/80855077


下面的截圖是推導:
其中公式里面的i=0有誤,都改為i=1,因為點是從(x1,y1)開始的。W3改為Wm


代碼部分

2.1 多項式擬合曲線C++代碼:

// 用最小二乘法根據點集擬合多項式系數 // order是設置的多項式次數 // is_x_axis是根據x軸的方向。因為像素坐標系的x,y和車身坐標系的x,y方向不一樣 // coeff是求出的系數向量(order+1行,1列) bool PolyCurveFit(const std::vector<Point2D<float>> &point_set, const int &order,const bool &is_x_axis, cv::Mat *coeff) {if (coeff == nullptr) {SERROR << "The pointer of coefficient matrix is null!";return false;}const int n = static_cast<int>(point_set.size());if (n <= order) {SERROR << "The number of points should be larger than the order.""The number of points = "<< n;return false;}cv::Mat A = cv::Mat::zeros(order + 1, order + 1, CV_64FC1);cv::Mat B = cv::Mat::zeros(order + 1, 1, CV_64FC1);// Fill matrix Afor (int i = 0; i < order + 1; ++i) {for (int j = 0; j < order + 1; ++j) {for (int k = 0; k < n;++k) { // 遍歷點,把每個點的x或y坐標都進行求i+j次方// 矩陣A的每個元素都是[x的冪],或[y的冪],最大冪為2*orderA.at<double>(i, j) +=std::pow(is_x_axis ? static_cast<double>(point_set.at(k).x): static_cast<double>(point_set.at(k).y),i + j);}}}// Fill matrix Bfor (int i = 0; i < order + 1; ++i) {// 遍歷點,把每個點都進行(x坐標求i次方)*y 或 (y坐標求i次方)*xfor (int k = 0; k < n; ++k) {// 矩陣B的每個元素都是[x的冪*y],或[y的冪*x],最大冪為orderB.at<double>(i, 0) +=std::pow(is_x_axis ? static_cast<double>(point_set.at(k).x): static_cast<double>(point_set.at(k).y),i) *(is_x_axis ? static_cast<double>(point_set.at(k).y): static_cast<double>(point_set.at(k).x));}}(*coeff) = cv::Mat::zeros(order + 1, 1, CV_64FC1);// 使用最小二乘法,最后優化問題化簡為,求A*X=B, 即 A*coeff=B,// 矩陣方程式有了,求未知系數矩陣X,使用的是LU矩陣分解算法// 這里就是求解order+1元order次方程組,求得就是系數if (!cv::solve(A, B, *coeff, cv::DECOMP_LU)) {SERROR << "Cannot solve polynomial coefficient!";return false;}return true; }

上面代碼是使用opencv的庫函數解出Ax=b中的x,這里的x就是系數coef。
如果是使用Eigen矩陣的話,那么代碼這樣的:

const int N = Order + 1; Eigen::MatrixXd matA(N, N); Eigen::VectorXd matB(N);/* 這里省略給矩陣A和向量B賦值 *///使用LU矩陣分解法求出系數矩陣coef Eigen::VectorXd coef = matA.lu().solve(matB);

2.2 求出一系列點的多項式之后,給出一個點的x值,就可以根據求出的多項式系數,求出該點的y值:

// 模板參數中的N是N次多項式的最高次數,N次多項式有N+1個多項式系數 // std::array<float, N + 1> poly_coeff是通過上面函數求出的多項式系數,可由Mat中轉存到array中 // 下面函數就是以 y=a+b*x+c*x^2+d*x^3+...的形式計算x值對應的y值 template <typename T, std::size_t N> T GetPolyValue(const std::array<float, N + 1> &poly_coeff, T x) {T value = 0;for (int i = 0; i < N+1; ++i) {value += poly_coeff[i] * std::pow(x, i);}return value; }

2.3 畫出x從0~100擬合曲線,x采樣間隔為0.3,使用圓圈在圖像上畫出這些點

  • (1) 如果擬合的多項式的點(x,y)本來就是像素坐標系的點,可以直接在圖像中畫出來:
for (float x = 0; x < 100; x += 0.3) {float y = GetPolyValue<float, 3>(poly_coeff, x);cv::Point point;point.x = x ;point.y = y;cv::circle(img_, point, 6, cv::Scalar(0, 255, 0)); }
  • (2) 如果x,y是車身坐標系的點,那么需要先轉化為像素坐標系的點,然后再到圖像中標出這些點:
for (float x = 0; x < 100; x += 0.3) {float y = GetPolyValue<float, 3>(poly_coeff, x);cv::Point point;//注意,車身坐標系的x,y和像素坐標系的y,x對應。并且像素坐標系原點在左上角,// 即車輛坐標系的x值Xc越大,其對應的像素坐標系Yp值越往上,Yp值就越小// 車輛坐標系的y值Yc向左為正,Yc值越大,其對應的像素坐標系的Xp值越小point.y = ph0 - static_cast<int>x ;point.x = pw0 - static_cast<int>y ;cv::circle(img_, point, 6, cv::Scalar(0, 255, 0)); } 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的【数学和算法】最小二乘法理论(附c++代码)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久精品一区 | 韩国中文三级hd字幕 | 国产黄色免费在线观看 | 免费在线毛片 | 国产精品久久综合青草亚洲AV | 欧美性生交大片免费看app麻豆 | 亚洲啊啊 | 国产色诱视频 | 日韩精品无码一区二区三区久久久 | 高清乱码免费看污 | 国产成人一区二区三区视频 | 一级片自拍 | 9l视频自拍蝌蚪9l视频 | 天天综合中文字幕 | 人妻精品一区二区在线 | 激情五月开心婷婷 | 正在播放老肥熟妇露脸 | 亚洲一区成人在线 | 欧美理论在线 | 中文字幕第2页 | 欧美亚洲精品一区二区 | 91福利一区 | 成人日韩视频 | 好吊妞操 | 日韩一区三区 | 黄在线网站 | 天堂网91 | 国产大片一区二区三区 | 中文字幕一区二区三区在线视频 | 夜夜爽妓女8888视频免费观看 | 久久久亚洲综合 | 国产黄a三级三级看三级 | 中文字幕自拍偷拍 | 伊人66| 欧美国产日韩在线 | 午夜在线播放 | 免费成人av | 91色视频在线 | 欧美区国产区 | 日韩电影一区二区三区四区 | 欧美专区在线视频 | 伊人网影院 | 五月天婷婷网站 | 精品久久久久久无码中文野结衣 | 人成在线免费视频 | 69社| 国产欧美一区二区视频 | 久久精品人妻av一区二区三区 | 黄色靠逼视频 | 国产精品毛片久久久 | 欧美日韩一区二区三区 | 欧美一级影院 | 黄色片视频免费观看 | 亚洲操片| 一区二区三区精 | 澳门三级 | 国产又爽又黄的激情精品视频 | 亚洲天堂高清 | 日本免费一区二区三区视频 | 伊人55| 成年人免费看的视频 | 97精品久久人人爽人人爽 | 亚洲天堂网视频 | 国产美女诱惑 | 日本成人精品 | 亚洲欧美激情另类校园 | 韩国伦理片观看 | 狠狠搞视频| 黄色不卡av| 欧美另类色 | 超碰在线最新地址 | 鲁丝一区二区三区 | 中国在线观看免费高清视频播放 | 五月激情小说 | 国产精品久久不卡 | 欧美手机在线 | 精品久久无码视频 | 国产黄色免费在线观看 | 男人爱看的网站 | 精品一区久久久 | www.国产91 | 亚洲AV无码精品色毛片浪潮 | 免费成人在线电影 | 亚洲精品一区 | 99精品亚洲| 丰满岳妇乱一区二区三区 | 91中文在线 | 久操热线| 午夜精品网站 | 五月天男人天堂 | 亲嘴扒胸摸屁股免费视频日本网站 | 亚洲欧美日本韩国 | 国产精品美女高潮无套 | 欧美视频在线播放 | 亚洲wwww | 国产va在线 | 日韩精品人妻一区二区三区免费 | 久久婷婷综合色 | 最新地址av |