道格拉斯-普克算法

道格拉斯-普克算法 [1]  (Douglas–Peucker algorithm,亦称为拉默-道格拉斯-普克算法、迭代适应点算法、分裂与合并算法)是将曲线近似表示为一系列点,并减少点的数量的一种算法。它的优点是具有平移和旋转不变性,给定曲线与阈值后,抽样结果一定。

算法步骤

  1. 连接曲线首尾两点A、B形成一条直线AB;
  2. 计算曲线上离该直线段距离最大的点C,计算其与AB的距离d;
  3. 比较该距离与预先给定的阈值threshold的大小,如果小于threshold,则以该直线作为曲线的近似,该段曲线处理完毕。
  4. 如果距离大于阈值,则用点C将曲线分为两段AC和BC,并分别对两段曲线进行步骤[1~3]的处理。
  5. 当所有曲线都处理完毕后,依次连接各个分割点形成折线,作为原曲线的近似。
 1 //DouglasPeucker.h
 2 #pragma once
 3 #include <vector>
 4 #include <stdio.h>
 5 #include <iostream>
 6 
 7 using namespace std;
 8 
 9 struct MyPointStruct//点云结构体 
10 {
11 public:
12     double X;
13     double Y;
14     double Z;
15     MyPointStruct()
16     {
17         this->X = 0;
18         this->Y = 0;
19         this->Z = 0;
20     };
21 
22     MyPointStruct(double x, double y, double z)
23     {
24         this->X = x;
25         this->Y = y;
26         this->Z = z;
27     };
28 
29     ~MyPointStruct() {};
30 };
31 
32 
33 
34 class DouglasPeucker :public MyPointStruct
35 {
36 public:
37     //MyPointStruct pointXYZ;
38     vector<MyPointStruct> PointStruct;
39     vector<bool> myTag; // 标记特征点的一个bool数组
40     vector<int> PointNum;//离散化得到的点号
41 
42 public:
43     DouglasPeucker(void);
44     DouglasPeucker(vector<MyPointStruct>& Points, int tolerance);
45     ~DouglasPeucker();
46 
47     void WriteData(const char *filename);
48 
49 private:
50     void DouglasPeuckerReduction(int firstPoint, int lastPoint, double tolerance);
51     double PerpendicularDistance(MyPointStruct &point1, MyPointStruct &point2, MyPointStruct &point3);
52     MyPointStruct& myConvert(int index);
53 };
View Code
 1 //DouglasPeucker.cpp
 2 
 3 #include "DouglasPeucker.h"
 4 #include <stdio.h>
 5 
 6 DouglasPeucker::DouglasPeucker()
 7 {
 8 
 9 }
10 
11 DouglasPeucker::DouglasPeucker(vector<MyPointStruct>& Points, int tolerance)
12 {
13     PointStruct = Points;
14     int totalPointNum = Points.size();
15 
16     myTag.resize(totalPointNum, 0);
17 
18     DouglasPeuckerReduction(0, totalPointNum - 1, tolerance);
19 
20     for (int index = 0; index < totalPointNum;index++)
21     {
22         if (myTag[index])
23         {
24             PointNum.push_back(index);
25         }
26     }
27 }
28 
29 
30 DouglasPeucker::~DouglasPeucker()
31 {
32 
33 }
34 
35 void DouglasPeucker::WriteData(const char *filename)
36 {
37     FILE *fp = fopen(filename, "w");
38     int pSize = PointNum.size();
39     for (int index = 0; index < pSize; index++)
40     {
41         fprintf(fp, "%lf\t%lf\n", PointStruct[PointNum[index]].X, PointStruct[PointNum[index]].Y);
42     }
43 }
44 
45 void DouglasPeucker::DouglasPeuckerReduction(int firstPoint, int lastPoint, double tolerance)
46 {
47     double maxDistance = 0;
48     int indexFarthest = 0; // 记录最大值时点元素在数组中的下标
49 
50     for (int index = firstPoint; index < lastPoint; index++)
51     {
52         double distance = PerpendicularDistance(myConvert(firstPoint),
53 
54             myConvert(lastPoint), myConvert(index));
55 
56         if (distance > maxDistance)
57         {
58             maxDistance = distance;
59             indexFarthest = index;
60         }
61     }
62     if (maxDistance > tolerance && indexFarthest != 0)
63     {
64         myTag[indexFarthest] = true; // 记录特征点的索引信息
65 
66         DouglasPeuckerReduction(firstPoint, indexFarthest, tolerance);
67         DouglasPeuckerReduction(indexFarthest, lastPoint, tolerance);
68     }
69 }
70 
71 double DouglasPeucker::PerpendicularDistance(MyPointStruct &point1, MyPointStruct &point2, MyPointStruct &point3)
72 {
73     // 点到直线的距离公式法
74     double A, B, C, maxDist = 0;
75     A = point2.Y - point1.Y;
76     B = point1.X - point2.X;
77     C = point2.X * point1.Y - point1.X * point2.Y;
78     maxDist = fabs((A * point3.X + B * point3.Y + C) / sqrt(A * A + B *B));
79     return maxDist;
80 }
81 
82 MyPointStruct& DouglasPeucker::myConvert(int index)
83 {
84     return PointStruct[index];
85 }
View Code

 

posted @ 2018-09-27 13:54  summer91  阅读(3931)  评论(0编辑  收藏  举报