Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

151
LINES

< > BotCompany Repo | #1035003 // G22RegionThinner_v2 - thin a region to 2 pixel wide [OK backup without final thinning]

JavaX fragment (include) [tags: use-pretranspiled]

Libraryless. Click here for Pure Java version (9070L/50K).

1  
srecord noeq G22RegionThinner_v2<Img extends WidthAndHeight>(IImageRegion<Img> originalRegion) is Steppable {
2  
  Rect bounds;
3  
  IImageRegion<Img> region;
4  
  bool phase1done;
5  
  
6  
  // 0 = outside of region
7  
  // 1 = inner pixel
8  
  // 2 = border pixel
9  
  // index is in bounds coordinates
10  
  byte[] pixels;
11  
  
12  
  int idx(int x, int y) {
13  
    ret (y-bounds.y)*bounds.w+x-bounds.x;
14  
  }
15  
  int idx(Pt p) { ret idx(p.x, p.y); }
16  
  
17  
  Pt idxToPt(int idx) {
18  
    ret pt(bounds.x+(idx % bounds.w), bounds.y+idx/bounds.w);
19  
  }
20  
  
21  
  byte getPixel(Pt p) {
22  
    ret !containsPt(bounds, p) ? 0 : pixels[idx(p)];
23  
  }
24  
  
25  
  byte getPixel(int x, int y) {
26  
    ret !containsPt(bounds, x, y) ? 0 : pixels[idx(x, y)];
27  
  }
28  
  
29  
  bool contains(int x, int y) {
30  
    ret getPixel(x, y) != 0;
31  
  }
32  
  
33  
  bool clearPixel(int x, int y) {
34  
    if (!region.contains(x, y)) false;
35  
    pixels[idx(x, y)] = 0;
36  
    true;
37  
  }
38  
  
39  
  void init {
40  
    if (bounds != null) ret;
41  
    bounds = originalRegion.bounds();
42  
    pixels = new byte[area(bounds)];
43  
    for (Pt p : originalRegion.pixelIterator())
44  
      pixels[idx(p.x, p.y)] = 1;
45  
      
46  
    region = new ThinnedRegion;
47  
  }
48  
  
49  
  class ThinnedRegion is IImageRegion<Img> {
50  
    public Img image() { ret originalRegion.image(); }
51  
    public Rect bounds() { ret bounds; }
52  
  
53  
    public bool contains(int x, int y) {
54  
      ret containsPt(bounds, x, y) && pixels[idx(x, y)] > 0;
55  
    }
56  
    
57  
    public ItIt<Pt> pixelIterator() {
58  
      ret iff_null(new IF0<Pt> {
59  
        int idx = 0;
60  
        
61  
        public Pt get() {
62  
          for (; idx < pixels.length; idx++)
63  
            if (pixels[idx] > 0)
64  
              ret idxToPt(idx++);
65  
          null;
66  
        }
67  
      });
68  
    }
69  
  }
70  
  
71  
  public bool step() {
72  
    init();
73  
    
74  
    if (phase1done)
75  
      ret finalStep();
76  
    
77  
    L<PtBuffer> traces = g22_allBorderTraces_withDiagonals(region);
78  
    for (points : traces)
79  
      for (p : points)
80  
        pixels[idx(p)] = 2;
81  
        
82  
    new PtBuffer toDelete;
83  
84  
    for (points : traces) {
85  
      int nPoints = l(points);
86  
      BitSet deletable = emptyBitSet(nPoints);
87  
      for i to nPoints: {
88  
        ping();
89  
        if (deletableBorderPoint(points, i))
90  
          deletable.set(i);
91  
      }
92  
93  
      // handle special cases      
94  
      for (int i = 1; i < nPoints-1; i++)
95  
        if (deletable.get(i-1)
96  
          && !deletable.get(i)
97  
          && deletable.get(i+1)) {
98  
          Pt p = points.get(i);
99  
          Pt prev = ptMinus(points.get(i-1), p);
100  
          Pt next = ptMinus(points.get(i+1), p);
101  
          int dir1 = onePathLookupDirection(prev);
102  
          int dir2 = onePathLookupDirection(next);
103  
          int diff = mod(dir2-dir1, 8);
104  
          printVars ifdef G22RegionThinner_debug(+p, +prev, +next, +dir1, +dir2, +diff);
105  
          if (diff == 1 || diff == 7)
106  
            deletable.set(i);
107  
        }
108  
109  
      for i to nPoints:
110  
        if (deletable.get(i))
111  
          toDelete.add(points.get(i));
112  
    }
113  
114  
    for (p : toDelete)
115  
      pixels[idx(p)] = 0;
116  
117  
    if (empty(toDelete))
118  
      set phase1done;
119  
    true;
120  
  }
121  
  
122  
  bool deletableBorderPoint(PtBuffer points, int i) {
123  
    L<Pt> range = cyclicSubList_incl(points, i-3, i+3);
124  
    Pt p = points.get(i);
125  
    
126  
    // special case
127  
    if (eq(range.get(1), p) || eq(range.get(5), p)) false;
128  
    
129  
    int surroundingBorderPixels = 0, surroundingInnerPixels = 0;
130  
    for (int dir = 1; dir <= 8; dir++) {
131  
      Pt p2 = ptPlus(p, onePathDirection(dir));
132  
      byte value = getPixel(p2);
133  
      if (value == 2 && !range.contains(p2))
134  
        surroundingBorderPixels++;
135  
      else if (value == 1)
136  
        surroundingInnerPixels++;
137  
    }
138  
    
139  
    bool deletable = surroundingInnerPixels > 0 && surroundingBorderPixels == 0;
140  
      
141  
    printVars ifdef G22RegionThinner_debug(+p, +surroundingInnerPixels, +surroundingBorderPixels, +deletable, +range);
142  
    ret deletable;
143  
  }
144  
  
145  
  IImageRegion region aka get() { ret or(region, originalRegion); }
146  
  
147  
  // go from 2 pixels wide to 1 pixel wide (TODO)
148  
  bool finalStep() {
149  
    false;
150  
  }
151  
}

Author comment

Began life as a copy of #1034983

download  show line numbers  debug dex  old transpilations   

Travelled to 3 computer(s): bhatertpkbcr, mowyntqkapby, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1035003
Snippet name: G22RegionThinner_v2 - thin a region to 2 pixel wide [OK backup without final thinning]
Eternal ID of this version: #1035003/1
Text MD5: 20538f6b51376f6e420242aa39130a5c
Transpilation MD5: 77cf4d8750bb0e2968fac7c8940b3160
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-03-22 18:34:55
Source code size: 4099 bytes / 151 lines
Pitched / IR pitched: No / No
Views / Downloads: 63 / 92
Referenced in: [show references]