2025年测绘程序设计比赛--基于统计滤波的点云去噪(已获国特)

小编最近的更新频率比较慢,是因为最近在准备这个全国大学生测绘学科创新创业智能大赛(测绘程序设计)--专业组的比赛,为了这个比赛,小编高强度的准备了一个月,也是取得了较为喜人的成绩。

如果有准备在2026年参加这个比赛的,可以加入小编和其它大佬所建的群242845175一起来备赛,为2026年的比赛打基础,也可以私信小编,为你答疑解惑

话不多说,接下来是代码与正文

一、读写数据文件

csharp 复制代码
public static List<Point> pts= new List<Point>();

public static List<Point> Readfile(string filename)
{
    string str;
    StreamReader sr = new StreamReader(filename);
    int n = 1;
    while(!sr.EndOfStream)
    {
        
        str= sr.ReadLine();
        string[]Buf=str.Split(new char[]{' ','\t'},StringSplitOptions.RemoveEmptyEntries);
        Point pt=new Point(double.Parse(Buf[0]), double.Parse(Buf[1]), double.Parse(Buf[2]),n);
        pts.Add(pt);
        n++;
    }
    return pts;
}
public static void Savefile(string report)
{
    SaveFileDialog sf=  new SaveFileDialog();
    sf.Filter = "文本数据|*.txt";
    sf.Title = "选择保存路径";
    sf.FileName = "result";
    if(sf.ShowDialog() == DialogResult.OK)
    {
        StreamWriter sw= new StreamWriter(sf.FileName);
        sw.Write(report);
        sw.Flush();
    }
}

二、点的相关属性

csharp 复制代码
    public class Point
    {
        public double x;
        public double y;
        public double z;
        public int n;

        //格网划分所需参数
        public int i;
        public int j;
        public int k;

        //候选点
        public List<Point> after=new List<Point>();
        //最近邻点
        public List<(int, double)> mind =new List<(int, double)>();

        //平均距离
        public double avd;
        public double sigema;

        //噪点判定
        public int number;
        public Point(double x, double y, double z,int n)
        {
            this.x= x; 
            this.y= y;
            this.z= z;
            this.n= n;
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(x.ToString()+" "+y.ToString()+" "+z.ToString()+" "+n.ToString());
            return sb.ToString();
        }
    }
}

三、格网划分与点云分配

csharp 复制代码
public static double fai = 3;
public static List<Point> zaopoint = new List<Point>(); 
//寻找各项极值
public static void Jizhi(out double xmax,out double ymax,out double zmax,out double xmin,out double ymin,out double zmin)
{
    xmax = Read.pts.Max(p => p.x);
    ymax = Read.pts.Max(p => p.y);
    zmax = Read.pts.Max(p => p.z);
    xmin = Read.pts.Min(p => p.x);
    ymin = Read.pts.Min(p => p.y);
    zmin = Read.pts.Min(p => p.z);
}

//计算格网最大值
public static void Gewang(out double xmax1,out double ymax1,out double zmax1)
{
    Jizhi(out double xmax, out double ymax, out double zmax, out double xmin, out double ymin, out double zmin);
    xmax1 = (int)((xmax - xmin) / fai + 1) * fai + xmin;
    ymax1 = (int)((ymax - ymin) / fai + 1) * fai + ymin;
    zmax1 = (int)((zmax - zmin) / fai + 1) * fai + zmin;
}

//格网划分
public static void Classify(List<Point> pts,out int sum)
{
    Jizhi(out double xmax, out double ymax, out double zmax, out double xmin, out double ymin, out double zmin);
    foreach (Point p in pts)
    {
        
        p.i = (int)((p.x - xmin) / fai);
        p.j = (int)((p.y - ymin) / fai);
        p.k = (int)((p.z - zmin) / fai);
    }
    //统计(0,0,0)的个数
    sum = 0;
    foreach(Point p in pts)
    {
        if (p.i == 0 && p.j == 0 && p.k == 0)
        {
            sum++;
        }
    }
}

四、k邻近点搜索(k=6)

值得注意的是,有些点的候选点可能不足6个,需要进行特殊处理(不足六个点,则全部选取)

csharp 复制代码
 //欧式距离计算
 public static double Distance(Point P1,Point P2)
 {
     double d = (P1.x - P2.x) * (P1.x - P2.x) + (P1.y - P2.y) * (P1.y - P2.y) + (P1.z - P2.z) * (P1.z - P2.z);
     return Math.Sqrt(d);
 }



 //统计点的候选点
 //(pt.i-p.i=1||pt.i-p.i=0||pt.i-p.i=-1)&&(pt.j-p.j=1||pt.j-p.j=0||pt.j-p.j=-1)&&(pt.k-p.k=1||pt.k-p.k=0||pt.k-p.k=-1)
 //Math.Abs(pt.i-p.i)<=1&& Math.Abs(pt.j - p.j) <= 1 && Math.Abs(pt.k - p.k) <= 1
 public static List<Point> Tongji(Point p)
 {
     List<Point> list = new List<Point>();
     foreach(Point pt in Read.pts)
     {
         if(Math.Abs(pt.i - p.i) <= 1 && Math.Abs(pt.j - p.j) <= 1 && Math.Abs(pt.k - p.k) <= 1)
         {
             list.Add(pt);//此处并未排除自身点,在后续输出中进行排除
         }
     }
     return list;
 }
 
 //计算每个点最近邻点
 public static void Mind(List<Point> pts)
 {
     foreach(Point pt in pts)
     {
         pt.after = Tongji(pt);
         List<(int,double)> list = new List< (int, double) >();
         foreach(Point p in pt.after)
         {
             if (p.n == pt.n)
             {
                 continue;
             }
             list.Add((p.n, Distance(pt,p)));

         }
        List<(int, double)> before = new List<(int, double)>();
        before = list.OrderBy(p => p.Item2).ToList();
         int k = 0;
         if (before.Count > 6)
         {
              k=6;
         }
         else
         {
             k=before.Count;
         }
        for (int i = 0; i < k; i++)
        {
            pt.mind.Add(before[i]);
        }
        
     }
 }

五、统计特征计算

csharp 复制代码
//计算每个点的平均距离和标准差
public static void Alhelp(List<Point> pts)
{
    foreach(Point pt in pts)
    {
        pt.avd = pt.mind.Average(p => p.Item2);
        double sum = 0;
        for(int i=0;i < pt.mind.Count; i++)
        {
            sum += (pt.mind[i].Item2 - pt.avd) * (pt.mind[i].Item2 - pt.avd);
        }
        pt.sigema=Math.Sqrt(sum/ pt.mind.Count);
    }
}

//计算全局平均距离均值和标准差
public static void Allpoint(out double avds,out double sigemas)
{
    avds=Read.pts.Average(p=>p.avd);
    sigemas=Read.pts.Average(p=> p.sigema);
}

六、全局噪点判断

csharp 复制代码
 //全局判断噪点
 public static void Alljudge(List<Point> pts)
 {
     Allpoint(out double avds, out double sigemas);
     foreach (Point pt in pts)
     {
         if(pt.avd > (avds + 2 * sigemas))
         {
             pt.number = 1;
             
         }
         else
         {
             zaopoint.Add(pt);
             pt.number = 0;
         }
     }
 }

窗体交互

csharp 复制代码
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        openFile.FileOk += openFile_FileOk;
    }
    public static List<Point> before=new List<Point>();
    public string report;

    private void toolStripLabel1_Click(object sender, EventArgs e)
    {
        if (openFile.ShowDialog() == DialogResult.OK)
        {
            string name=openFile.FileName; 
            before=Read.Readfile(name);
            dataGridView1.RowCount= before.Count;
            for(int i = 0; i < before.Count; i++)
            {
                dataGridView1[0, i].Value = before[i].x;
                dataGridView1[1,i].Value = before[i].y;
                dataGridView1[2,i].Value = before[i].z;
            }
        }
    }

    private void openFile_FileOk(object sender, CancelEventArgs e)
    {

    }

    private void toolStripLabel2_Click(object sender, EventArgs e)
    {
        report += "1\t点 P1 的 x 坐标 " + Read.pts[0].x.ToString("F3") + "\n";
        report += "2\t点 P6 的 y 坐标 " + Read.pts[5].y.ToString("F3") + "\n";
        report += "3\t点 P789 的 z 坐标 " + Read.pts[788].z.ToString("F3") + "\n";
        report += "4\t原始点云的总点数 " + Read.pts.Count + "\n";

        Alpoint.Jizhi(out double xmax,out double ymax,out double zmax,out double xmin,out double ymin,out double zmin);
        Alpoint.Gewang(out double xmax1, out double ymax1, out double zmax1);
        report += "5\t点云数据x最大值 " + xmax.ToString("F3") + "\n";
        report += "6\t点云数据y最大值 " + ymax.ToString("F3") + "\n";
        report += "7\t点云数据z最大值" + zmax.ToString("F3") + "\n";
        report += "8\t格网 xmin " + xmin.ToString("F3") + "\n";
        report += "9\t格网 xmax1 " + xmax1.ToString("F3") + "\n";
        report += "10\t格网 ymin " + ymin.ToString("F3") + "\n";
        report += "11\t格网 ymax1 " + ymax1.ToString("F3") + "\n";
        report += "12\t格网 zmin" + zmin.ToString("F3") + "\n";
        report += "13\t格网 zmax1 " + zmax1.ToString("F3") + "\n";
        Alpoint.Classify(Read.pts, out int sum);
        report += "14\t网格 (0,0,0) 内的点个数 " + sum + "\n";
        report += "15\t点 P1 的网格索引(i,j,k)中i分量 " + Read.pts[0].i + "\n";
        report += "16\t点 P6 的网格索引(i,j,k)中j分量" + Read.pts[5].j + "\n";
        Alpoint.Mind(Read.pts);
        report += "17\t点 P1 的候选点总数 " + (Read.pts[0].after.Count-1) + "\n";
        report += "18\t点 P6 的候选点总数 " + (Read.pts[5].after.Count-1) + "\n";
        int b = Read.pts[5].mind.Max(p => p.Item1);
        int a = Read.pts[0].mind.Max(p => p.Item1);
        report += "19\t点 P1 的 6 个邻近点序号中最大值" + a + "\n";
        report += "20\t点 P6 的 6 个邻近点序号中最大值 " + b+ "\n";
        Alpoint.Alhelp(Read.pts);
        Alpoint.Allpoint(out double avds, out double sigemas);
        Alpoint.Alljudge(Read.pts);
        report += "21\t点 P1 的邻域平均距离 u₁ " + Read.pts[0].avd.ToString("F3") + "\n";
        report += "22\t点 P1 的邻域距离标准差 σ₁ " + Read.pts[0].sigema.ToString("F3") + "\n";
        report += "23\t点 P6 的邻域平均距离 u₆" + Read.pts[5].avd.ToString("F3") + "\n";
        report += "24\t点 P6 的邻域距离标准差 σ₆ " + Read.pts[5].sigema.ToString("F3") + "\n";
        report += "25\t全局平均距离均值 μ " + avds.ToString("F3") + "\n";
        report += "26\t全局距离标准差 σ " + sigemas.ToString("F3") + "\n";
        report += "27\t点 P1 是否为噪声点(0、1分别表示否、是) " + Read.pts[0].number + "\n";
        report += "28\t点 P6 是否为噪声点(0、1分别表示否、是)" + Read.pts[5].number + "\n";
        report += "29\t去噪后保留的点云总数 " + Alpoint.zaopoint.Count + "\n";


        richTextBox1.Text = report;
        
    }

    private void toolStripLabel3_Click(object sender, EventArgs e)
    {
        Read.Savefile(report);
    }
}

七,运行结果

1 点 P1 的 x 坐标 533599.690

2 点 P6 的 y 坐标 3377146.850

3 点 P789 的 z 坐标 28.890

4 原始点云的总点数 44518

5 点云数据x最大值 533774.000

6 点云数据y最大值 3377195.000

7 点云数据z最大值113.120

8 格网 xmin 533574.000

9 格网 xmax1 533775.000

10 格网 ymin 3377000.000

11 格网 ymax1 3377198.000

12 格网 zmin8.560

13 格网 zmax1 113.560

14 网格 (0,0,0) 内的点个数 0

15 点 P1 的网格索引(i,j,k)中i分量 8

16 点 P6 的网格索引(i,j,k)中j分量48

17 点 P1 的候选点总数 69

18 点 P6 的候选点总数 47

19 点 P1 的 6 个邻近点序号中最大值44391

20 点 P6 的 6 个邻近点序号中最大值 1508

21 点 P1 的邻域平均距离 u₁ 1.981

22 点 P1 的邻域距离标准差 σ₁ 0.329

23 点 P6 的邻域平均距离 u₆1.411

24 点 P6 的邻域距离标准差 σ₆ 0.186

25 全局平均距离均值 μ 1.668

26 全局距离标准差 σ 0.339

27 点 P1 是否为噪声点(0、1分别表示否、是) 0

28 点 P6 是否为噪声点(0、1分别表示否、是)0

29 去噪后保留的点云总数 42555

八、报告文档

第一页为封面

第二页为目录

后面为正常模板





总结

本次的比赛也是收获匪浅,总体来说,还是要多练,今年的题目明显带有一定的挑战性质,需要不断多练,不要抱有侥幸心理,认为考过相似的题,就不会再考了,这几年的竞争压力还是很大的,所以一定要抓住时间,勤奋多练,我和诸多大佬都会在群里为你们答疑解惑的,C#,python,C++都有的,欢迎大家进群讨论242845175

相关推荐
做一位快乐的码农几秒前
基于springboot的在线考试系统/考试信息管理平台
java·struts·spring·eclipse·tomcat·maven·hibernate
创码小奇客5 分钟前
Spring Boot 集成 Talos:打造智能调参系统,让模型性能自动飙升
java·spring boot·trae
kyranhan10 分钟前
C#程序本地运行正常,通过网络下载报错:FileLoadException:“未能加载文件或程序集“xxx.dll”或它的某一个依赖项。
开发语言·c#·wpf
Yueeyuee_26 分钟前
【C#学习Day14笔记】泛型、集合(数组列表Arraylist、列表list)与字典
笔记·学习·c#
探索java1 小时前
Spring lookup-method实现原理深度解析
java·后端·spring
好好先森&1 小时前
C语言:模块化编程
c语言·c++·windows
lxsy1 小时前
spring-ai-alibaba 之 graph 槽点
java·后端·spring·吐槽·ai-alibaba
重生之我是Java开发战士1 小时前
【C语言】结构体详解
c语言·开发语言
FuckPatience1 小时前
Winform 渐变色 调色板
.net
先鱼鲨生1 小时前
gtest框架的安装与使用
开发语言·apache