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

249
LINES

< > BotCompany Repo | #1035111 // G22RegionThinner_v2 - thin a region to 1 pixel wide [backup]

JavaX fragment (include)

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  
  settable bool debug;
7  
  settable bool doFinalStep = true;
8  
  settable int lastPhaseThreshold1 = 2;
9  
  settable int lastPhaseThreshold = 5;
10  
  
11  
  settable byte[] lookupTable;
12  
  
13  
  // 0 = outside of region
14  
  // 1 = inner pixel
15  
  // 2 = border pixel
16  
  // index is in bounds coordinates
17  
  byte[] pixels;
18  
  
19  
  int idx(int x, int y) {
20  
    ret (y-bounds.y)*bounds.w+x-bounds.x;
21  
  }
22  
  int idx(Pt p) { ret idx(p.x, p.y); }
23  
  
24  
  Pt idxToPt(int idx) {
25  
    ret pt(bounds.x+(idx % bounds.w), bounds.y+idx/bounds.w);
26  
  }
27  
  
28  
  byte getPixel(long p) {
29  
    ret getPixel(firstIntFromLong(p), secondIntFromLong(p));
30  
  }
31  
  
32  
  byte getPixel(Pt p) {
33  
    ret !containsPt(bounds, p) ? 0 : pixels[idx(p)];
34  
  }
35  
  
36  
  byte getPixel(int x, int y) {
37  
    ret !containsPt(bounds, x, y) ? 0 : pixels[idx(x, y)];
38  
  }
39  
  
40  
  bool contains(int x, int y) {
41  
    ret getPixel(x, y) != 0;
42  
  }
43  
  
44  
  bool clearPixel(int x, int y) {
45  
    if (!region.contains(x, y)) false;
46  
    pixels[idx(x, y)] = 0;
47  
    true;
48  
  }
49  
  
50  
  void init {
51  
    if (bounds != null) ret;
52  
    bounds = originalRegion.bounds();
53  
    pixels = new byte[area(bounds)];
54  
    for (Pt p : originalRegion.pixelIterator())
55  
      pixels[idx(p.x, p.y)] = 1;
56  
      
57  
    region = new ThinnedRegion;
58  
  }
59  
  
60  
  class ThinnedRegion is IImageRegion<Img> {
61  
    public Img image() { ret originalRegion.image(); }
62  
    public Rect bounds() { ret bounds; }
63  
  
64  
    public bool contains(int x, int y) {
65  
      ret containsPt(bounds, x, y) && pixels[idx(x, y)] > 0;
66  
    }
67  
    
68  
    public ItIt<Pt> pixelIterator() {
69  
      ret iff_null(new IF0<Pt> {
70  
        int idx = 0;
71  
        
72  
        public Pt get() {
73  
          for (; idx < pixels.length; idx++)
74  
            if (pixels[idx] > 0)
75  
              ret idxToPt(idx++);
76  
          null;
77  
        }
78  
      });
79  
    }
80  
  }
81  
  
82  
  public bool step() {
83  
    init();
84  
    
85  
    if (phase1done)
86  
      ret finalStep();
87  
    
88  
    L<PtBuffer> traces = g22_allBorderTraces_withDiagonals(region);
89  
    for (points : traces)
90  
      for (p : points)
91  
        pixels[idx(p)] = 2;
92  
        
93  
    new PtBuffer toDelete;
94  
95  
    for (points : traces) {
96  
      int nPoints = l(points);
97  
      BitSet deletable = emptyBitSet(nPoints);
98  
      for i to nPoints: {
99  
        bool del = deletableBorderPoint(points, i);
100  
        /*bool del2 = deletableBorderPoint_old(points, i);
101  
        if (del != del2)
102  
          failWithVars("deletableBorderPoint", +i, +nPoints, +del);*/
103  
        if (del)
104  
          deletable.set(i);
105  
      }
106  
107  
      // handle special cases      
108  
      for i to nPoints:
109  
        if (cyclicGet(deletable, nPoints, i-1)
110  
          && !deletable.get(i)
111  
          && cyclicGet(deletable, nPoints, i+1)) {
112  
          Pt p = points.get(i);
113  
          Pt prev = ptMinus(cyclicGet(points, i-1), p);
114  
          Pt next = ptMinus(cyclicGet(points, i+1), p);
115  
          int dir1 = onePathLookupDirection(prev);
116  
          int dir2 = onePathLookupDirection(next);
117  
          int diff = mod(dir2-dir1, 8);
118  
          if (debug) printVars("special case", +p, +prev, +next, +dir1, +dir2, +diff);
119  
          if (diff == 1 || diff == 7)
120  
            deletable.set(i);
121  
        }
122  
123  
      for i to nPoints:
124  
        if (deletable.get(i))
125  
          toDelete.add(points.get(i));
126  
    }
127  
128  
    for (p : toDelete)
129  
      pixels[idx(p)] = 0;
130  
131  
    if (empty(toDelete))
132  
      set phase1done;
133  
    true;
134  
  }
135  
  
136  
  bool deletableBorderPoint(PtBuffer points, int i) {
137  
    //L<Pt> range = cyclicSubList_incl(points, i-3, i+3);
138  
    LongBuffer pointsBuf = points.buf;
139  
    long p_long = pointsBuf.get(i);
140  
    
141  
    // special case
142  
    
143  
    if (p_long == cyclicGet(pointsBuf, i-2)
144  
      || p_long == cyclicGet(pointsBuf, i+2)) {
145  
      printVars ifdef G22RegionThinner_debug("special case", p := ptFromLong(p_long));
146  
      false;
147  
    }
148  
    
149  
    int surroundingBorderPixels = 0, surroundingInnerPixels = 0;
150  
    for (int dir = 1; dir <= 8; dir++) {
151  
      long p2_long = onePathDirection_long(p_long, dir);
152  
      byte value = getPixel(p2_long);
153  
      if (value == 2 && !rangeContains(pointsBuf, i, p2_long)) {
154  
        printVars ifdef G22RegionThinner_debug("surroundingBorderPixel", p2 := ptFromLong(p2_long));
155  
        //surroundingBorderPixels++;
156  
        false;
157  
      } else if (value == 1) {
158  
        printVars ifdef G22RegionThinner_debug("surroundingInnerPixel", p2 := ptFromLong(p2_long));
159  
        surroundingInnerPixels++;
160  
      }
161  
    }
162  
    
163  
    ret surroundingInnerPixels > 0;
164  
    
165  
    //bool deletable = surroundingInnerPixels > 0 && surroundingBorderPixels == 0;
166  
    //printVars ifdef G22RegionThinner_debug(+p, +surroundingInnerPixels, +surroundingBorderPixels, +deletable, +range);
167  
    //ret deletable;
168  
  }
169  
  
170  
  bool rangeContains(LongBuffer pointsBuf, int i, long p2_long) {
171  
    for (int j = i-3; j <= i+3; j++)
172  
      if (cyclicGet(pointsBuf, j) == p2_long)
173  
        true;
174  
    false;
175  
  }
176  
  
177  
  bool deletableBorderPoint_old(PtBuffer points, int i) {
178  
    L<Pt> range = cyclicSubList_incl(points, i-3, i+3);
179  
    Pt p = points.get(i);
180  
    
181  
    // special case
182  
    if (eq(range.get(1), p) || eq(range.get(5), p)) false;
183  
    
184  
    int surroundingBorderPixels = 0, surroundingInnerPixels = 0;
185  
    for (int dir = 1; dir <= 8; dir++) {
186  
      Pt p2 = ptPlus(p, onePathDirection(dir));
187  
      byte value = getPixel(p2);
188  
      if (value == 2 && !range.contains(p2))
189  
        surroundingBorderPixels++;
190  
      else if (value == 1)
191  
        surroundingInnerPixels++;
192  
    }
193  
    
194  
    bool deletable = surroundingInnerPixels > 0 && surroundingBorderPixels == 0;
195  
      
196  
    printVars ifdef G22RegionThinner_debug(+p, +surroundingInnerPixels, +surroundingBorderPixels, +deletable, +range);
197  
    ret deletable;
198  
  }
199  
  
200  
  IImageRegion region aka get() { ret or(region, originalRegion); }
201  
  
202  
  // go from 2 pixels wide to 1 pixel wide (TODO)
203  
  bool finalStep() {
204  
    if (!doFinalStep) false;
205  
    
206  
    if (lookupTable == null)
207  
      lookupTable = new G22RegionThinner_LookupTable()
208  
        .lastPhaseThreshold(lastPhaseThreshold)
209  
        .lastPhaseThreshold1(lastPhaseThreshold1)!;
210  
    
211  
    bool change;
212  
    int x1 = bounds.x, x2 = bounds.x2();
213  
    int y1 = bounds.y, y2 = bounds.y2();
214  
    printVars ifdef G22RegionThinner_lastPhase_debug("finalStep", +x1, +y1, +x2, +y2);
215  
    
216  
    var pingSource = pingSource();
217  
    
218  
    for (int y = y1; y < y2; y++) {
219  
      ping(pingSource);
220  
      for (int x = x1; x < x2; x++) {
221  
        // need a set pixel
222  
        if (!contains(x, y)) continue;
223  
224  
        // check if this pixel is essential to hold the structure
225  
        // together by doing a floodfill in the 3x3 neighborhood
226  
        // (simulating the pixel being cleared already)
227  
        
228  
        var imgPattern = ubyteFromBits(
229  
          contains(x-1, y-1),
230  
          contains(x,   y-1),
231  
          contains(x+1, y-1),
232  
          contains(x-1, y),
233  
          contains(x+1, y),
234  
          contains(x-1, y+1),
235  
          contains(x,   y+1),
236  
          contains(x+1, y+1));
237  
        
238  
        bool delete = getBit(lookupTable, imgPattern);
239  
        
240  
        printVars ifdef G22RegionThinner_lastPhase_debug(
241  
          +x, +y, +imgPattern, +pixels, +delete);
242  
        
243  
        if (delete)
244  
          change |= clearPixel(x, y);
245  
      }
246  
    }
247  
    ret change;
248  
  }
249  
}

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: #1035111
Snippet name: G22RegionThinner_v2 - thin a region to 1 pixel wide [backup]
Eternal ID of this version: #1035111/1
Text MD5: 2d6300eef7c1e021c9e342ae1bd61b11
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-03-30 03:47:39
Source code size: 7495 bytes / 249 lines
Pitched / IR pitched: No / No
Views / Downloads: 53 / 64
Referenced in: [show references]