最小二乘法直线拟合

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

前言

众所周知,曲线拟合是图像识别中的重要技术,其中常用的就是直线拟合,拟合方式大概分为切比雪夫法和最小二乘法的方式,其中最小二乘法会有更多人使用,在近期我也接触了这方面项目的设计和研究,以下是我的设计过程。

提示:以下是本篇文章正文内容,下面案例可供参考

一、最小二乘法是什么?

相信很多人和我一样听到了最小二乘法一开始是懵逼的状态,什么是最小二乘法?其实就是类似于线性回归方程,把散乱的点用一条直线方程表示出来,我不清楚这样描述是否正确,但是我大概清楚了自己要做什么了。

二、使用步骤

1.winform窗口设计

窗口设计如下:

最小二乘法直线拟合

 点击加载可以将你需要拟合的图像,加入图像后图像会出现在右侧,由于我做的是激光扫描后的图像,所以得到的都是黑点,每个黑点可以视为一个坐标,由此可以进行直线拟合,点击计算可以获取直线的方程表达式。

2.代码

代码如下:

(1)Argorithm.cs

获取黑点并进行拟合

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace DEMO
{
    class Argorithm
    {

        /// <summary>
        /// 获得黑色点
        /// </summary>
        /// <param name="img"></param>
        /// <returns></returns>
        static public List<Point> GetBlakePoints(Image img)
        {
            List<Point> blakePoints = new List<Point>();
            Point point = new Point();


            int height = img.Height;
            int width = img.Width;


            Bitmap bitmap = new Bitmap(img);

            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    Color color = bitmap.GetPixel(i, j);

                    if (color.R < 0x1F && color.G < 0x1F && color.B < 0x1F)
                    {
                        point.X = i;
                        point.Y = j;
                        blakePoints.Add(point);
                    }

                }
            }

            return blakePoints;
        }


        /*
        /// <summary>
        /// 最小二乘法直线拟合,直线方程 y = kx + b, Ax + By + C = 0
        /// </summary>
        /// <param name="points"></param>
        /// <param name="k"></param>
        /// <param name="b"></param>
        static public void CalculateLineViaLeastSquaresFitting(List<Point> points, ref int k, ref int b)//int *k   
        {
            k = 1;
            b = 80;
        }
         * */



        /// <summary>
        /// 最小二乘法直线拟合,直线方程 y = kx + b, Ax+By+C = 0
        /// </summary>
        /// <param name="points"></param>
        /// <param name="k"></param>
        /// <param name="b"></param>
        static public void CalculateLineViaLeastSquaresFitting(List<Point> points, ref double k, ref double b)
        {
            if (points.Count < 2)
            {
                throw new Exception("最小二乘法直线拟合失败"); ;
            }
            k = 0.0;
            b = 0.0;
            double Xavr = 0.0;
            double Yavr = 0.0;
            int N = points.Count;
           

            foreach (var pt in points)
            {
                Xavr += pt.X;
                Yavr += pt.Y;
            }
            Xavr = Xavr / N;
            Yavr = Yavr / N;
            double A = 0, B = 0, C = 0;
            for (int i = 0; i < N; i++)
            {
                double x = points[i].X - Xavr;
                double y = points[i].Y - Yavr;
                A += x * y;
                B += x * x - y * y;
                C += -x * y;
            }
            double k1 = (-B + Math.Sqrt(B * B - 4 * A * C)) / (2 * A);
            double k2 = (-B - Math.Sqrt(B * B - 4 * A * C)) / (2 * A);
           
            k = k1;
            b = Yavr - Xavr * k ;

            return;
        }
   }
}(2)MainForm.cs
加入图片,画出直线,显示直线方程

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DEMO
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnLoad_Click(object sender, EventArgs e)
        {

            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Multiselect = false;

            dialog.Title = "请选择BMP文件";
            dialog.Filter = "BMP文件(*.bmp)|*.bmp";

            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                string filename = dialog.FileName;
                Image orignalImg = Image.FromFile(filename);

 

                pbxMap.Image = orignalImg;

                //pbxMap.Height = orignalImg.Height;
                //pbxMap.Width = orignalImg.Width;


                MessageBox.Show(orignalImg.Width + "," + orignalImg.Height);
                
            }

        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnCal_Click(object sender, EventArgs e)
        {     
            

            if (null == pbxMap.Image)
            {
                MessageBox.Show("加载图片");
                return;
            }

            Graphics gra = pbxMap.CreateGraphics();

            List<Point> points = Argorithm.GetBlakePoints(pbxMap.Image);
            SolidBrush myBrush = new SolidBrush(Color.Blue);


            lbxMsg.Items.Add("共" + points.Count + "个点");

            //把所有黑点描成蓝点
            foreach (var tem in points)
            {
                gra.FillRectangle(myBrush, tem.X, tem.Y, 1, 1);
            }



            double k = 0;
            double b = 0;

            //调用函数
            Argorithm.CalculateLineViaLeastSquaresFitting(points, ref k, ref b);
       
            if (b >= 0)
            {
                lbxMsg.Items.Add("拟合方程: y = " + k + "x + " + b);
            }
            else
            {
                lbxMsg.Items.Add("拟合方程: y = " + k + "x - " + Math.Abs(b));
            }


            //开始点
            Point start = new Point();
            start.X = 200;
            start.Y = (int)(k * start.X + b);


            //结束点
            Point end = new Point();
            end.X = 20;
            end.Y = (int)(k * end.X + b);



            //画线
            myBrush = new SolidBrush(Color.Red);
            Pen pen = new Pen(myBrush);
            gra.DrawLine(pen, start, end);


        }





    }
}(3)Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace DEMO
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }
    }
}

效果图:

最小二乘法直线拟合

 

总结

以上就是今天要讲的内容,本文仅仅简单介绍了最小二乘法直线拟合的算法和应用,实际上我还想请教各位大佬怎么用这个winform设计直线的分段拟合,这一直在困扰我。初次发表还请多多指教,也希望能够帮助到有帮助的人。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2022年6月8日 上午10:34
下一篇 2022年6月8日 上午10:37

相关推荐