道格拉斯-普克 Douglas-Peuker(DP算法) python java实现
1、道格拉斯-普克抽稀算法說明
道格拉斯-普克抽稀算法是用來對大量冗余的圖形數據點進行壓縮以提取必要的數據點。
該算法實現抽稀的過程是:
1)對曲線的首末點虛連一條直線,求曲線上所有點與直線的距離,并找出最大距離值dmax,用dmax與事先給定的閾值D相比:?
2)若dmax<D,則將這條曲線上的中間點全部舍去;則該直線段作為曲線的近似,該段曲線處理完畢。?
?若dmax≥D,保留dmax對應的坐標點,并以該點為界,把曲線分為兩部分,對這兩部分重復使用該方法,即重復1),2)步,直到所有dmax均<D,即完成對曲線的抽稀。?
顯然,本算法的抽稀精度也與閾值相關,閾值越大,簡化程度越大,點減少的越多,反之,化簡程度越低,點保留的越多,形狀也越趨于原曲線。?
2、舉例說明
輸出結果:1.0 4.0,4.0 2.0,7.0 7.0,9.0 5.0,10.0 10.0,其中2 3,6 6,8 6兩個坐標被抽稀掉了。
示意圖:
假設在平面坐標系上有一條由N個坐標點組成的曲線,已設定一個閾值epsilon。
(1)首先,將起始點與結束點用直線連接, 再找出到該直線的距離最大,同時又大于閾值epsilon的點并記錄下該點的位置(這里暫且稱其為最大閾值點),如圖所示:
(2)接著,以該點為分界點,將整條曲線分割成兩段(這里暫且稱之為左曲線和右曲線),將這兩段曲線想象成獨立的曲線然后重復操作(1),找出兩邊的最大閾值點,如圖所示:
(3)最后,重復操作(2)(1)直至再也找不到最大閾值點為止,然后將所有最大閾值點按順序連接起來便可以得到一條更簡化的,更平滑的,與原曲線十分近似的曲線,如圖所示:
3、Java代碼實現
Point類:
public class Point {double x;double y;public Point(int x, int y) {this.x = x;this.y = y;System.out.print("(" + x + "," + y + ") ");}public static Point instance(int x, int y) {return new Point(x, y);} }DouglasPeuckerUtil 類:
public class DouglasPeuckerUtil {public static void main(String[] args) {System.out.print("原始坐標:");List<Point> points = new ArrayList<>();List<Point> result = new ArrayList<>();points.add(Point.instance(1, 1));points.add(Point.instance(2, 2));points.add(Point.instance(3, 4));points.add(Point.instance(4, 1));points.add(Point.instance(5, 0));points.add(Point.instance(6, 3));points.add(Point.instance(7, 5));points.add(Point.instance(8, 2));points.add(Point.instance(9, 1));points.add(Point.instance(10, 6));System.out.println("");System.out.println("=====================================================================");System.out.print("抽稀坐標:");result = DouglasPeucker(points, 1);for (Point p : result) {System.out.print("(" + p.x + "," + p.y + ") ");}}public static List<Point> DouglasPeucker(List<Point> points, int epsilon) {// 找到最大閾值點,即操作(1)double maxH = 0;int index = 0;int end = points.size();for (int i = 1; i < end - 1; i++) {double h = H(points.get(i), points.get(0), points.get(end - 1));if (h > maxH) {maxH = h;index = i;}}// 如果存在最大閾值點,就進行遞歸遍歷出所有最大閾值點List<Point> result = new ArrayList<>();if (maxH > epsilon) {List<Point> leftPoints = new ArrayList<>();// 左曲線List<Point> rightPoints = new ArrayList<>();// 右曲線// 分別提取出左曲線和右曲線的坐標點for (int i = 0; i < end; i++) {if (i <= index) {leftPoints.add(points.get(i));if (i == index)rightPoints.add(points.get(i));} else {rightPoints.add(points.get(i));}}// 分別保存兩邊遍歷的結果List<Point> leftResult = new ArrayList<>();List<Point> rightResult = new ArrayList<>();leftResult = DouglasPeucker(leftPoints, epsilon);rightResult = DouglasPeucker(rightPoints, epsilon);// 將兩邊的結果整合rightResult.remove(0);//移除重復點leftResult.addAll(rightResult);result = leftResult;} else {// 如果不存在最大閾值點則返回當前遍歷的子曲線的起始點result.add(points.get(0));result.add(points.get(end - 1));}return result;}/*** 計算點到直線的距離* * @param p* @param s* @param e* @return*/public static double H(Point p, Point s, Point e) {double AB = distance(s, e);double CB = distance(p, s);double CA = distance(p, e);double S = helen(CB, CA, AB);double H = 2 * S / AB;return H;}/*** 計算兩點之間的距離* * @param p1* @param p2* @return*/public static double distance(Point p1, Point p2) {double x1 = p1.x;double y1 = p1.y;double x2 = p2.x;double y2 = p2.y;double xy = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));return xy;}/*** 海倫公式,已知三邊求三角形面積* * @param cB* @param cA* @param aB* @return 面積*/public static double helen(double CB, double CA, double AB) {double p = (CB + CA + AB) / 2;double S = Math.sqrt(p * (p - CB) * (p - CA) * (p - AB));return S;}輸出結果:
?
4 Python代碼實現
4.1 遞歸實現
4.2 非遞歸實現
參考:
1、https://www.jianshu.com/p/bf595477a124
2、https://zhuanlan.zhihu.com/p/74906781
3、https://blog.csdn.net/cdl2008sky/article/details/7701769
?
?
?
總結
以上是生活随笔為你收集整理的道格拉斯-普克 Douglas-Peuker(DP算法) python java实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pycharm 自动生成文件注释和函数注
- 下一篇: Python2和Python3除法差别