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

284
LINES

< > BotCompany Repo | #1034521 // FastRegions_BWImage (backup)

JavaX fragment (include)

1  
srecord noeq FastRegions_BWImage(BWImage image) is Runnable, IImageRegions<BWImage> {
2  
  int w, h, runner;
3  
  gettable int size;
4  
  
5  
  new IntBuffer stack; // locations as y*w+x
6  
  int[] regionMatrix; // for each pixel: region index (starting at 1)
7  
  new IntBuffer regionPixels; // collect all pixels for regions
8  
  
9  
  // initialize these to use them
10  
  
11  
  new IntBuffer regionFirstPixel; // for each region: index of first pixel found in regionPixels
12  
  new IntBuffer regionSize; // for each region: number of pixels
13  
  new IntBuffer regionBounds; // for each region: bounds (x1, y1, x2, y2)
14  
  
15  
  // index = dual log of region size, value = region index
16  
  new L<IntBuffer> regionsBySize;
17  
  
18  
  int regionCounter;
19  
  bool verbose;
20  
  
21  
  double regionStep = .1; // for rendering in regionsImage
22  
  
23  
  int x(int pos) { ret pos % w; }
24  
  int y(int pos) { ret pos / w; }
25  
  int pos(int x, int y) { ret y*w+x; }
26  
  Pt pt(int pos) { ret Pt(x(pos), y(pos)); }
27  
  bool validPos(int x, int y) { ret x >= 0 && y >= 0 && x < w && y < h; }
28  
  
29  
  int getColor(int pos) { ret image.getInt(x(pos), y(pos)); }
30  
  
31  
  *(BufferedImage img) { this(toBWImage(img)); }
32  
33  
  run {
34  
    w = image.getWidth(); h = image.getHeight();
35  
    size = w*h;
36  
    regionMatrix = new int[size];
37  
    
38  
    // 0 entries are unused
39  
    regionFirstPixel?.add(0); 
40  
    regionSize?.add(0);
41  
    
42  
    regionPixels?.setSize(size);
43  
    
44  
    while (runner < size) {
45  
      if (regionMatrix[runner] == 0) {
46  
        // make a new region, get color
47  
        int region = ++regionCounter;
48  
        regionFirstPixel?.add(regionPixels != null ? l(regionPixels) : runner);
49  
        stack.add(runner);
50  
        int color = getColor(runner);
51  
        int rsize = 0, x1 = w, y1 = h, x2 = 0, y2 = 0;
52  
        ifdef FastRegions_debug
53  
          printVars FastRegions(+region, +runner);
54  
        endifdef
55  
56  
        // flood-fill region
57  
        while (nempty(stack)) {
58  
          int pos = stack.popLast();
59  
          if (regionMatrix[pos] != 0) continue; // touching myself (or someone else)
60  
          if (getColor(pos) != color) continue; // wrong color
61  
        
62  
          // new pixel found, mark as ours
63  
          regionMatrix[pos] = region;
64  
          ++rsize;
65  
          regionPixels?.add(pos);
66  
          int x = x(pos), y = y(pos);
67  
          
68  
          ifdef FastRegions_debug
69  
            printVars FastRegions(+x, +y);
70  
          endifdef
71  
          
72  
          if (x < x1) x1 = x;
73  
          if (x > x2) x2 = x;
74  
          if (y < y1) y1 = y;
75  
          if (y > y2) y2 = y;
76  
77  
          // explore neighborhood
78  
          if (x > 0)   stack.add(pos-1);
79  
          if (x < w-1) stack.add(pos+1);
80  
          if (y > 0)   stack.add(pos-w);
81  
          if (y < h-1) stack.add(pos+w);
82  
        }
83  
        
84  
        regionSize?.add(rsize);
85  
        regionBounds?.addAll(x1, y1, x2+1, y2+1);
86  
        if (regionsBySize != null) {
87  
          int iBucket = dualLog(rsize);
88  
          var buffer = listGetOrCreate(regionsBySize, iBucket, -> new IntBuffer);
89  
          buffer.add(region);
90  
        }
91  
      }
92  
      
93  
      ++runner;
94  
    }
95  
  }
96  
  
97  
  IBWImage regionsImage() {
98  
    ret iBWImageFromFunction((x, y) -> {
99  
      var region = regionMatrix[pos(x, y)];
100  
      ret ((region-1)*regionStep) % (1.0+regionStep-0.0001);
101  
    }, w, h);
102  
  }
103  
  
104  
  int regionCount aka nRegions() { ret regionCounter; }
105  
  
106  
  abstract class RegionIterator {
107  
    int pos;
108  
    
109  
    abstract bool next();
110  
    
111  
    int pos() { ret pos; }
112  
    int x() { ret BWImage_FastRegions.this.x(pos); }
113  
    int y() { ret BWImage_FastRegions.this.y(pos); }
114  
  }
115  
  
116  
  // returns points in no particular order
117  
  class FloodRegionIterator > RegionIterator {
118  
    int region;
119  
    new IntBuffer stack; // locations as y*w+x
120  
    BitSet seen = new(size);
121  
    
122  
    *(int *region) {
123  
      int pos = regionFirstPixel.get(region);
124  
      printVars(+region, +pos);
125  
      seen.set(pos);
126  
      stack.add(pos);
127  
    }
128  
    
129  
    // flood-fill region
130  
    bool next() {
131  
      if (empty(stack)) false;
132  
      
133  
      pos = stack.popLast();
134  
135  
      // explore neighborhood
136  
      int x = x(), y = y();
137  
      if (x > 0)   tryPosition(pos-1);
138  
      if (x < w-1) tryPosition(pos+1);
139  
      if (y > 0)   tryPosition(pos-w);
140  
      if (y < h-1) tryPosition(pos+w);
141  
142  
      true;
143  
    }
144  
    
145  
    private void tryPosition(int p) {
146  
      if (!seen.get(p) && regionMatrix[p] == region) {
147  
        seen.set(p);
148  
        stack.add(p);
149  
      }
150  
    }
151  
  }
152  
  
153  
  class CachedRegionIterator > RegionIterator {
154  
    int i, to;
155  
156  
    *(int region) {
157  
      i = regionFirstPixel.get(region);
158  
      to = region+1 < l(regionFirstPixel) ? regionFirstPixel.get(region+1) : l(regionPixels);
159  
      
160  
      ifdef FastRegions_debug
161  
        printVars CachedRegionIterator(+region, +i, +to);
162  
      endifdef
163  
    }
164  
    
165  
    bool next() {
166  
      if (i >= to) false;
167  
      pos = regionPixels.get(i++);
168  
      true;
169  
    }
170  
  }
171  
  
172  
  int regionSize(int iRegion) { ret regionSize.get(iRegion); }
173  
  
174  
  Pt samplePixel aka firstPixel(int iRegion) {
175  
    ret pt(firstPixelPos(iRegion));
176  
  }
177  
  
178  
  int firstPixelPos(int iRegion) {
179  
    int i = regionFirstPixel.get(iRegion);
180  
    ret regionPixels != null ? regionPixels.get(i) : i;
181  
  }
182  
  
183  
  bool inRegion(int iRegion, int x, int y) {
184  
    ret validPos(x, y) && regionMatrix[pos(x, y)] == iRegion;
185  
  }
186  
  Rect regionBounds(int iRegion) { ret rectFromPoints(
187  
    regionBounds.get((iRegion-1)*4),
188  
    regionBounds.get((iRegion-1)*4+1),
189  
    regionBounds.get((iRegion-1)*4+2),
190  
    regionBounds.get((iRegion-1)*4+3),
191  
  ); }
192  
  
193  
  int regionAt(Pt p) { ret regionAt(p.x, p.y); }
194  
  
195  
  int regionAt(int x, int y) {
196  
    ret !validPos(x, y) ? 0 : regionMatrix[pos(x, y)];
197  
  }
198  
  
199  
  int regionAt(int pos) {
200  
    ret regionMatrix[pos];
201  
  }
202  
  
203  
  RegionIterator regionIterator(int iRegion) {
204  
    ret regionPixels != null
205  
      ? new CachedRegionIterator(iRegion)
206  
      : new FloodRegionIterator(iRegion);
207  
  }
208  
  
209  
  L<Pt> regionPixels(int iRegion) {
210  
    var it = regionIterator(iRegion);
211  
    new L<Pt> l;
212  
    while (it.next())
213  
      l.add(Pt(it.x(), it.y()));
214  
    ret l;
215  
  }
216  
  
217  
  // select extra features before regions are made
218  
  // (not necessary anymore)
219  
  
220  
  void collectFirstPixels { /*regionFirstPixel = new IntBuffer;*/ }
221  
  void collectBounds { /*regionBounds = new IntBuffer;*/ }
222  
  
223  
  BitMatrix regionBitMatrix(int iRegion) {
224  
    ret new AbstractBitMatrix(w, h) {
225  
      public Bool get(int x, int y) {
226  
        ret inRegion(iRegion, x, y);
227  
      }
228  
    };
229  
  }
230  
  
231  
  void markRegionInPixelArray(int[] pixels, int iRegion, int rgba) {
232  
    if (iRegion <= 0) ret;
233  
    for i over pixels:
234  
      if (regionAt(i) == iRegion)
235  
        pixels[i] = rgba;
236  
  }
237  
  
238  
  L<Int> regionIndices() { ret virtualCountList(1, nRegions()+1); }
239  
  
240  
  ItIt<Int> regionsRoughlyByDecreasingSize() {
241  
    ret nestedIterator(countIterator_inclusive_backwards(regionsBySize.size()-1, 0),
242  
      iBucket -> iterator(regionsBySize.get(iBucket)));
243  
  }
244  
  
245  
  IImageRegion<BWImage> getRegion aka get(int iRegion) {
246  
    ret new ImageRegion(iRegion);
247  
  }
248  
  
249  
  public L<IImageRegion<BWImage>> regions() {
250  
    ret listFromFunction(i -> getRegion(i+1), nRegions());
251  
  }
252  
  
253  
  record ImageRegion(int iRegion) is IImageRegion<BWImage> {
254  
    public BWImage image() { ret image; }
255  
    public O creator() { ret FastRegions_BWImage.this; }
256  
    public int indexInCreator() { ret iRegion; }
257  
  
258  
    public Rect bounds() { ret regionBounds(iRegion); }
259  
    
260  
    public int numberOfPixels() { ret regionSize(iRegion); }
261  
    
262  
    public Pt firstPixel() { ret pt(firstPixelPos()); }
263  
    public int firstPixelPos() { ret FastRegions_BWImage.this.firstPixelPos(iRegion); }
264  
    
265  
    public Iterator<Pt> pixelIterator() {
266  
      var it = regionIterator(iRegion);
267  
      ret iteratorFromFunction(-> it.next() ? pt(it.pos()) : null);
268  
    }
269  
    
270  
    public bool contains(int x, int y) { ret inRegion(iRegion, x, y); }
271  
    
272  
    public RGB color() {
273  
      ret rgbFromGrayscale(brightness());
274  
    }
275  
    
276  
    public int brightness() {
277  
      ret getColor(firstPixelPos());
278  
    }
279  
    
280  
    toString {
281  
      ret renderRecordVars("Region", +brightness(), +color(), pixels := numberOfPixels(), +bounds());
282  
    }
283  
  }
284  
}

Author comment

Began life as a copy of #1033761

download  show line numbers  debug dex  old transpilations   

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

No comments. add comment

Snippet ID: #1034521
Snippet name: FastRegions_BWImage (backup)
Eternal ID of this version: #1034521/1
Text MD5: 484e489088fcb98df200f266817573c1
Author: stefan
Category: javax / imaging
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-02-10 07:39:37
Source code size: 8297 bytes / 284 lines
Pitched / IR pitched: No / No
Views / Downloads: 126 / 140
Referenced in: [show references]