【点云学习】 源代码和关键功能介绍

导览

源代码和关键功能代码介绍

  1. 工程源代码下载
  2. 图像坐标系转换
  3. UI设计代码

01

工程和源代码下载

https://pan.baidu.com/s/1XaKFZLudnnISui7lV8540A

提取码:5ytm

现已经支持的点格式:.asc/.csv/.xyz

02

图像坐标系转化

窗口的交互设计都是基于C#中的PictureBox的坐标系

图像原点与图像框坐标原点

我们基于鼠标事件得到坐标都是基于图像框坐标系的,我们的点云坐标是与图像坐标对应的,因此需要将图像框的坐标转换到图片的坐标。

一般经过两次变化:平移+缩放

平移

缩放

代码语言:javascript
复制
        private Point TransImageToPicbox(Point e)
        {
            try
            {
                //取得当前图像在图片框中的位置和长宽
                rectangle_curr = (Rectangle)pictureBox1.GetType().GetProperty("ImageRectangle", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(pictureBox1, null);
                int currentWidth = rectangle_curr.Width;
                int currentHeight = rectangle_curr.Height;
                //计算缩放系数
                double rate_h = (double)currentHeight / (double)pictureBox1.Image.Height; double rate_w = (double)currentWidth / (double)pictureBox1.Image.Width;
                //计算XY偏移
                int black_left_width = (currentWidth == this.pictureBox1.Width) ? 0 : (this.pictureBox1.Width - currentWidth) / 2;
                int black_top_height = (currentHeight == this.pictureBox1.Height) ? 0 : (this.pictureBox1.Height - currentHeight) / 2;
                int zoom_x = e.X - black_left_width;
                int zoom_y = e.Y - black_top_height;
                double original_x = (double)zoom_x / rate_w;
                double original_y = (double)zoom_y / rate_h;
                //如果鼠标落在图片区域外则返回原点坐标
                if (e.X < black_left_width || e.X >= currentWidth + rectangle_curr.Location.X)
                {
                    return new Point(0, 0);
                }
                if (e.Y < black_top_height || e.Y >= currentHeight + rectangle_curr.Location.Y)
                {
                    return new Point(0, 0);
                }
                //返回实际图像坐标
                return new Point((int)original_x, (int)original_y);
            }
            catch (Exception)
            {
                return new Point(0, 0);
            }
        }

02

交互代码

通过鼠标拉线获取线上所有点云数据

1.设置鼠标事件 2.

代码语言:javascript
复制
        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
//鼠标按下时,记录开始点坐标
          StrPoint_pic = e.Location;
//转换坐标系到图像          
          StrPoint = TransImageToPicbox(e.Location);
          break;
        }                        

3.

代码语言:javascript
复制
        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
//鼠标松开记录结束点坐标        
        bitmap = (Bitmap)pictureBox1.Image;
        Graphics graphics = Graphics.FromImage(this.bitmap);
        EndPoint_pic = e.Location;
//转换坐标系到图像        
        EndPoint = TransImageToPicbox(new Point(EndPoint_pic.X, StrPoint_pic.Y));
        double[] data = new double[Get_Point_line(StrPoint, EndPoint).Count]; int count = 0;
        foreach (Point3 item in Get_Point_line(StrPoint, EndPoint))
        {
             data[count] = item.Z; count++;
        }
        FileOpt.data_buffer = data.ToList();
        chart.chart1.ChartAreas[0].AxisY.Maximum = data.Max() + 10; chart.chart1.ChartAreas[0].AxisY.Minimum = data.Min() - 10;
        chart.chart1.Series[0].IsValueShownAsLabel = false;
        chart.chart1.Series[0].Points.DataBindY(data);
//将两点的连线画在图像上        
        graphics.DrawLine(new Pen(Color.Red, 3), StrPoint, EndPoint);
        pictureBox1.Image = bitmap;
        break;
}                 

4.计算线的图像坐标系方程

5.

代码语言:javascript
复制
        private List<Point3> Get_Point_line(Point str,Point end)
        {
            //声明直线方程的k和b,声明一个存放线上点云数据的表
            float k;float b;List<Point3> point_list1 = new List<Point3>();
            try
            {
            Point3 point3 = new Point3();
            k = (float)(end.Y - str.Y) /(float)(end.X - str.X);
            b = str.Y - k * (float)str.X;
            //k存在,k&gt;1或者0&gt;k&gt;-1
            if (k&gt;1||((k&lt;0)&amp;&amp;(k&lt;-1)))
            {
                for (int i = Math.Min(str.Y, end.Y); i &lt; Math.Max(str.Y, end.Y); i++)
                {
                    point3.Y = i; point3.X = (int)((i-b)/k); point3.Z = FileOpt.datamat_buffer[point3.X, point3.Y];
                    point_list1.Add(point3);
                }
                point_list = point_list1;
            }
            //k存在,k&lt;1或者k&lt;-1
            else

            {
                for (int i = Math.Min(str.X, end.X); i &lt; Math.Max(str.X, end.X); i++)
                {
                    point3.X = i; point3.Y = (int)(k * (float)i + b); point3.Z = FileOpt.datamat_buffer[point3.X, point3.Y];
                    point_list1.Add(point3);
                }
                point_list = point_list1;
            }
            return point_list1;
        }
        catch (Exception)
        {
            //k不存在,此时线属于铅垂线
            Point3 point3 = new Point3();
            for (int i = Math.Min(str.Y, end.Y); i &lt; Math.Max(str.Y, end.Y); i++)
            {
                point3.X = str.X; point3.Y = i; point3.Z = FileOpt.datamat_buffer[point3.X, point3.Y];
                point_list1.Add(point3);
            }
            point_list = point_list1;
            return point_list1;
            throw;
        }
    }</code></pre></div></div><p>小结</p><p>       1. 坐标系变化</p><p>       2. 交互设计</p>