Advertisement
WarPie90

DistanceTransform

Sep 17th, 2023
1,242
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 3.20 KB | None | 0 0
  1. {*
  2.  Distance transform
  3. *}
  4.  
  5. type EDistUnit = (duEuclidean, duManhatten, duChebyshev);
  6.  
  7. function dtEucDist(x1,x2:Int32): Int32;
  8. begin
  9.   Result := Sqr(x1) + Sqr(x2);
  10. end;
  11.  
  12. function dtEucSep(i,j, ii,jj:Int32): Int32;
  13. begin
  14.   Result := Round((sqr(j) - sqr(i) + sqr(jj) - sqr(ii))/(2*(j-i)));
  15. end;
  16.  
  17.  
  18. function dtMtnDist(x1, x2: Int32): Int32;
  19. begin
  20.   Result := Abs(x1) + x2
  21. end;
  22.  
  23. function dtMtnSep(i,j, ii, jj: Int32): Int32;
  24. begin
  25.   if (jj >= (ii + j - i)) then
  26.     Exit($FFFFFF);
  27.   if (ii > (jj + j - i)) then
  28.     Exit(-$FFFFFF);
  29.   Result := (jj-ii+j+i) shr 1;
  30. end;
  31.  
  32. function dtChbDist(x1, x2: Int32): Int32;
  33. begin
  34.   Result := Max(Abs(x1), x2);
  35. end;
  36.  
  37.  
  38. function dtChbSep(i,j, ii,jj: Int32): Int32;
  39. begin
  40.   if (ii <= jj) then
  41.     Result := Max(i+jj, Trunc((i+j) / 2))
  42.   else
  43.     Result := Min(j-ii, Trunc((i+j) / 2));
  44. end;
  45.  
  46.  
  47. function DistanceTransform(const binIm:TIntegerArray; m,n:Int32; distanceUnit:EDistUnit): TSingleMatrix;
  48. type
  49.   TSepFunc = function(i,j, ii,jj: Int32): Int32;
  50.   TDistFunc = function(x1,x2: Int32): Int32;
  51. var
  52.   x,y,h,w,i,wid:Int32;
  53.   dist: single;
  54.   tmp,s,t:TIntegerArray;
  55.   sf: TSepFunc;
  56.   df: TDistFunc;
  57. begin
  58.   // first pass
  59.   SetLength(tmp, m*n);
  60.   h := n-1;
  61.   w := m-1;
  62.   for x:=0 to w do
  63.   begin
  64.     if binIm[x] = 0 then
  65.       tmp[x] := 0
  66.     else
  67.       tmp[x] := m+n;
  68.  
  69.     for y:=1 to h do
  70.       if (binIm[y*m+x] = 0) then
  71.         tmp[y*m+x] := 0
  72.       else
  73.         tmp[y*m+x] := 1 + tmp[(y-1)*m+x];
  74.  
  75.     for y:=h-1 downto 0 do
  76.       if (tmp[(y+1)*m+x] < tmp[y*m+x]) then
  77.         tmp[y*m+x] := 1 + tmp[(y+1)*m+x]
  78.   end;
  79.  
  80.  
  81.   case distanceUnit of
  82.     duEuclidean:
  83.     begin
  84.       df := @dtEucDist;
  85.       sf := @dtEucSep;
  86.     end;
  87.     duManhatten:
  88.     begin
  89.       df := @dtMtnDist;
  90.       sf := @dtMtnSep;
  91.     end;
  92.     duChebyshev:
  93.     begin
  94.       df := @dtChbDist;
  95.       sf := @dtChbSep;
  96.     end;
  97.   end;
  98.  
  99.   // second pass
  100.   SetLength(Result,n,m);
  101.   SetLength(s,m);
  102.   SetLength(t,m);
  103.   wid := 0;
  104.   for y:=0 to h do
  105.   begin
  106.     i := 0;
  107.     s[0] := 0;
  108.     t[0] := 0;
  109.  
  110.     for x:=1 to W do
  111.     begin
  112.       while (i >= 0) and (df(t[i]-s[i], tmp[y*m+s[i]]) > df(t[i]-x, tmp[y*m+x])) do
  113.         Dec(i);
  114.       if (i < 0) then
  115.       begin
  116.         i := 0;
  117.         s[0] := x;
  118.       end else
  119.       begin
  120.         wid := 1 + sf(s[i], x, tmp[y*m+s[i]], tmp[y*m+x]);
  121.         if (wid < m) then
  122.         begin
  123.           Inc(i);
  124.           s[i] := x;
  125.           t[i] := wid;
  126.         end;
  127.       end;
  128.     end;
  129.  
  130.     for x:=W downto 0 do
  131.     begin
  132.       dist := df(x-s[i], tmp[y*m+s[i]]);
  133.       if distanceUnit = duEuclidean then dist := Sqrt(dist);
  134.  
  135.       Result[y,x] := dist;
  136.       if (x = t[i]) then Dec(i);
  137.     end;
  138.   end;
  139. end;
  140.  
  141.  
  142. function DistanceTransform(const TPA:TPointArray; distanceUnit:EDistUnit): TSingleMatrix; overload;
  143. var
  144.   data:TIntegerArray;
  145.   w,h,n,i:Int32;
  146.   area:TBox;
  147. begin
  148.   n := Length(TPA);
  149.   if (n = 0) then Exit;
  150.   area := GetTPABounds(TPA);
  151.   area.y1 -= 1;
  152.   area.x1 -= 1;
  153.   w := (area.x2 - area.x1) + 2;
  154.   h := (area.y2 - area.y1) + 2;
  155.   SetLength(data, h*w);
  156.   for i:=0 to n-1 do
  157.     data[(TPA[i].y-area.y1)*w+(TPA[i].x-area.x1)] := 1;
  158.  
  159.   Result := DistanceTransform(data,w,h,distanceUnit);
  160. end;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement