Python實現曲線點抽稀演算法的示例
阿新 • • 發佈:2021-06-22
目錄
-
何為抽稀
-
道格拉斯-普克(Douglas-Peuker)演算法
-
垂距限值法
-
最後
正文
在處理向量化資料時,記錄中往往會有很多重複資料,對進一步資料處理帶來諸多不便。多餘的資料一方面浪費了較多的儲存空間,另一方面造成所要表達的圖形不光滑或不符合標準。因此要通過某種規則,在保證向量曲線形狀不變的情況下, 最大限度地減少資料點個數,這個過程稱為抽稀。
通俗的講就是對曲線進行取樣簡化,即在曲線上取有限個點,將其變為折線,並且能夠在一定程度保持原有形狀。比較常用的兩種抽稀演算法是:道格拉斯- 普克(Douglas-Peuker)演算法和垂距限值法。
道格拉斯-普克(Douglas-Peuker)演算法
Douglas-Peuker演算法(DP演算法)過程如下:
1、連線曲線首尾兩點A、B; 2、依次計算曲線上所有點到A、B兩點所在曲線的距離; 3、計算最大距離D,如果D小於閾值threshold,則去掉曲線上出A、B外的所有點;如果D大於閾值threshold,則把曲線以最大距離分割成兩段; 4、對所有曲線分段重複1-3步驟,知道所有D均小於閾值。即完成抽稀。 這種演算法的抽稀精度與閾值有很大關係,閾值越大,簡化程度越大,點減少的越多;反之簡化程度越低,點保留的越多,形狀也越趨於原曲線。
下面是Python程式碼實現:
# -*- coding: utf-8 -*-
"""------------------------------------------------- File Name: DouglasPeuker Description : 道格拉斯-普克抽稀演算法 Author : J_hao date: 2017/8/16------------------------------------------------- Change Activity: 2017/8/16: 道格拉斯-普克抽稀演算法-------------------------------------------------"""
from __future__ import division
from math import sqrt, pow
__author__ = 'J_hao'
THRESHOLD = 0.0001 # 閾值
def point2LineDistance(point_a, point_b, point_c):
""" 計算點a到點b c所在直線的距離 :param point_a: :param point_b: :param point_c: :return: """
# 首先計算b c 所在直線的斜率和截距
if point_b[0] == point_c[0]:
return 9999999
slope = (point_b[1] - point_c[1]) / (point_b[0] - point_c[0])
intercept = point_b[1] - slope * point_b[0]
# 計算點a到b c所在直線的距離
distance = abs(slope * point_a[0] - point_a[1] + intercept) / sqrt(1 + pow(slope, 2))
return distance
class DouglasPeuker(object):
def__init__(self):
self.threshold = THRESHOLD
self.qualify_list = list()
self.disqualify_list = list()
def diluting(self, point_list):
""" 抽稀 :param point_list:二維點列表 :return: """
if len(point_list) < 3:
self.qualify_list.extend(point_list[::-1])
else:
# 找到與收尾兩點連線距離最大的點
max_distance_index, max_distance = 0, 0
for index, point in enumerate(point_list):
if index in [0, len(point_list) - 1]:
continue
distance = point2LineDistance(point, point_list[0], point_list[-1])
if distance > max_distance:
max_distance_index = index
max_distance = distance
# 若最大距離小於閾值,則去掉所有中間點。 反之,則將曲線按最大距離點分割
if max_distance < self.threshold:
self.qualify_list.append(point_list[-1])
self.qualify_list.append(point_list[0])
else:
# 將曲線按最大距離的點分割成兩段
sequence_a = point_list[:max_distance_index]
sequence_b = point_list[max_distance_index:]
for sequence in [sequence_a, sequence_b]:
if len(sequence) < 3 and sequence == sequence_b:
self.qualify_list.extend(sequence[::-1])
else:
self.disqualify_list.