Douglas Peucker算法的C#实现
一、算法原理
Douglas-Peucker算法
在数字化过程中,需要对曲线进行采样简化,即在曲线上取有限个点,将其变为折线,并且能够在一定程度
上保持原有的形状。
经典的Douglas-Peucker算法描述如下:
(1)在曲线首尾两点A,B之间连接一条直线AB,该直线为曲线的弦;
(2)得到曲线上离该直线段距离最大的点C,计算其与AB的距离D;
(3)比较该距离与预先给定的阈值threshold的大小,如果小于threshold,则该直线段作为曲线的近似,该段曲线处理完毕。
(4)如果距离大于阈值,则用C将曲线分为两段AC和BC,并分别对两段取信进行1~3的处理。
(5)当所有曲线都处理完毕时,依次连接各个分割点形成的折线,即可以作为曲线的近似。
二、算法C#实现
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace ConsoleApplication2 7 { 8 public struct cvPoint 9 { 10 public int X; 11 public int Y; 12 public cvPoint(int x, int y) 13 { 14 X = x; 15 Y = y; 16 } 17 } 18 class Program 19 { 20 static void Main(string[] args) 21 { 22 var points = new List<cvPoint>(); 23 points.Add(new cvPoint(1, 1)); 24 points.Add(new cvPoint(2, 2)); 25 points.Add(new cvPoint(3, 3)); 26 points.Add(new cvPoint(4, 3)); 27 points.Add(new cvPoint(5, 3)); 28 points.Add(new cvPoint(6, 3)); 29 points.Add(new cvPoint(5, 3)); 30 points.Add(new cvPoint(6, 3)); 31 points.Add(new cvPoint(7, 3)); 32 points.Add(new cvPoint(8, 3)); 33 var epsilon = 0.8d; 34 var filteredPoints = new List<cvPoint>(); 35 DouglasPeucker(points, epsilon, ref filteredPoints); 36 Console.WriteLine("Filtered points:"); 37 foreach (var f in filteredPoints) 38 { 39 Console.WriteLine(string.Format("{0},{1}", f.X, f.Y)); 40 } 41 Console.ReadKey(); 42 } 43 private static double distanceToSegment(cvPoint p, cvPoint start, cvPoint end) 44 { 45 var m1 = ((double)(end.Y - start.Y)) / ((double)(end.X - start.X)); 46 var c1 = start.Y - m1 * start.X; 47 var interPointX = 0d; 48 var interPointY = 0d; 49 if (m1 == 0) 50 { 51 interPointX = p.X; 52 interPointY = c1; 53 54 } 55 else 56 { 57 var m2 = -1 / m1; 58 var c2 = p.Y - m2 * p.X; 59 interPointX = (c1 - c2) / (m2 - m1); 60 interPointY = m2 * interPointX + c2; 61 } 62 return Math.Sqrt(Math.Pow(p.X - interPointX, 2) + Math.Pow(p.Y - interPointY, 2)); 63 } 64 65 private static void DouglasPeucker(IList<cvPoint> PointList, double epsilon, ref List<cvPoint> filteredPoints) 66 { 67 var dmax = 0d; 68 int index = 0; 69 int length = PointList.Count; 70 for (int i = 1; i < length - 1; i++) 71 { 72 var d = distanceToSegment(PointList[i], PointList[0], PointList[length - 1]); 73 Console.WriteLine(string.Format("{0}.distence:{1}", i, d)); 74 if (d > dmax) 75 { 76 index = i; 77 dmax = d; 78 } 79 } 80 Console.WriteLine(string.Format("dMax:{0}", dmax)); 81 // If max distance is greater than epsilon, recursively simplify 82 if (dmax > epsilon) 83 { 84 filteredPoints.Add(PointList[0]); 85 filteredPoints.Add(PointList[index]); 86 filteredPoints.Add(PointList[length - 1]); 87 DouglasPeucker(PointList.Take(index + 1).ToList(), epsilon, ref filteredPoints); 88 DouglasPeucker(PointList.Skip(index + 1).Take(PointList.Count - index - 1).ToList(), epsilon, ref filteredPoints); 89 } 90 } 91 } 92 }
三、算法验证
近似前:
近似后的线段:
本文地址: http://www.cnblogs.com/deepleo/p/Douglas-Peucker.html
参考:http://www.codeproject.com/Articles/18936/A-C-Implementation-of-Douglas-Peucker-Line-Approxi
阿里云9折优惠码:3RRWQH,第一次购买云服务器或云数据库可享受原价9折优惠,还可多人使用,拿走不谢。