首页 > 解决方案 > 从 C# 中的点列表中删除异常值

问题描述

问题

我在 Windows 窗体对象的面板上绘制了 C# 中的点列表。列表变量是 2listAlistB。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 上复制的最小可复制示例。请帮助,感谢您的时间和贡献。

预期产出

我添加了一张图片以明确我想要的结果 在此处输入图像描述

标签: c#graphicsoutliers

解决方案


如果您有许多点形成定义形状的线穿过的点云,那么您可以删除异常值。例如,请参阅删除异常值。但在这种情况下,列表中的每个点似乎都是形状的一个顶点。删除一个点会显着改变形状。

你能解释一下这些形状代表什么吗?如果您删除异常值,应该会发生什么?是否应该换成另一个点?

虽然这不是您问题的答案,但这里是代码的改进和简化版本:

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].


推荐阅读