• 利用RamerDouglasPeucker算法减少多边形轮廓点数


    部分童鞋应该可以从《使用方形游移匹配算法来勾勒图像轮廓》一文看到它的潜在用途了,只要获得图像的轮廓,转换成Box2D形状就相当容易。

    但有个问题,所生成的形状会有太多点,范例中处理的logo就多达2200点,太多。

    点的数量真心需要减少。为了解决这个问题,Ramer-Douglas-Peucker算法闪亮登场。

    该算法的思想为,给定一条由若干线段组成的曲线,找出包含的点数少且外观相近的曲线。

    该算法基于原始曲线与简化曲线直接最大间距定义了“dissimilar”。简化曲线由定义原始曲线的点的一个子集组成。

    Marius Karthaus为RDP算法写了一个非常不错的javascript范例,我在此基础上添加了部分内容将其移植到AS3,请参见19~75行:
    介于排版问题,代码贴于沙发
    RDP函数的第二个参数,即ε,用于约束全局,,范围介于0.2到0.8。

    看最后看一个例子,舞台右侧勾勒的轮廓仅仅用了343个点,使用的ε值为0.50:

    (wtf!背景白色看不出了,移驾原始页面看效果吧http://www.emanueleferonato.com/ ... archingsquares1.swf
    无需下载任何东西,只要将这段代码制粘贴到原始范例的Main类即可。

    View Code
      1 package {
      2         import flash.display.Sprite;
      3         import flash.display.BitmapData;
      4         import flash.display.Bitmap;
      5         import flash.geom.Matrix;
      6         import flash.geom.Point;
      7         public class Main extends Sprite {
      8                 private var bitmapData:BitmapData=new BitmapData(640,480,true,0x00000000);
      9                 // tolerance is the amount of alpha for a pixel to be considered solid
     10                 private var tolerance:Number=0x01;
     11                 public function Main() {
     12                         // adding a png image with transparency
     13                         bitmapData.draw(new Logo(278,429),new Matrix(1,0,0,1,20,40));
     14                         var bitmap:Bitmap=new Bitmap(bitmapData);
     15                         addChild(bitmap);
     16                         bitmap.alpha=0.5
     17                         // at the end of this function, marchingVector will contain the points tracing the contour
     18                         var marchingVector:Vector.<Point>=marchingSquares(bitmapData);
     19                         marchingVector=RDP(marchingVector,0.50);
     20                         var canvas:Sprite=new Sprite();
     21                         addChild(canvas);
     22                         canvas.graphics.moveTo(marchingVector[0].x+320,marchingVector[0].y);
     23                         for (var i:Number=0; i<marchingVector.length; i++) {
     24                                 canvas.graphics.lineStyle(2,0xffffff);
     25                                 canvas.graphics.lineTo(marchingVector[i].x+320,marchingVector[i].y);
     26                                 canvas.graphics.lineStyle(1,0xff0000);
     27                                 canvas.graphics.drawCircle(marchingVector[i].x+320,marchingVector[i].y, 2);
     28                         }
     29                         canvas.graphics.lineStyle(2,0xffffff);
     30                         canvas.graphics.lineTo(marchingVector[0].x+320,marchingVector[0].y);
     31                 }
     32 
     33                 public function RDP(v:Vector.<Point>,epsilon:Number):Vector.<Point> {
     34                         var firstPoint:Point=v[0];
     35                         var lastPoint:Point=v[v.length-1];
     36                         if (v.length<3) {
     37                                 return v;
     38                         }
     39                         var index:Number=-1;
     40                         var dist:Number=0;
     41                         for (var i:Number=1; i<v.length-1; i++) {
     42                                 var cDist:Number=findPerpendicularDistance(v[i],firstPoint,lastPoint);
     43                                 if (cDist>dist) {
     44                                         dist=cDist;
     45                                         index=i;
     46                                 }
     47                         }
     48                         if (dist>epsilon) {
     49                                 var l1:Vector.<Point>=v.slice(0,index+1);
     50                                 var l2:Vector.<Point>=v.slice(index);
     51                                 var r1=RDP(l1,epsilon);
     52                                 var r2=RDP(l2,epsilon);
     53                                 var rs:Vector.<Point>=r1.slice(0,r1.length-1).concat(r2);
     54                                 return rs;
     55                         }
     56                         else {
     57                                 return new Vector.<Point>(firstPoint,lastPoint);
     58                         }
     59                         return null;
     60                 }
     61 
     62                 private function findPerpendicularDistance(p:Point, p1:Point,p2:Point) {
     63                         var result;
     64                         var slope;
     65                         var intercept;
     66                         if (p1.x==p2.x) {
     67                                 result=Math.abs(p.x-p1.x);
     68                         }
     69                         else {
     70                                 slope = (p2.y - p1.y) / (p2.x - p1.x);
     71                                 intercept=p1.y-(slope*p1.x);
     72                                 result = Math.abs(slope * p.x - p.y + intercept) / Math.sqrt(Math.pow(slope, 2) + 1);
     73                         }
     74                         return result;
     75                 }
     76 
     77                 public function marchingSquares(bitmapData:BitmapData):Vector.<Point> {
     78                         var contourVector:Vector.<Point> = new Vector.<Point>();
     79                         // this is the canvas we'll use to draw the contour
     80                         var canvas:Sprite=new Sprite();
     81                         addChild(canvas);
     82                         canvas.graphics.lineStyle(2,0x00ff00);
     83                         // getting the starting pixel;
     84                         var startPoint:Point=getStartingPixel(bitmapData);
     85                         // if we found a starting pixel we can begin
     86                         if (startPoint!=null) {
     87                                 // moving the graphic pen to the starting pixel
     88                                 canvas.graphics.moveTo(startPoint.x,startPoint.y);
     89                                 // pX and pY are the coordinates of the starting point;
     90                                 var pX:Number=startPoint.x;
     91                                 var pY:Number=startPoint.y;
     92                                 // stepX and stepY can be -1, 0 or 1 and represent the step in pixels to reach
     93                                 // next contour point
     94                                 var stepX:Number;
     95                                 var stepY:Number;
     96                                 // we also need to save the previous step, that's why we use prevX and prevY
     97                                 var prevX:Number;
     98                                 var prevY:Number;
     99                                 // closedLoop will be true once we traced the full contour
    100                                 var closedLoop:Boolean=false;
    101                                 while (!closedLoop) {
    102                                         // the core of the script is getting the 2x2 square value of each pixel
    103                                         var squareValue:Number=getSquareValue(pX,pY);
    104                                         switch (squareValue) {
    105                                                         /* going UP with these cases:
    106                                                         
    107                                                         +---+---+   +---+---+   +---+---+
    108                                                         | 1 |   |   | 1 |   |   | 1 |   |
    109                                                         +---+---+   +---+---+   +---+---+
    110                                                         |   |   |   | 4 |   |   | 4 | 8 |
    111                                                         +---+---+   +---+---+  +---+---+
    112                                                         
    113                                                         */
    114                                                 case 1 :
    115                                                 case 5 :
    116                                                 case 13 :
    117                                                         stepX=0;
    118                                                         stepY=-1;
    119                                                         break;
    120                                                         /* going DOWN with these cases:
    121                                                         
    122                                                         +---+---+   +---+---+   +---+---+
    123                                                         |   |   |   |   | 2 |   | 1 | 2 |
    124                                                         +---+---+   +---+---+   +---+---+
    125                                                         |   | 8 |   |   | 8 |   |   | 8 |
    126                                                         +---+---+   +---+---+  +---+---+
    127                                                         
    128                                                         */
    129                                                 case 8 :
    130                                                 case 10 :
    131                                                 case 11 :
    132                                                         stepX=0;
    133                                                         stepY=1;
    134                                                         break;
    135                                                         /* going LEFT with these cases:
    136                                                         
    137                                                         +---+---+   +---+---+   +---+---+
    138                                                         |   |   |   |   |   |   |   | 2 |
    139                                                         +---+---+   +---+---+   +---+---+
    140                                                         | 4 |   |   | 4 | 8 |   | 4 | 8 |
    141                                                         +---+---+   +---+---+  +---+---+
    142                                                         
    143                                                         */
    144                                                 case 4 :
    145                                                 case 12 :
    146                                                 case 14 :
    147                                                         stepX=-1;
    148                                                         stepY=0;
    149                                                         break;
    150                                                         /* going RIGHT with these cases:
    151                                                         
    152                                                         +---+---+   +---+---+   +---+---+
    153                                                         |   | 2 |   | 1 | 2 |   | 1 | 2 |
    154                                                         +---+---+   +---+---+   +---+---+
    155                                                         |   |   |   |   |   |   | 4 |   |
    156                                                         +---+---+   +---+---+  +---+---+
    157                                                         
    158                                                         */
    159                                                 case 2 :
    160                                                 case 3 :
    161                                                 case 7 :
    162                                                         stepX=1;
    163                                                         stepY=0;
    164                                                         break;
    165                                                 case 6 :
    166                                                         /* special saddle point case 1:
    167                                                         
    168                                                         +---+---+ 
    169                                                         |   | 2 | 
    170                                                         +---+---+
    171                                                         | 4 |   |
    172                                                         +---+---+
    173                                                         
    174                                                         going LEFT if coming from UP
    175                                                         else going RIGHT 
    176                                                         
    177                                                         */
    178                                                         if (prevX==0&&prevY==-1) {
    179                                                                 stepX=-1;
    180                                                                 stepY=0;
    181                                                         }
    182                                                         else {
    183                                                                 stepX=1;
    184                                                                 stepY=0;
    185                                                         }
    186                                                         break;
    187                                                 case 9 :
    188                                                         /* special saddle point case 2:
    189                                                         
    190                                                         +---+---+ 
    191                                                         | 1 |   | 
    192                                                         +---+---+
    193                                                         |   | 8 |
    194                                                         +---+---+
    195                                                         
    196                                                         going UP if coming from RIGHT
    197                                                         else going DOWN 
    198                                                         
    199                                                         */
    200                                                         if (prevX==1&&prevY==0) {
    201                                                                 stepX=0;
    202                                                                 stepY=-1;
    203                                                         }
    204                                                         else {
    205                                                                 stepX=0;
    206                                                                 stepY=1;
    207                                                         }
    208                                                         break;
    209                                         }
    210                                         // moving onto next point
    211                                         pX+=stepX;
    212                                         pY+=stepY;
    213                                         // saving contour point
    214                                         contourVector.push(new Point(pX, pY));
    215                                         prevX=stepX;
    216                                         prevY=stepY;
    217                                         //  drawing the line
    218                                         canvas.graphics.lineTo(pX,pY);
    219                                         // if we returned to the first point visited, the loop has finished;
    220                                         if (pX==startPoint.x&&pY==startPoint.y) {
    221                                                 closedLoop=true;
    222                                         }
    223                                 }
    224                         }
    225                         return contourVector;
    226                 }
    227 
    228                 private function getStartingPixel(bitmapData:BitmapData):Point {
    229                         // finding the starting pixel is a matter of brute force, we need to scan
    230                         // the image pixel by pixel until we find a non-transparent pixel
    231                         var zeroPoint:Point=new Point(0,0);
    232                         var offsetPoint:Point=new Point(0,0);
    233                         for (var i:Number=0; i<bitmapData.height; i++) {
    234                                 for (var j:Number=0; j<bitmapData.width; j++) {
    235                                         offsetPoint.x=j;
    236                                         offsetPoint.y=i;
    237                                         if (bitmapData.hitTest(zeroPoint,tolerance,offsetPoint)) {
    238                                                 return offsetPoint;
    239                                         }
    240                                 }
    241                         }
    242                         return null;
    243                 }
    244 
    245                 private function getSquareValue(pX:Number,pY:Number):Number {
    246                         /*
    247                         
    248                         checking the 2x2 pixel grid, assigning these values to each pixel, if not transparent
    249                         
    250                         +---+---+
    251                         | 1 | 2 |
    252                         +---+---+
    253                         | 4 | 8 | <- current pixel (pX,pY)
    254                         +---+---+
    255                         
    256                         */
    257                         var squareValue:Number=0;
    258                         // checking upper left pixel
    259                         if (getAlphaValue(bitmapData.getPixel32(pX-1,pY-1))>=tolerance) {
    260                                 squareValue+=1;
    261                         }
    262                         // checking upper pixel
    263                         if (getAlphaValue(bitmapData.getPixel32(pX,pY-1))>tolerance) {
    264                                 squareValue+=2;
    265                         }
    266                         // checking left pixel
    267                         if (getAlphaValue(bitmapData.getPixel32(pX-1,pY))>tolerance) {
    268                                 squareValue+=4;
    269                         }
    270                         // checking the pixel itself
    271                         if (getAlphaValue(bitmapData.getPixel32(pX,pY))>tolerance) {
    272                                 squareValue+=8;
    273                         }
    274                         return squareValue;
    275                 }
    276 
    277                 private function getAlphaValue(n:Number):Number {
    278                         // given an ARGB color value, returns the alpha 0 -> 255
    279                         return n >> 24 & 0xFF;
    280                 }
    281         }
    282 }

     

    原文链接:算法减少多边形轮廓点数

    英文链接:http://www.emanueleferonato.com/2013/03/04/reduce-the-number-of-points-in-a-polygon-with-the-ramer-douglas-peucker-algorithm/

  • 相关阅读:
    SQL总结----存储过程
    SQL SERVER中的二种获得自增长ID的方法
    C#调用存储过程的ADO.Net
    扩展jQuery---选中指定索引的文本
    使用带参数的SQL语句向数据库中插入空值
    js中对小数取整
    Lr原理初识-慧测课堂笔记
    Https 安全传输的原理
    静态性能测试-慧测课堂笔记
    Docker常用命令
  • 原文地址:https://www.cnblogs.com/atong/p/2946539.html
Copyright © 2020-2023  润新知