c# - 从 C# 中的点列表中删除异常值
问题描述
问题
我在 Windows 窗体对象的面板上绘制了 C# 中的点列表。列表变量是 2listA
和listB
。in 的点就是 inlistB
的点,listA
只是它们经过了一些变换,将其变形为类似于点 in 形成的形状listA
,然后添加了一些异常值,使它们看起来不同。如果您可以在您的视觉工作室上尝试这些,那么这就是代码......
class Form1 : Form
{
//declare the list to hold points for
//shapes
List<Point> listA = new List<Point>();
List<Point> listB = new List<Point>();
//this methods transforms,applies outliers and draws the shapes on panel1
private void button1_click(EventArgs e, object sender)
{
//clear the lists for initializing
listA.Clear();
listB.Clear();
Point p1a = new Point(20, 30);
Point p2a = new Point(120, 50);
Point p3a = new Point(160, 80);
Point p4a = new Point(180, 300);
Point p5a = new Point(100, 220);
Point p6a = new Point(50, 280);
Point p7a = new Point(20, 140);
//Hold the Points in an array
Point[] mypoints = new Point[] { p1a, p2a, p3a, p4a, p5a, p6a, p7a };
//add the points to the List with one call
listA.AddRange(mypoints);
//define a new Transformation
//that will translate shapeA to have a slightly different imageB
Transformation t2 = new Transformation();
t2.A = 1.05; t2.B = 0.05; t2.T1 = 15; t2.T2 = 22;
//assign the new translated points to listB
listB = applytransformation(t2, listA);
//Add outliers to listb by manipulating the values in the list
Shape2[2] = new Point(Shape2[2].X + 10, Shape2[2].Y + 3);
//create a new instance of pen
//for drawing imageA in blue
Pen penner = new Pen(Brushes.Blue, 3);
//Create a new instance of pen for
//drawing imageB in red
Pen mypen = new Pen(Brushes.Red, 3);
//get the graphic context
Graphics g = panel1.CreateGraphics();
//draw both shapes
DisplayShape(listA, penner, g);
DisplayShape(listB, mypen, g);
}
//the method below does the transformation of imagea into imageb by manipulating the points and the transformation
List<Point> applytransformation(Transformation x, List<Point> shape)
{
List<Point> Tlist = new List<Point>();
foreach (Point c in shape) {
double xprime = x.A * c.X + x.B * c.Y + x.T1;
double yprime = x.B * c.X * -1 + x.A * c.Y + x.T2;
Point ptrans = new Point((int)xprime, (int)yprime);
Tlist.Add(ptrans);
}
//it returns the points that will be used to draw imageB
return Tlist;
}
//this method draws the points on the panel
void DisplayShape(List<Point> Shp, Pen pen, Graphics G)
{
Point? prevPoint = null;//nullable
foreach (Point pt in Shp) {
G.DrawEllipse(pen, new Rectangle(pt.X - 2, pt.Y - 2, 4, 4));
if (prevPoint != null) {
G.DrawLine(pen, (Point)prevPoint, pt);
}
prevPoint = pt;
}
G.DrawLine(pen, Shp[0], Shp[Shp.Count - 1]);
}
}
public class Transformation
{
public double A { get; set; }
public double B { get; set; }
public double T1 { get; set; }
public double T2 { get; set; }
}
目标
我想删除 imageB 中的所有异常值,以便它类似于 imageA,即使它不完美。欢迎所有方法或算法,即RANSAC,minimum cost function
。我试图在网上找到一个权威的资源,可以指导或帮助我在 C# 中以零成功实现这一目标。我提供的代码是可以在任何 Visual Studio IDE 上复制的最小可复制示例。请帮助,感谢您的时间和贡献。
预期产出
我添加了一张图片以明确我想要的结果
解决方案
如果您有许多点形成定义形状的线穿过的点云,那么您可以删除异常值。例如,请参阅删除异常值。但在这种情况下,列表中的每个点似乎都是形状的一个顶点。删除一个点会显着改变形状。
你能解释一下这些形状代表什么吗?如果您删除异常值,应该会发生什么?是否应该换成另一个点?
虽然这不是您问题的答案,但这里是代码的改进和简化版本:
List<Point> listA, listB; // Initialization not required.
private void button1_click(EventArgs e, object sender)
{
// Simplify initialization with collection and object initializers.
listA = new List<Point> {
new Point(20, 30), new Point(120, 50),
new Point(160, 80), new Point(180, 300),
new Point(100, 220), new Point(50, 280),
new Point(20, 140)
};
var t2 = new Transformation { A = 1.05, B = 0.05, T1 = 15, T2 = 22 };
listB = ApplyTransformation(t2, listA);
// Simplify shifting point.
Shape2[2] += new Size(10, 3);
// Invalidate panel and let Panel1_Paint draw it.
// Never create your own Graphics object.
panel1.Invalidate();
}
private void Panel1_Paint(object sender, PaintEventArgs e)
{
if (listA != null && listB != null) {
// Use predefined pens instead of creating brushes.
DisplayShape(listA, Pens.Blue, e.Graphics);
DisplayShape(listB, Pens.Red, e.Graphics);
}
}
List<Point> ApplyTransformation(Transformation x, List<Point> shape)
{
// Prevent list resizing by specifying initial size.
var transformedList = new List<Point>(shape.Count);
foreach (Point c in shape) {
double xprime = x.A * c.X + x.B * c.Y + x.T1;
double yprime = x.B * c.X * -1 + x.A * c.Y + x.T2;
transformedList.Add(new Point((int)xprime, (int)yprime));
}
return transformedList;
}
void DisplayShape(List<Point> shape, Pen pen, Graphics g)
{
// By using "for" instead of "foreach" we have indexes we can use to
// simplify closing the shape, since we always have a previous point.
for (int i = 0; i < shape.Count; i++) {
Point prevPoint = i > 0 ? shape[i - 1] : shape[shape.Count - 1];
Point pt = shape[i];
// No need to create a rectangle,
// there is an overload accepting location and size.
g.DrawEllipse(pen, pt.X - 2, pt.Y - 2, 4, 4);
g.DrawLine(pen, prevPoint, pt);
}
}
从 C# 8.0 和 .NET Core 项目开始,我们还可以编写shape[^1]
来获取最后一点,而不是shape[shape.Count - 1]
.
推荐阅读
- php - 当我们从文本框中按 Enter 键时,在单个 jQuery 方法中处理多个操作
- python - python读取和重写每行的值
- sql - Spring中的数据转换
- ios - 构建设置中缺少 Xcode 12 beta 有效架构
- android - Kotlin 上的 Android 手电筒
- git - 无法通过 git bash 提交更改,提交消息为空
- java - 通过 Java Servlet 将文件下载到特定位置
- java - 为什么 Java 不能识别这些空格?
- python - 在循环不同日期时获取重复数据以每天从 NewsApi 获取 100 篇文章(免费版本限制)
- elasticsearch - ElasticSearch 集处理器