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

209
LINES

< > BotCompany Repo | #1032205 // Minimal Recognizer [backup 2]

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

Uses 108K of libraries. Click here for Pure Java version (14093L/86K).

1  
do not include class IntegralImage.
2  
do not include class IIntegralImage.
3  
4  
srecord noeq MinimalRecognizer(BufferedImage inputImage) {
5  
  replace Channel with int.
6  
7  
  IIntegralImage mainImage;
8  
  
9  
  static final int grayscale = 3; // channel number for grayscale
10  
  
11  
  abstract class IIntegralImage {
12  
    // width and height of image
13  
    int w, h;
14  
    
15  
    abstract double integralValue(int x, int y, Channel channel);
16  
    
17  
    BufferedImage render() {
18  
      ret imageFromFunction(w, h, (x, y) -> rgbPixel(x, y, x+1, y+1) | fullAlphaMask());
19  
    }
20  
21  
    double getPixel(Rect r, int channel) {
22  
      ret getPixel(r.x, r.y, r.x2(), r.y2(), channel);
23  
    }
24  
25  
    double getPixel(int channel) { ret getPixel(0, 0, w, h, channel); }
26  
    
27  
    // return value ranges from 0 to 1 (usually)
28  
    double getPixel(int x1, int y1, int x2, int y2, int channel) {
29  
      ret doubleRatio(rectSum(x1, y1, x2, y2, channel), (x2-x1)*(y2-y1)*255.0);
30  
    }
31  
    
32  
    double rectSum(Rect r, int channel) {
33  
      ret rectSum(r.x, r.y, r.x2(), r.y2(), channel);
34  
    }
35  
    
36  
    double rectSum(int x1, int y1, int x2, int y2, int channel) {
37  
      double bottomLeft  = integralValue(x1-1, y2-1, channel);
38  
      double bottomRight = integralValue(x2-1, y2-1, channel);
39  
      double topLeft     = integralValue(x1-1, y1-1, channel);
40  
      double topRight    = integralValue(x2-1, y1-1, channel);
41  
      ret bottomRight-topRight-bottomLeft+topLeft;
42  
    }
43  
44  
    int rgbPixel(int x1, int y1, int x2, int y2) {
45  
      int r = iround(clampZeroToOne(getPixel(x1, y1, x2, y2, 0))*255);
46  
      int g = iround(clampZeroToOne(getPixel(x1, y1, x2, y2, 1))*255);
47  
      int b = iround(clampZeroToOne(getPixel(x1, y1, x2, y2, 2))*255);
48  
      ret rgbInt(r, g, b);
49  
    }
50  
    
51  
    double liveliness(int channel) {
52  
      // optimization (but no change in semantics):
53  
      // if (w <= 1 && h <= 1) ret 0; // liveliness of single pixel is 0
54  
      ret standardDeviation(map(q -> q.getPixel(channel), quadrants()));
55  
    }
56  
57  
    L<IIntegralImage> descentShapes() {
58  
      ret centerPlusQuadrants();
59  
    }
60  
    
61  
    L<IIntegralImage> centerPlusQuadrants() {
62  
      int midX = w/2, midY = h/2;
63  
      Rect r = rectAround(midX, midY, max(midX/2, 1), max(midY/2, 1));
64  
      ret itemPlusList(clip(r), quadrants());
65  
    }
66  
    
67  
    L<IIntegralImage> quadrants() {
68  
      if (w <= 1 && h <= 1) null; // let's really not have quadrants of a single pixel
69  
      int midX = w/2, midY = h/2;
70  
      ret mapLL clip(
71  
        rect(0, 0, max(midX, 1), max(midY, 1)),
72  
        rect(midX, 0, w-midX, max(midY, 1)),
73  
        rect(0, midY, max(midX, 1), h-midY),
74  
        rect(midX, midY, w-midX, h-midY)
75  
      );
76  
    }
77  
78  
    IIntegralImage liveliestSubshape(int channel) {
79  
      ret highestBy(q -> q.liveliness(channel), quadrants());
80  
    }
81  
    
82  
    ProbabilisticList<IIntegralImage> liveliestSubshape_probabilistic(int channel) {
83  
      ret new ProbabilisticList<IIntegralImage>(map(descentShapes(), shape ->
84  
        withProbability(shape.liveliness(channel), shape)));
85  
    }
86  
87  
    Clip clip(Rect r) { ret new Clip(this, r); }
88  
    Clip clip(int x1, int y1, int w, int h) { ret clip(rect(x1, y1, w, h)); }
89  
    
90  
    Rect positionInImage(IIntegralImage mainImage) {
91  
      if (this == mainImage) ret rect(0, 0, w, h);
92  
      null;
93  
    }
94  
  }
95  
96  
  // virtual clip of an integral image
97  
  class Clip extends IIntegralImage {
98  
    IIntegralImage fullImage;
99  
    int x1, y1;
100  
101  
    *(IIntegralImage *fullImage, Rect r) {
102  
      x1 = r.x; y1 = r.y; w = r.w; h = r.h;
103  
    }
104  
     
105  
    *(IIntegralImage *fullImage, int *x1, int *y1, int *w, int *h) {}
106  
    
107  
    public double integralValue(int x, int y, int channel) {
108  
      ret fullImage.integralValue(x+x1, y+y1, channel);
109  
    }
110  
111  
    // don't clip a clip - be smarter than that!
112  
    Clip clip(Rect r) {
113  
      ret new Clip(fullImage, translateRect(r, x1, y1));
114  
    }
115  
116  
    Rect rectInImage() {
117  
      ret rect(x1, y1, w, h);
118  
    }
119  
120  
    Rect positionInImage(IIntegralImage mainImage) {
121  
      try object Rect r = super.positionInImage(mainImage);
122  
      if (fullImage == mainImage) ret rect(x1, y1, w, h);
123  
      null;
124  
    }
125  
126  
    toString { ret rectInImage() + " in " + fullImage; }
127  
  }
128  
129  
  class IntegralImage extends IIntegralImage {
130  
    int[] data;
131  
     
132  
    *(BufferedImage img) {
133  
      w = img.getWidth(); h = img.getHeight();
134  
      if (longMul(w, h) > 8000000) fail("Image too big: " + w + "*" + h);
135  
      int[] pixels = pixelsOfBufferedImage(img);
136  
      data = new int[w*h*3];
137  
      int i = 0, j = 0;
138  
      int[] sum = new[3];
139  
      for y to h: {
140  
        for c to 3: sum[c] = 0;
141  
        for x to w: {
142  
          int rgb = pixels[j++] & 0xFFFFFF;
143  
          for c to 3: {
144  
            data[i] = (sum[c] += rgb >> 16);
145  
            if (y > 0)
146  
              data[i] += data[i-w*3];
147  
            i++;
148  
            rgb = (rgb << 8) & 0xFFFFFF;
149  
          }
150  
        }
151  
      }
152  
    }
153  
    
154  
    public double integralValue(int x, int y, Channel channel) {
155  
      if (channel == grayscale)
156  
        ret doubleAvg(countIterator(3, c -> integralValue(x, y, c)));
157  
        
158  
      ret x < 0 || y < 0 ? 0
159  
        : data[(min(y, h-1)*w+min(x, w-1))*3+channel];
160  
    }
161  
  }
162  
163  
  IIntegralImage liveliestPointIn(IIntegralImage image) {
164  
    ret applyUntilEqual_goOneBackOnNull(c -> c.liveliestSubshape(grayscale), image);
165  
  }
166  
167  
  int highLevel = 3; // determines how many points you get
168  
  int maxPoints = 1000;
169  
  
170  
  run {
171  
    mainImage = new IntegralImage(inputImage);
172  
    inputImage = null; // save space
173  
    
174  
    //print(liveliness := mainImage.liveliness(grayscale));
175  
    new L<ProbabilisticList<IIntegralImage>> schedulers;
176  
    new BetterLinkedHashSet<IIntegralImage> liveliestPoints;
177  
    schedulers.add(mainImage.liveliestSubshape_probabilistic(grayscale));
178  
179  
    while ping (nempty(schedulers)) {
180  
      // go to high level
181  
      truncateList(schedulers, highLevel);
182  
183  
      // clean up used schedulers
184  
      while (nempty(schedulers) && empty(last(schedulers)))
185  
        removeLast(schedulers);
186  
187  
      if (empty(schedulers)) break;
188  
189  
      // quick descend
190  
      while (l(schedulers) < 20) {
191  
        var nextSeed = popFirst(last(schedulers))!;
192  
        var newOptions = nextSeed.liveliestSubshape_probabilistic(grayscale);
193  
        print(+nextSeed);
194  
        pnl(newOptions);
195  
        if (empty(newOptions)) break;
196  
        schedulers.add(newOptions);
197  
      }
198  
199  
      if (empty(schedulers)) break;
200  
201  
      // return a result
202  
      liveliestPoints.add(popFirst(last(schedulers))!);
203  
      if (l(liveliestPoints) >= maxPoints) break;
204  
    }
205  
    showImageWithSelections(mainImage.render(),
206  
      map(liveliestPoints, p -> growRect(1.5, p.positionInImage(mainImage))));
207  
    //pnl(subshapes);
208  
  }
209  
}

Author comment

Began life as a copy of #1032199

download  show line numbers  debug dex  old transpilations   

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

No comments. add comment

Snippet ID: #1032205
Snippet name: Minimal Recognizer [backup 2]
Eternal ID of this version: #1032205/1
Text MD5: 9c8ef4b75efd3365aeadec6d541ee82c
Transpilation MD5: 8f03e2bbfcfd8888b7ac493fac69f9d2
Author: stefan
Category:
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-08-20 06:15:50
Source code size: 6791 bytes / 209 lines
Pitched / IR pitched: No / No
Views / Downloads: 155 / 212
Referenced in: [show references]