提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
- 文章目录
-
目录
-
前言
众所周知,曲线拟合是图像识别中的重要技术,其中常用的就是直线拟合,拟合方式大概分为切比雪夫法和最小二乘法的方式,其中最小二乘法会有更多人使用
,在近期我也接触了这方面项目的设计和研究,以下是我的设计过程。
提示:以下是本篇文章正文内容,下面案例可供参考
一、最小二乘法是什么?
相信很多人和我一样听到了最小二乘法一开始是懵逼的状态,什么是最小二乘法?其实就是类似于线性回归方程,把散乱的点用一条直线方程表示出来,我不清楚这样描述是否正确,但是我大概清楚了自己要做什么了。
二、使用步骤
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设计直线的分段拟合,这一直在困扰我。初次发表还请多多指教,也希望能够帮助到有帮助的人。
文章出处登录后可见!
已经登录?立即刷新