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

2028
LINES

< > BotCompany Repo | #1019064 // Test HaarCascade_FaceDetector (copied in, dev.)

JavaX source code (Dynamic Module) [tags: use-pretranspiled] - run with: Stefan's OS

Uses 12233K of libraries. Compilation Failed (18724L/112K).

1  
!7
2  
3  
!include once #1010056 // OpenIMAJ
4  
5  
import org.openimaj.image.Image;
6  
import org.openimaj.image.processor.*;
7  
import static org.openimaj.image.processor.SinglebandImageProcessor.Processable;
8  
9  
replace Rectangle with RectangleO.
10  
11  
abstract sclass SingleBandImage<Q extends Comparable<Q>, I extends SingleBandImage<Q, I>> extends Image<Q, I> implements Processable<Q, I, I>, org.openimaj.image.processor.SinglebandKernelProcessor.Processable<Q, I, I> {
12  
    private static final long serialVersionUID = 1L;
13  
    public int height;
14  
    public int width;
15  
16  
    public SingleBandImage() {
17  
    }
18  
19  
    public int getHeight() {
20  
        return this.height;
21  
    }
22  
23  
    public int getWidth() {
24  
        return this.width;
25  
    }
26  
27  
    public I process(KernelProcessor<Q, I> p) {
28  
        return this.process(p, false);
29  
    }
30  
31  
    public I process(KernelProcessor<Q, I> p, boolean pad) {
32  
        I newImage = (I) this.newInstance(this.width, this.height);
33  
        I tmp = (I) this.newInstance(p.getKernelWidth(), p.getKernelHeight());
34  
        int hh = p.getKernelHeight() / 2;
35  
        int hw = p.getKernelWidth() / 2;
36  
        int y;
37  
        int x;
38  
        if (!pad) {
39  
            for(y = hh; y < this.getHeight() - (p.getKernelHeight() - hh); ++y) {
40  
                for(x = hw; x < this.getWidth() - (p.getKernelWidth() - hw); ++x) {
41  
                    newImage.setPixel(x, y, p.processKernel(this.extractROI(x, y, tmp)));
42  
                }
43  
            }
44  
        } else {
45  
            for(y = 0; y < this.getHeight(); ++y) {
46  
                for(x = 0; x < this.getWidth(); ++x) {
47  
                    newImage.setPixel(x, y, p.processKernel(this.extractROI(x, y, tmp)));
48  
                }
49  
            }
50  
        }
51  
52  
        return newImage;
53  
    }
54  
55  
    public I process(SinglebandKernelProcessor<Q, I> p) {
56  
        return this.process(p, false);
57  
    }
58  
59  
    public I process(SinglebandKernelProcessor<Q, I> p, boolean pad) {
60  
        I newImage = (SingleBandImage)this.newInstance(this.width, this.height);
61  
        I tmp = (SingleBandImage)this.newInstance(p.getKernelWidth(), p.getKernelHeight());
62  
        int hh = p.getKernelHeight() / 2;
63  
        int hw = p.getKernelWidth() / 2;
64  
        int y;
65  
        int x;
66  
        if (!pad) {
67  
            for(y = hh; y < this.getHeight() - (p.getKernelHeight() - hh); ++y) {
68  
                for(x = hw; x < this.getWidth() - (p.getKernelWidth() - hw); ++x) {
69  
                    newImage.setPixel(x, y, p.processKernel(this.extractROI(x, y, tmp)));
70  
                }
71  
            }
72  
        } else {
73  
            for(y = 0; y < this.getHeight(); ++y) {
74  
                for(x = 0; x < this.getWidth(); ++x) {
75  
                    newImage.setPixel(x, y, p.processKernel(this.extractROI(x, y, tmp)));
76  
                }
77  
            }
78  
        }
79  
80  
        return newImage;
81  
    }
82  
83  
    public I processInplace(SinglebandKernelProcessor<Q, I> p) {
84  
        return this.processInplace(p, false);
85  
    }
86  
87  
    public I processInplace(SinglebandKernelProcessor<Q, I> p, boolean pad) {
88  
        I newImage = this.process(p, pad);
89  
        this.internalAssign(newImage);
90  
        return this;
91  
    }
92  
93  
    public I process(SinglebandImageProcessor<Q, I> p) {
94  
        I newImage = this.clone();
95  
        newImage.processInplace(p);
96  
        return newImage;
97  
    }
98  
99  
    public I processInplace(SinglebandImageProcessor<Q, I> p) {
100  
        p.processImage(this);
101  
        return this;
102  
    }
103  
104  
    public I fill(Q colour) {
105  
        for(int y = 0; y < this.getHeight(); ++y) {
106  
            for(int x = 0; x < this.getWidth(); ++x) {
107  
                this.setPixel(x, y, colour);
108  
            }
109  
        }
110  
111  
        return this;
112  
    }
113  
114  
    public abstract I clone();
115  
116  
    public boolean equals(Object obj) {
117  
        I that = (SingleBandImage)obj;
118  
119  
        for(int y = 0; y < this.getHeight(); ++y) {
120  
            for(int x = 0; x < this.getWidth(); ++x) {
121  
                boolean fail = !((Comparable)this.getPixel(x, y)).equals(that.getPixel(x, y));
122  
                if (fail) {
123  
                    return false;
124  
                }
125  
            }
126  
        }
127  
128  
        return true;
129  
    }
130  
}
131  
132  
133  
sclass FImage extends SingleBandImage<Float, FImage> {
134  
    private static final long serialVersionUID = 1L;
135  
    protected static Logger logger = Logger.getLogger(FImage.class);
136  
    protected static final float DEFAULT_GAUSS_TRUNCATE = 4.0F;
137  
    public float[][] pixels;
138  
139  
    public FImage(float[] array, int width, int height) {
140  
        assert array.length == width * height;
141  
142  
        this.pixels = new float[height][width];
143  
        this.height = height;
144  
        this.width = width;
145  
146  
        for(int y = 0; y < height; ++y) {
147  
            for(int x = 0; x < width; ++x) {
148  
                this.pixels[y][x] = array[y * width + x];
149  
            }
150  
        }
151  
152  
    }
153  
154  
    public FImage(double[] array, int width, int height) {
155  
        assert array.length == width * height;
156  
157  
        this.pixels = new float[height][width];
158  
        this.height = height;
159  
        this.width = width;
160  
161  
        for(int y = 0; y < height; ++y) {
162  
            for(int x = 0; x < width; ++x) {
163  
                this.pixels[y][x] = (float)array[y * width + x];
164  
            }
165  
        }
166  
167  
    }
168  
169  
    public FImage(double[] array, int width, int height, int offset) {
170  
        assert array.length == width * height;
171  
172  
        this.pixels = new float[height][width];
173  
        this.height = height;
174  
        this.width = width;
175  
176  
        for(int y = 0; y < height; ++y) {
177  
            for(int x = 0; x < width; ++x) {
178  
                this.pixels[y][x] = (float)array[offset + y * width + x];
179  
            }
180  
        }
181  
182  
    }
183  
184  
    public FImage(float[][] array) {
185  
        this.pixels = array;
186  
        this.height = array.length;
187  
        this.width = array[0].length;
188  
    }
189  
190  
    public FImage(int width, int height) {
191  
        this.pixels = new float[height][width];
192  
        this.height = height;
193  
        this.width = width;
194  
    }
195  
196  
    public FImage(int[] data, int width, int height) {
197  
        this.internalAssign(data, width, height);
198  
    }
199  
200  
    public FImage(int[] data, int width, int height, ARGBPlane plane) {
201  
        this.width = width;
202  
        this.height = height;
203  
        this.pixels = new float[height][width];
204  
205  
        for(int y = 0; y < height; ++y) {
206  
            for(int x = 0; x < width; ++x) {
207  
                int rgb = data[x + y * width];
208  
                int colour = 0;
209  
                switch(plane) {
210  
                case RED:
211  
                    colour = rgb >> 16 & 255;
212  
                    break;
213  
                case GREEN:
214  
                    colour = rgb >> 8 & 255;
215  
                    break;
216  
                case BLUE:
217  
                    colour = rgb & 255;
218  
                }
219  
220  
                this.pixels[y][x] = (float)colour;
221  
            }
222  
        }
223  
224  
    }
225  
226  
    public FImage abs() {
227  
        for(int r = 0; r < this.height; ++r) {
228  
            for(int c = 0; c < this.width; ++c) {
229  
                this.pixels[r][c] = Math.abs(this.pixels[r][c]);
230  
            }
231  
        }
232  
233  
        return this;
234  
    }
235  
236  
    public FImage add(FImage im) {
237  
        if (!ImageUtilities.checkSameSize(new Image[]{this, im})) {
238  
            throw new AssertionError("images must be the same size");
239  
        } else {
240  
            FImage newImage = new FImage(im.width, im.height);
241  
242  
            for(int r = 0; r < im.height; ++r) {
243  
                for(int c = 0; c < im.width; ++c) {
244  
                    newImage.pixels[r][c] = this.pixels[r][c] + im.pixels[r][c];
245  
                }
246  
            }
247  
248  
            return newImage;
249  
        }
250  
    }
251  
252  
    public FImage add(Float num) {
253  
        FImage newImage = new FImage(this.width, this.height);
254  
        float fnum = num;
255  
256  
        for(int r = 0; r < this.height; ++r) {
257  
            for(int c = 0; c < this.width; ++c) {
258  
                newImage.pixels[r][c] = this.pixels[r][c] + fnum;
259  
            }
260  
        }
261  
262  
        return newImage;
263  
    }
264  
265  
    public FImage add(Image<?, ?> im) {
266  
        if (im instanceof FImage) {
267  
            return this.add((FImage)im);
268  
        } else {
269  
            throw new UnsupportedOperationException("Unsupported Type");
270  
        }
271  
    }
272  
273  
    public FImage addInplace(FImage im) {
274  
        if (!ImageUtilities.checkSameSize(new Image[]{this, im})) {
275  
            throw new AssertionError("images must be the same size");
276  
        } else {
277  
            for(int r = 0; r < im.height; ++r) {
278  
                for(int c = 0; c < im.width; ++c) {
279  
                    this.pixels[r][c] += im.pixels[r][c];
280  
                }
281  
            }
282  
283  
            return this;
284  
        }
285  
    }
286  
287  
    public FImage addInplace(Float num) {
288  
        float fnum = num;
289  
290  
        for(int r = 0; r < this.height; ++r) {
291  
            for(int c = 0; c < this.width; ++c) {
292  
                this.pixels[r][c] += fnum;
293  
            }
294  
        }
295  
296  
        return this;
297  
    }
298  
299  
    public FImage addInplace(Image<?, ?> im) {
300  
        if (im instanceof FImage) {
301  
            return this.addInplace((FImage)im);
302  
        } else {
303  
            throw new UnsupportedOperationException("Unsupported Type");
304  
        }
305  
    }
306  
307  
    public FImage clip(Float min, Float max) {
308  
        for(int r = 0; r < this.height; ++r) {
309  
            for(int c = 0; c < this.width; ++c) {
310  
                if (this.pixels[r][c] < min) {
311  
                    this.pixels[r][c] = 0.0F;
312  
                }
313  
314  
                if (this.pixels[r][c] > max) {
315  
                    this.pixels[r][c] = 1.0F;
316  
                }
317  
            }
318  
        }
319  
320  
        return this;
321  
    }
322  
323  
    public FImage clipMax(Float thresh) {
324  
        float fthresh = thresh;
325  
326  
        for(int r = 0; r < this.height; ++r) {
327  
            for(int c = 0; c < this.width; ++c) {
328  
                if (this.pixels[r][c] > fthresh) {
329  
                    this.pixels[r][c] = 1.0F;
330  
                }
331  
            }
332  
        }
333  
334  
        return this;
335  
    }
336  
337  
    public FImage clipMin(Float thresh) {
338  
        float fthresh = thresh;
339  
340  
        for(int r = 0; r < this.height; ++r) {
341  
            for(int c = 0; c < this.width; ++c) {
342  
                if (this.pixels[r][c] < fthresh) {
343  
                    this.pixels[r][c] = 0.0F;
344  
                }
345  
            }
346  
        }
347  
348  
        return this;
349  
    }
350  
351  
    public FImage clone() {
352  
        FImage cpy = new FImage(this.width, this.height);
353  
354  
        for(int r = 0; r < this.height; ++r) {
355  
            System.arraycopy(this.pixels[r], 0, cpy.pixels[r], 0, this.width);
356  
        }
357  
358  
        return cpy;
359  
    }
360  
361  
    public FImageRenderer createRenderer() {
362  
        return new FImageRenderer(this);
363  
    }
364  
365  
    public FImageRenderer createRenderer(RenderHints options) {
366  
        return new FImageRenderer(this, options);
367  
    }
368  
369  
    public FImage divide(FImage im) {
370  
        if (!ImageUtilities.checkSameSize(new Image[]{this, im})) {
371  
            throw new AssertionError("images must be the same size");
372  
        } else {
373  
            FImage newImage = new FImage(im.width, im.height);
374  
375  
            for(int r = 0; r < im.height; ++r) {
376  
                for(int c = 0; c < im.width; ++c) {
377  
                    newImage.pixels[r][c] = this.pixels[r][c] / im.pixels[r][c];
378  
                }
379  
            }
380  
381  
            return newImage;
382  
        }
383  
    }
384  
385  
    public FImage divideInplace(FImage im) {
386  
        if (!ImageUtilities.checkSameSize(new Image[]{this, im})) {
387  
            throw new AssertionError("images must be the same size");
388  
        } else {
389  
            for(int y = 0; y < this.height; ++y) {
390  
                for(int x = 0; x < this.width; ++x) {
391  
                    this.pixels[y][x] /= im.pixels[y][x];
392  
                }
393  
            }
394  
395  
            return this;
396  
        }
397  
    }
398  
399  
    public FImage divideInplace(Float val) {
400  
        float fval = val;
401  
402  
        for(int y = 0; y < this.height; ++y) {
403  
            for(int x = 0; x < this.width; ++x) {
404  
                this.pixels[y][x] /= fval;
405  
            }
406  
        }
407  
408  
        return this;
409  
    }
410  
411  
    public FImage divideInplace(float fval) {
412  
        for(int y = 0; y < this.height; ++y) {
413  
            for(int x = 0; x < this.width; ++x) {
414  
                this.pixels[y][x] /= fval;
415  
            }
416  
        }
417  
418  
        return this;
419  
    }
420  
421  
    public FImage divideInplace(Image<?, ?> im) {
422  
        if (im instanceof FImage) {
423  
            return this.divideInplace((FImage)im);
424  
        } else {
425  
            throw new UnsupportedOperationException("Unsupported Type");
426  
        }
427  
    }
428  
429  
    public FImage extractROI(int x, int y, FImage out) {
430  
        int r = y;
431  
432  
        for(int rr = 0; rr < out.height; ++rr) {
433  
            int c = x;
434  
435  
            for(int cc = 0; cc < out.width; ++cc) {
436  
                if (r >= 0 && r < this.height && c >= 0 && c < this.width) {
437  
                    out.pixels[rr][cc] = this.pixels[r][c];
438  
                } else {
439  
                    out.pixels[rr][cc] = 0.0F;
440  
                }
441  
442  
                ++c;
443  
            }
444  
445  
            ++r;
446  
        }
447  
448  
        return out;
449  
    }
450  
451  
    public FImage extractROI(int x, int y, int w, int h) {
452  
        FImage out = new FImage(w, h);
453  
        int r = y;
454  
455  
        for(int rr = 0; rr < h; ++rr) {
456  
            int c = x;
457  
458  
            for(int cc = 0; cc < w; ++cc) {
459  
                if (r >= 0 && r < this.height && c >= 0 && c < this.width) {
460  
                    out.pixels[rr][cc] = this.pixels[r][c];
461  
                } else {
462  
                    out.pixels[rr][cc] = 0.0F;
463  
                }
464  
465  
                ++c;
466  
            }
467  
468  
            ++r;
469  
        }
470  
471  
        return out;
472  
    }
473  
474  
    public FImage fill(Float colour) {
475  
        for(int r = 0; r < this.height; ++r) {
476  
            for(int c = 0; c < this.width; ++c) {
477  
                this.pixels[r][c] = colour;
478  
            }
479  
        }
480  
481  
        return this;
482  
    }
483  
484  
    public FImage fill(float colour) {
485  
        for(int r = 0; r < this.height; ++r) {
486  
            for(int c = 0; c < this.width; ++c) {
487  
                this.pixels[r][c] = colour;
488  
            }
489  
        }
490  
491  
        return this;
492  
    }
493  
494  
    public Rectangle getContentArea() {
495  
        int minc = this.width;
496  
        int maxc = 0;
497  
        int minr = this.height;
498  
        int maxr = 0;
499  
500  
        for(int r = 0; r < this.height; ++r) {
501  
            for(int c = 0; c < this.width; ++c) {
502  
                if (this.pixels[r][c] > 0.0F) {
503  
                    if (c < minc) {
504  
                        minc = c;
505  
                    }
506  
507  
                    if (c > maxc) {
508  
                        maxc = c;
509  
                    }
510  
511  
                    if (r < minr) {
512  
                        minr = r;
513  
                    }
514  
515  
                    if (r > maxr) {
516  
                        maxr = r;
517  
                    }
518  
                }
519  
            }
520  
        }
521  
522  
        return new Rectangle((float)minc, (float)minr, (float)(maxc - minc + 1), (float)(maxr - minr + 1));
523  
    }
524  
525  
    public double[] getDoublePixelVector() {
526  
        double[] f = new double[this.height * this.width];
527  
528  
        for(int y = 0; y < this.height; ++y) {
529  
            for(int x = 0; x < this.width; ++x) {
530  
                f[x + y * this.width] = (double)this.pixels[y][x];
531  
            }
532  
        }
533  
534  
        return f;
535  
    }
536  
537  
    public FImage getField(Field f) {
538  
        FImage img = new FImage(this.width, this.height / 2);
539  
        int init = f.equals(Field.ODD) ? 1 : 0;
540  
        int r = init;
541  
542  
        for(int r2 = 0; r < this.height && r2 < this.height / 2; ++r2) {
543  
            for(int c = 0; c < this.width; ++c) {
544  
                img.pixels[r2][c] = this.pixels[r][c];
545  
            }
546  
547  
            r += 2;
548  
        }
549  
550  
        return img;
551  
    }
552  
553  
    public FImage getFieldCopy(Field f) {
554  
        FImage img = new FImage(this.width, this.height);
555  
556  
        for(int r = 0; r < this.height; r += 2) {
557  
            for(int c = 0; c < this.width; ++c) {
558  
                if (f.equals(Field.EVEN)) {
559  
                    img.pixels[r][c] = this.pixels[r][c];
560  
                    img.pixels[r + 1][c] = this.pixels[r][c];
561  
                } else {
562  
                    img.pixels[r][c] = this.pixels[r + 1][c];
563  
                    img.pixels[r + 1][c] = this.pixels[r + 1][c];
564  
                }
565  
            }
566  
        }
567  
568  
        return img;
569  
    }
570  
571  
    public FImage getFieldInterpolate(Field f) {
572  
        FImage img = new FImage(this.width, this.height);
573  
574  
        for(int r = 0; r < this.height; r += 2) {
575  
            for(int c = 0; c < this.width; ++c) {
576  
                if (f.equals(Field.EVEN)) {
577  
                    img.pixels[r][c] = this.pixels[r][c];
578  
                    if (r + 2 == this.height) {
579  
                        img.pixels[r + 1][c] = this.pixels[r][c];
580  
                    } else {
581  
                        img.pixels[r + 1][c] = 0.5F * (this.pixels[r][c] + this.pixels[r + 2][c]);
582  
                    }
583  
                } else {
584  
                    img.pixels[r + 1][c] = this.pixels[r + 1][c];
585  
                    if (r == 0) {
586  
                        img.pixels[r][c] = this.pixels[r + 1][c];
587  
                    } else {
588  
                        img.pixels[r][c] = 0.5F * (this.pixels[r - 1][c] + this.pixels[r + 1][c]);
589  
                    }
590  
                }
591  
            }
592  
        }
593  
594  
        return img;
595  
    }
596  
597  
    public float[] getFloatPixelVector() {
598  
        float[] f = new float[this.height * this.width];
599  
600  
        for(int y = 0; y < this.height; ++y) {
601  
            for(int x = 0; x < this.width; ++x) {
602  
                f[x + y * this.width] = this.pixels[y][x];
603  
            }
604  
        }
605  
606  
        return f;
607  
    }
608  
609  
    public Float getPixel(int x, int y) {
610  
        return this.pixels[y][x];
611  
    }
612  
613  
    public Comparator<? super Float> getPixelComparator() {
614  
        return new Comparator<Float>() {
615  
            public int compare(Float o1, Float o2) {
616  
                return o1.compareTo(o2);
617  
            }
618  
        };
619  
    }
620  
621  
    public Float getPixelInterp(double x, double y) {
622  
        int x0 = (int)Math.floor(x);
623  
        int x1 = x0 + 1;
624  
        int y0 = (int)Math.floor(y);
625  
        int y1 = y0 + 1;
626  
        if (x0 < 0) {
627  
            x0 = 0;
628  
        }
629  
630  
        if (x0 >= this.width) {
631  
            x0 = this.width - 1;
632  
        }
633  
634  
        if (y0 < 0) {
635  
            y0 = 0;
636  
        }
637  
638  
        if (y0 >= this.height) {
639  
            y0 = this.height - 1;
640  
        }
641  
642  
        if (x1 < 0) {
643  
            x1 = 0;
644  
        }
645  
646  
        if (x1 >= this.width) {
647  
            x1 = this.width - 1;
648  
        }
649  
650  
        if (y1 < 0) {
651  
            y1 = 0;
652  
        }
653  
654  
        if (y1 >= this.height) {
655  
            y1 = this.height - 1;
656  
        }
657  
658  
        float f00 = this.pixels[y0][x0];
659  
        float f01 = this.pixels[y1][x0];
660  
        float f10 = this.pixels[y0][x1];
661  
        float f11 = this.pixels[y1][x1];
662  
        float dx = (float)(x - (double)x0);
663  
        float dy = (float)(y - (double)y0);
664  
        if (dx < 0.0F) {
665  
            ++dx;
666  
        }
667  
668  
        if (dy < 0.0F) {
669  
            ++dy;
670  
        }
671  
672  
        return Interpolation.bilerp(dx, dy, f00, f01, f10, f11);
673  
    }
674  
675  
    public Float getPixelInterp(double x, double y, Float background) {
676  
        int x0 = (int)Math.floor(x);
677  
        int x1 = x0 + 1;
678  
        int y0 = (int)Math.floor(y);
679  
        int y1 = y0 + 1;
680  
        boolean ty1 = true;
681  
        boolean tx1 = true;
682  
        boolean ty0 = true;
683  
        boolean tx0 = true;
684  
        if (x0 < 0) {
685  
            tx0 = false;
686  
        }
687  
688  
        if (x0 >= this.width) {
689  
            tx0 = false;
690  
        }
691  
692  
        if (y0 < 0) {
693  
            ty0 = false;
694  
        }
695  
696  
        if (y0 >= this.height) {
697  
            ty0 = false;
698  
        }
699  
700  
        if (x1 < 0) {
701  
            tx1 = false;
702  
        }
703  
704  
        if (x1 >= this.width) {
705  
            tx1 = false;
706  
        }
707  
708  
        if (y1 < 0) {
709  
            ty1 = false;
710  
        }
711  
712  
        if (y1 >= this.height) {
713  
            ty1 = false;
714  
        }
715  
716  
        double f00 = (double)(ty0 && tx0 ? this.pixels[y0][x0] : background);
717  
        double f01 = (double)(ty1 && tx0 ? this.pixels[y1][x0] : background);
718  
        double f10 = (double)(ty0 && tx1 ? this.pixels[y0][x1] : background);
719  
        double f11 = (double)(ty1 && tx1 ? this.pixels[y1][x1] : background);
720  
        double dx = x - (double)x0;
721  
        double dy = y - (double)y0;
722  
        if (dx < 0.0D) {
723  
            ++dx;
724  
        }
725  
726  
        if (dy < 0.0D) {
727  
            ++dy;
728  
        }
729  
730  
        double interpVal = Interpolation.bilerp(dx, dy, f00, f01, f10, f11);
731  
        return (float)interpVal;
732  
    }
733  
734  
    public float getPixelInterpNative(float x, float y, float background) {
735  
        int x0 = (int)Math.floor((double)x);
736  
        int x1 = x0 + 1;
737  
        int y0 = (int)Math.floor((double)y);
738  
        int y1 = y0 + 1;
739  
        boolean ty1 = true;
740  
        boolean tx1 = true;
741  
        boolean ty0 = true;
742  
        boolean tx0 = true;
743  
        if (x0 < 0) {
744  
            tx0 = false;
745  
        }
746  
747  
        if (x0 >= this.width) {
748  
            tx0 = false;
749  
        }
750  
751  
        if (y0 < 0) {
752  
            ty0 = false;
753  
        }
754  
755  
        if (y0 >= this.height) {
756  
            ty0 = false;
757  
        }
758  
759  
        if (x1 < 0) {
760  
            tx1 = false;
761  
        }
762  
763  
        if (x1 >= this.width) {
764  
            tx1 = false;
765  
        }
766  
767  
        if (y1 < 0) {
768  
            ty1 = false;
769  
        }
770  
771  
        if (y1 >= this.height) {
772  
            ty1 = false;
773  
        }
774  
775  
        float f00 = ty0 && tx0 ? this.pixels[y0][x0] : background;
776  
        float f01 = ty1 && tx0 ? this.pixels[y1][x0] : background;
777  
        float f10 = ty0 && tx1 ? this.pixels[y0][x1] : background;
778  
        float f11 = ty1 && tx1 ? this.pixels[y1][x1] : background;
779  
        float dx = x - (float)x0;
780  
        float dy = y - (float)y0;
781  
        if (dx < 0.0F) {
782  
            ++dx;
783  
        }
784  
785  
        if (dy < 0.0F) {
786  
            ++dy;
787  
        }
788  
789  
        float interpVal = Interpolation.bilerpf(dx, dy, f00, f01, f10, f11);
790  
        return interpVal;
791  
    }
792  
793  
    public FImage internalCopy(FImage im) {
794  
        int h = im.height;
795  
        int w = im.width;
796  
        float[][] impixels = im.pixels;
797  
798  
        for(int r = 0; r < h; ++r) {
799  
            System.arraycopy(impixels[r], 0, this.pixels[r], 0, w);
800  
        }
801  
802  
        return this;
803  
    }
804  
805  
    public FImage internalAssign(FImage im) {
806  
        this.pixels = im.pixels;
807  
        this.height = im.height;
808  
        this.width = im.width;
809  
        return this;
810  
    }
811  
812  
    public FImage internalAssign(int[] data, int width, int height) {
813  
        if (this.height != height || this.width != width) {
814  
            this.height = height;
815  
            this.width = width;
816  
            this.pixels = new float[height][width];
817  
        }
818  
819  
        for(int y = 0; y < height; ++y) {
820  
            for(int x = 0; x < width; ++x) {
821  
                int rgb = data[x + width * y];
822  
                int red = rgb >> 16 & 255;
823  
                int green = rgb >> 8 & 255;
824  
                int blue = rgb & 255;
825  
                float fpix = 0.299F * (float)red + 0.587F * (float)green + 0.114F * (float)blue;
826  
                this.pixels[y][x] = ImageUtilities.BYTE_TO_FLOAT_LUT[(int)fpix];
827  
            }
828  
        }
829  
830  
        return this;
831  
    }
832  
833  
    public FImage inverse() {
834  
        float max = this.max();
835  
836  
        for(int r = 0; r < this.height; ++r) {
837  
            for(int c = 0; c < this.width; ++c) {
838  
                this.pixels[r][c] = max - this.pixels[r][c];
839  
            }
840  
        }
841  
842  
        return this;
843  
    }
844  
845  
    public Float max() {
846  
        float max = 1.4E-45F;
847  
848  
        for(int r = 0; r < this.height; ++r) {
849  
            for(int c = 0; c < this.width; ++c) {
850  
                if (max < this.pixels[r][c]) {
851  
                    max = this.pixels[r][c];
852  
                }
853  
            }
854  
        }
855  
856  
        return max;
857  
    }
858  
859  
    public FValuePixel maxPixel() {
860  
        FValuePixel max = new FValuePixel(-1, -1);
861  
        max.value = -3.4028235E38F;
862  
863  
        for(int y = 0; y < this.height; ++y) {
864  
            for(int x = 0; x < this.width; ++x) {
865  
                if (max.value < this.pixels[y][x]) {
866  
                    max.value = this.pixels[y][x];
867  
                    max.x = x;
868  
                    max.y = y;
869  
                }
870  
            }
871  
        }
872  
873  
        return max;
874  
    }
875  
876  
    public Float min() {
877  
        float min = 3.4028235E38F;
878  
879  
        for(int r = 0; r < this.height; ++r) {
880  
            for(int c = 0; c < this.width; ++c) {
881  
                if (min > this.pixels[r][c]) {
882  
                    min = this.pixels[r][c];
883  
                }
884  
            }
885  
        }
886  
887  
        return min;
888  
    }
889  
890  
    public FValuePixel minPixel() {
891  
        FValuePixel min = new FValuePixel(-1, -1);
892  
        min.value = 3.4028235E38F;
893  
894  
        for(int y = 0; y < this.height; ++y) {
895  
            for(int x = 0; x < this.width; ++x) {
896  
                if (min.value > this.pixels[y][x]) {
897  
                    min.value = this.pixels[y][x];
898  
                    min.x = x;
899  
                    min.y = y;
900  
                }
901  
            }
902  
        }
903  
904  
        return min;
905  
    }
906  
907  
    public FImage multiply(Float num) {
908  
        return (FImage)super.multiply(num);
909  
    }
910  
911  
    public FImage multiplyInplace(FImage im) {
912  
        if (!ImageUtilities.checkSameSize(new Image[]{this, im})) {
913  
            throw new AssertionError("images must be the same size");
914  
        } else {
915  
            for(int r = 0; r < this.height; ++r) {
916  
                for(int c = 0; c < this.width; ++c) {
917  
                    this.pixels[r][c] *= im.pixels[r][c];
918  
                }
919  
            }
920  
921  
            return this;
922  
        }
923  
    }
924  
925  
    public FImage multiplyInplace(Float num) {
926  
        float fnum = num;
927  
928  
        for(int r = 0; r < this.height; ++r) {
929  
            for(int c = 0; c < this.width; ++c) {
930  
                this.pixels[r][c] *= fnum;
931  
            }
932  
        }
933  
934  
        return this;
935  
    }
936  
937  
    public FImage multiplyInplace(float fnum) {
938  
        for(int r = 0; r < this.height; ++r) {
939  
            for(int c = 0; c < this.width; ++c) {
940  
                this.pixels[r][c] *= fnum;
941  
            }
942  
        }
943  
944  
        return this;
945  
    }
946  
947  
    public FImage multiplyInplace(Image<?, ?> im) {
948  
        if (im instanceof FImage) {
949  
            return this.multiplyInplace((FImage)im);
950  
        } else {
951  
            throw new UnsupportedOperationException("Unsupported Type");
952  
        }
953  
    }
954  
955  
    public FImage newInstance(int width, int height) {
956  
        return new FImage(width, height);
957  
    }
958  
959  
    public FImage normalise() {
960  
        float min = this.min();
961  
        float max = this.max();
962  
        if (max == min) {
963  
            return this;
964  
        } else {
965  
            for(int r = 0; r < this.height; ++r) {
966  
                for(int c = 0; c < this.width; ++c) {
967  
                    this.pixels[r][c] = (this.pixels[r][c] - min) / (max - min);
968  
                }
969  
            }
970  
971  
            return this;
972  
        }
973  
    }
974  
975  
    public FImage process(KernelProcessor<Float, FImage> p) {
976  
        return this.process(p, false);
977  
    }
978  
979  
    public FImage process(KernelProcessor<Float, FImage> p, boolean pad) {
980  
        FImage newImage = new FImage(this.width, this.height);
981  
        int kh = p.getKernelHeight();
982  
        int kw = p.getKernelWidth();
983  
        FImage tmp = new FImage(kw, kh);
984  
        int hh = kh / 2;
985  
        int hw = kw / 2;
986  
        int y;
987  
        int x;
988  
        if (!pad) {
989  
            for(y = hh; y < this.height - (kh - hh); ++y) {
990  
                for(x = hw; x < this.width - (kw - hw); ++x) {
991  
                    newImage.pixels[y][x] = (Float)p.processKernel(this.extractROI(x - hw, y - hh, tmp));
992  
                }
993  
            }
994  
        } else {
995  
            for(y = 0; y < this.height; ++y) {
996  
                for(x = 0; x < this.width; ++x) {
997  
                    newImage.pixels[y][x] = (Float)p.processKernel(this.extractROI(x - hw, y - hh, tmp));
998  
                }
999  
            }
1000  
        }
1001  
1002  
        return newImage;
1003  
    }
1004  
1005  
    public FImage processInplace(PixelProcessor<Float> p) {
1006  
        for(int y = 0; y < this.height; ++y) {
1007  
            for(int x = 0; x < this.width; ++x) {
1008  
                this.pixels[y][x] = (Float)p.processPixel(this.pixels[y][x]);
1009  
            }
1010  
        }
1011  
1012  
        return this;
1013  
    }
1014  
1015  
    public void analyseWith(PixelAnalyser<Float> p) {
1016  
        p.reset();
1017  
1018  
        for(int y = 0; y < this.height; ++y) {
1019  
            for(int x = 0; x < this.width; ++x) {
1020  
                p.analysePixel(this.pixels[y][x]);
1021  
            }
1022  
        }
1023  
1024  
    }
1025  
1026  
    public void setPixel(int x, int y, Float val) {
1027  
        if (x >= 0 && x < this.width && y >= 0 && y < this.height) {
1028  
            this.pixels[y][x] = val;
1029  
        }
1030  
1031  
    }
1032  
1033  
    public FImage subtract(FImage im) {
1034  
        if (!ImageUtilities.checkSameSize(new Image[]{this, im})) {
1035  
            throw new AssertionError("images must be the same size");
1036  
        } else {
1037  
            FImage newImage = new FImage(im.width, im.height);
1038  
1039  
            for(int r = 0; r < im.height; ++r) {
1040  
                for(int c = 0; c < im.width; ++c) {
1041  
                    newImage.pixels[r][c] = this.pixels[r][c] - im.pixels[r][c];
1042  
                }
1043  
            }
1044  
1045  
            return newImage;
1046  
        }
1047  
    }
1048  
1049  
    public FImage subtract(Float num) {
1050  
        FImage newImage = new FImage(this.width, this.height);
1051  
1052  
        for(int r = 0; r < this.height; ++r) {
1053  
            for(int c = 0; c < this.width; ++c) {
1054  
                newImage.pixels[r][c] = this.pixels[r][c] - num;
1055  
            }
1056  
        }
1057  
1058  
        return newImage;
1059  
    }
1060  
1061  
    public FImage subtract(Image<?, ?> input) {
1062  
        if (input instanceof FImage) {
1063  
            return this.subtract((FImage)input);
1064  
        } else {
1065  
            throw new UnsupportedOperationException("Unsupported Type");
1066  
        }
1067  
    }
1068  
1069  
    public FImage subtractInplace(FImage im) {
1070  
        if (!ImageUtilities.checkSameSize(new Image[]{this, im})) {
1071  
            throw new AssertionError("images must be the same size");
1072  
        } else {
1073  
            float[][] pix1 = this.pixels;
1074  
            float[][] pix2 = im.pixels;
1075  
1076  
            for(int r = 0; r < this.height; ++r) {
1077  
                for(int c = 0; c < this.width; ++c) {
1078  
                    pix1[r][c] -= pix2[r][c];
1079  
                }
1080  
            }
1081  
1082  
            return this;
1083  
        }
1084  
    }
1085  
1086  
    public FImage subtractInplace(Float num) {
1087  
        float fnum = num;
1088  
1089  
        for(int r = 0; r < this.height; ++r) {
1090  
            for(int c = 0; c < this.width; ++c) {
1091  
                this.pixels[r][c] -= fnum;
1092  
            }
1093  
        }
1094  
1095  
        return this;
1096  
    }
1097  
1098  
    public FImage subtractInplace(Image<?, ?> im) {
1099  
        if (im instanceof FImage) {
1100  
            return this.subtractInplace((FImage)im);
1101  
        } else {
1102  
            throw new UnsupportedOperationException("Unsupported Type");
1103  
        }
1104  
    }
1105  
1106  
    public FImage threshold(Float thresh) {
1107  
        float fthresh = thresh;
1108  
1109  
        for(int r = 0; r < this.height; ++r) {
1110  
            for(int c = 0; c < this.width; ++c) {
1111  
                if (this.pixels[r][c] <= fthresh) {
1112  
                    this.pixels[r][c] = 0.0F;
1113  
                } else {
1114  
                    this.pixels[r][c] = 1.0F;
1115  
                }
1116  
            }
1117  
        }
1118  
1119  
        return this;
1120  
    }
1121  
1122  
    public byte[] toByteImage() {
1123  
        byte[] pgmData = new byte[this.height * this.width];
1124  
1125  
        for(int j = 0; j < this.height; ++j) {
1126  
            for(int i = 0; i < this.width; ++i) {
1127  
                int v = (int)(255.0F * this.pixels[j][i]);
1128  
                v = Math.max(0, Math.min(255, v));
1129  
                pgmData[i + j * this.width] = (byte)(v & 255);
1130  
            }
1131  
        }
1132  
1133  
        return pgmData;
1134  
    }
1135  
1136  
    public int[] toPackedARGBPixels() {
1137  
        int[] bimg = new int[this.width * this.height];
1138  
1139  
        for(int r = 0; r < this.height; ++r) {
1140  
            for(int c = 0; c < this.width; ++c) {
1141  
                int v = Math.max(0, Math.min(255, (int)(this.pixels[r][c] * 255.0F)));
1142  
                int rgb = -16777216 | v << 16 | v << 8 | v;
1143  
                bimg[c + this.width * r] = rgb;
1144  
            }
1145  
        }
1146  
1147  
        return bimg;
1148  
    }
1149  
1150  
    public String toString() {
1151  
        String imageString = "";
1152  
1153  
        for(int y = 0; y < this.height; ++y) {
1154  
            for(int x = 0; x < this.width; ++x) {
1155  
                imageString = imageString + String.format("%+.3f ", this.pixels[y][x]);
1156  
                if (x == 16 && this.width - 16 > x) {
1157  
                    imageString = imageString + "... ";
1158  
                    x = this.width - 16;
1159  
                }
1160  
            }
1161  
1162  
            imageString = imageString + "\n";
1163  
            if (y == 16 && this.height - 16 > y) {
1164  
                y = this.height - 16;
1165  
                imageString = imageString + "... \n";
1166  
            }
1167  
        }
1168  
1169  
        return imageString;
1170  
    }
1171  
1172  
    public String toString(String format) {
1173  
        String imageString = "";
1174  
1175  
        for(int y = 0; y < this.height; ++y) {
1176  
            for(int x = 0; x < this.width; ++x) {
1177  
                imageString = imageString + String.format(format, this.pixels[y][x]);
1178  
            }
1179  
1180  
            imageString = imageString + "\n";
1181  
        }
1182  
1183  
        return imageString;
1184  
    }
1185  
1186  
    public FImage transform(Matrix transform) {
1187  
        return (FImage)super.transform(transform);
1188  
    }
1189  
1190  
    public FImage zero() {
1191  
        for(int r = 0; r < this.height; ++r) {
1192  
            for(int c = 0; c < this.width; ++c) {
1193  
                this.pixels[r][c] = 0.0F;
1194  
            }
1195  
        }
1196  
1197  
        return this;
1198  
    }
1199  
1200  
    public boolean equals(Object o) {
1201  
        return !(o instanceof FImage) ? false : this.equalsThresh((FImage)o, 0.0F);
1202  
    }
1203  
1204  
    public boolean equalsThresh(FImage o, float thresh) {
1205  
        FImage that = o;
1206  
        if (o.height == this.height && o.width == this.width) {
1207  
            for(int i = 0; i < this.height; ++i) {
1208  
                for(int j = 0; j < this.width; ++j) {
1209  
                    if (Math.abs(that.pixels[i][j] - this.pixels[i][j]) > thresh) {
1210  
                        return false;
1211  
                    }
1212  
                }
1213  
            }
1214  
1215  
            return true;
1216  
        } else {
1217  
            return false;
1218  
        }
1219  
    }
1220  
1221  
    public float getPixelNative(Pixel p) {
1222  
        return this.getPixelNative(p.x, p.y);
1223  
    }
1224  
1225  
    public float getPixelNative(int x, int y) {
1226  
        return this.pixels[y][x];
1227  
    }
1228  
1229  
    public float[] getPixelVectorNative(float[] f) {
1230  
        for(int y = 0; y < this.getHeight(); ++y) {
1231  
            for(int x = 0; x < this.getWidth(); ++x) {
1232  
                f[x + y * this.getWidth()] = this.pixels[y][x];
1233  
            }
1234  
        }
1235  
1236  
        return f;
1237  
    }
1238  
1239  
    public void setPixelNative(int x, int y, float val) {
1240  
        this.pixels[y][x] = val;
1241  
    }
1242  
1243  
    public static FImage[] createArray(int num, int width, int height) {
1244  
        FImage[] array = new FImage[num];
1245  
1246  
        for(int i = 0; i < num; ++i) {
1247  
            array[i] = new FImage(width, height);
1248  
        }
1249  
1250  
        return array;
1251  
    }
1252  
1253  
    public float sum() {
1254  
        float sum = 0.0F;
1255  
        float[][] var2 = this.pixels;
1256  
        int var3 = var2.length;
1257  
1258  
        for(int var4 = 0; var4 < var3; ++var4) {
1259  
            float[] row = var2[var4];
1260  
1261  
            for(int i = 0; i < row.length; ++i) {
1262  
                sum += row[i];
1263  
            }
1264  
        }
1265  
1266  
        return sum;
1267  
    }
1268  
1269  
    public MBFImage toRGB() {
1270  
        return new MBFImage(ColourSpace.RGB, new FImage[]{this.clone(), this.clone(), this.clone()});
1271  
    }
1272  
1273  
    public FImage flipX() {
1274  
        int hwidth = this.width / 2;
1275  
1276  
        for(int y = 0; y < this.height; ++y) {
1277  
            for(int x = 0; x < hwidth; ++x) {
1278  
                int xx = this.width - x - 1;
1279  
                float tmp = this.pixels[y][x];
1280  
                this.pixels[y][x] = this.pixels[y][xx];
1281  
                this.pixels[y][xx] = tmp;
1282  
            }
1283  
        }
1284  
1285  
        return this;
1286  
    }
1287  
1288  
    public FImage flipY() {
1289  
        int hheight = this.height / 2;
1290  
1291  
        for(int y = 0; y < hheight; ++y) {
1292  
            int yy = this.height - y - 1;
1293  
1294  
            for(int x = 0; x < this.width; ++x) {
1295  
                float tmp = this.pixels[y][x];
1296  
                this.pixels[y][x] = this.pixels[yy][x];
1297  
                this.pixels[yy][x] = tmp;
1298  
            }
1299  
        }
1300  
1301  
        return this;
1302  
    }
1303  
1304  
    public FImage overlayInplace(FImage img, FImage alpha, int x, int y) {
1305  
        int sx = Math.max(x, 0);
1306  
        int sy = Math.max(y, 0);
1307  
        int ex = Math.min(this.width, x + img.getWidth());
1308  
        int ey = Math.min(this.height, y + img.getHeight());
1309  
1310  
        for(int yc = sy; yc < ey; ++yc) {
1311  
            for(int xc = sx; xc < ex; ++xc) {
1312  
                float a = alpha.pixels[yc - sy][xc - sx];
1313  
                this.pixels[yc][xc] = a * img.pixels[yc - sy][xc - sx] + (1.0F - a) * this.pixels[yc][xc];
1314  
            }
1315  
        }
1316  
1317  
        return this;
1318  
    }
1319  
1320  
    public FImage overlayInplace(FImage image, int x, int y) {
1321  
        return this.overlayInplace(image, this.clone().fill(1.0F), x, y);
1322  
    }
1323  
1324  
    public static FImage randomImage(int width, int height) {
1325  
        FImage img = new FImage(width, height);
1326  
1327  
        for(int y = 0; y < height; ++y) {
1328  
            for(int x = 0; x < width; ++x) {
1329  
                img.pixels[y][x] = (float)Math.random();
1330  
            }
1331  
        }
1332  
1333  
        return img;
1334  
    }
1335  
1336  
    public FImage replace(Float target, Float replacement) {
1337  
        return this.replace(target, replacement);
1338  
    }
1339  
1340  
    public FImage replace(float target, float replacement) {
1341  
        for(int r = 0; r < this.height; ++r) {
1342  
            for(int c = 0; c < this.width; ++c) {
1343  
                if (this.pixels[r][c] == target) {
1344  
                    this.pixels[r][c] = replacement;
1345  
                }
1346  
            }
1347  
        }
1348  
1349  
        return this;
1350  
    }
1351  
1352  
    public FImage extractCentreSubPix(float cx, float cy, FImage out) {
1353  
        int width = out.width;
1354  
        int height = out.height;
1355  
1356  
        for(int y = 0; y < height; ++y) {
1357  
            for(int x = 0; x < width; ++x) {
1358  
                float ix = (float)((double)((float)x + cx) - (double)(width - 1) * 0.5D);
1359  
                float iy = (float)((double)((float)y + cy) - (double)(height - 1) * 0.5D);
1360  
                out.pixels[y][x] = this.getPixelInterpNative(ix, iy, 0.0F);
1361  
            }
1362  
        }
1363  
1364  
        return out;
1365  
    }
1366  
}
1367  
1368  
1369  
static abstract class AbstractMultiScaleObjectDetector<IMAGE extends Image<?, IMAGE>, DETECTED_OBJECT> implements MultiScaleObjectDetector<IMAGE, DETECTED_OBJECT> {
1370  
    protected Rectangle roi;
1371  
    protected int minSize = 0;
1372  
    protected int maxSize = 0;
1373  
1374  
    protected AbstractMultiScaleObjectDetector() {
1375  
    }
1376  
1377  
    protected AbstractMultiScaleObjectDetector(int minSize, int maxSize) {
1378  
        this.minSize = minSize;
1379  
        this.maxSize = maxSize;
1380  
    }
1381  
1382  
    public void setROI(Rectangle roi) {
1383  
        this.roi = roi;
1384  
    }
1385  
1386  
    public void setMinimumDetectionSize(int size) {
1387  
        this.minSize = size;
1388  
    }
1389  
1390  
    public void setMaximumDetectionSize(int size) {
1391  
        this.maxSize = size;
1392  
    }
1393  
1394  
    public int getMinimumDetectionSize() {
1395  
        return this.minSize;
1396  
    }
1397  
1398  
    public int getMaximumDetectionSize() {
1399  
        return this.maxSize;
1400  
    }
1401  
}
1402  
1403  
sclass Detector extends AbstractMultiScaleObjectDetector<FImage, Rectangle> {
1404  
  /**
1405  
   * Default step size to make when there is a hint of detection.
1406  
   */
1407  
  public static final int DEFAULT_SMALL_STEP = 1;
1408  
1409  
  /**
1410  
   * Default step size to make when there is definitely no detection.
1411  
   */
1412  
  public static final int DEFAULT_BIG_STEP = 2;
1413  
1414  
  /**
1415  
   * Default scale factor multiplier.
1416  
   */
1417  
  public static final float DEFAULT_SCALE_FACTOR = 1.1f;
1418  
1419  
  protected StageTreeClassifier cascade;
1420  
  protected float scaleFactor = 1.1f;
1421  
  protected int smallStep = 1;
1422  
  protected int bigStep = 2;
1423  
1424  
  /**
1425  
   * Construct the {@link Detector} with the given parameters.
1426  
   * 
1427  
   * @param cascade
1428  
   *            the cascade or tree of stages.
1429  
   * @param scaleFactor
1430  
   *            the amount to change between scales (multiplicative)
1431  
   * @param smallStep
1432  
   *            the amount to step when there is a hint of detection
1433  
   * @param bigStep
1434  
   *            the amount to step when there is definitely no detection
1435  
   */
1436  
  public Detector(StageTreeClassifier cascade, float scaleFactor, int smallStep, int bigStep) {
1437  
    super(Math.max(cascade.width, cascade.height), 0);
1438  
1439  
    this.cascade = cascade;
1440  
    this.scaleFactor = scaleFactor;
1441  
    this.smallStep = smallStep;
1442  
    this.bigStep = bigStep;
1443  
  }
1444  
1445  
  /**
1446  
   * Construct the {@link Detector} with the given tree of stages and scale
1447  
   * factor. The default step sizes are used.
1448  
   * 
1449  
   * @param cascade
1450  
   *            the cascade or tree of stages.
1451  
   * @param scaleFactor
1452  
   *            the amount to change between scales
1453  
   */
1454  
  public Detector(StageTreeClassifier cascade, float scaleFactor) {
1455  
    this(cascade, scaleFactor, DEFAULT_SMALL_STEP, DEFAULT_BIG_STEP);
1456  
  }
1457  
1458  
  /**
1459  
   * Construct the {@link Detector} with the given tree of stages, and the
1460  
   * default parameters for step sizes and scale factor.
1461  
   * 
1462  
   * @param cascade
1463  
   *            the cascade or tree of stages.
1464  
   */
1465  
  public Detector(StageTreeClassifier cascade) {
1466  
    this(cascade, DEFAULT_SCALE_FACTOR, DEFAULT_SMALL_STEP, DEFAULT_BIG_STEP);
1467  
  }
1468  
1469  
  /**
1470  
   * Perform detection at a single scale. Subclasses may override this to
1471  
   * customise the spatial search. The given starting and stopping coordinates
1472  
   * take into account any region of interest set on this detector.
1473  
   * 
1474  
   * @param sat
1475  
   *            the summed area table(s)
1476  
   * @param startX
1477  
   *            the starting x-ordinate
1478  
   * @param stopX
1479  
   *            the stopping x-ordinate
1480  
   * @param startY
1481  
   *            the starting y-ordinate
1482  
   * @param stopY
1483  
   *            the stopping y-ordinate
1484  
   * @param ystep
1485  
   *            the amount to step
1486  
   * @param windowWidth
1487  
   *            the window width at the current scale
1488  
   * @param windowHeight
1489  
   *            the window height at the current scale
1490  
   * @param results
1491  
   *            the list to store detection results in
1492  
   */
1493  
  protected void detectAtScale(final SummedSqTiltAreaTable sat, final int startX, final int stopX, final int startY,
1494  
      final int stopY, final float ystep, final int windowWidth, final int windowHeight,
1495  
      final List<Rectangle> results)
1496  
  {
1497  
    for (int iy = startY; iy < stopY; iy++) {
1498  
      final int y = Math.round(iy * ystep);
1499  
1500  
      for (int ix = startX, xstep = 0; ix < stopX; ix += xstep) {
1501  
        final int x = Math.round(ix * ystep);
1502  
1503  
        final int result = cascade.classify(sat, x, y);
1504  
1505  
        if (result > 0) {
1506  
          results.add(new Rectangle(x, y, windowWidth, windowHeight));
1507  
        }
1508  
1509  
        // if there is no detection, then increase the step size
1510  
        xstep = (result > 0 ? smallStep : bigStep);
1511  
1512  
        // TODO: think about what to do if there isn't a detection, but
1513  
        // we're very close to having one based on the ratio of stages
1514  
        // passes to total stages.
1515  
      }
1516  
    }
1517  
  }
1518  
1519  
  @Override
1520  
  public List<Rectangle> detect(FImage image) {
1521  
    final List<Rectangle> results = new ArrayList<Rectangle>();
1522  
1523  
    final int imageWidth = image.getWidth();
1524  
    final int imageHeight = image.getHeight();
1525  
1526  
    final SummedSqTiltAreaTable sat = new SummedSqTiltAreaTable(image, cascade.hasTiltedFeatures);
1527  
1528  
    // compute the number of scales to test and the starting factor
1529  
    int nFactors = 0;
1530  
    int startFactor = 0;
1531  
    for (float factor = 1; factor * cascade.width < imageWidth - 10 &&
1532  
        factor * cascade.height < imageHeight - 10; factor *= scaleFactor)
1533  
    {
1534  
      final float width = factor * cascade.width;
1535  
      final float height = factor * cascade.height;
1536  
1537  
      if (width < minSize || height < minSize) {
1538  
        startFactor++;
1539  
      }
1540  
1541  
      if (maxSize > 0 && (width > maxSize || height > maxSize)) {
1542  
        break;
1543  
      }
1544  
1545  
      nFactors++;
1546  
    }
1547  
1548  
    // run the detection at each scale
1549  
    float factor = (float) Math.pow(scaleFactor, startFactor);
1550  
    for (int scaleStep = startFactor; scaleStep < nFactors; factor *= scaleFactor, scaleStep++) {
1551  
      final float ystep = Math.max(2, factor);
1552  
1553  
      final int windowWidth = (int) (factor * cascade.width);
1554  
      final int windowHeight = (int) (factor * cascade.height);
1555  
1556  
      // determine the spatial range, taking into account any ROI.
1557  
      final int startX = (int) (roi == null ? 0 : Math.max(0, roi.x));
1558  
      final int startY = (int) (roi == null ? 0 : Math.max(0, roi.y));
1559  
      final int stopX = Math.round(
1560  
          (((roi == null ? imageWidth : Math.min(imageWidth, roi.x + roi.width)) - windowWidth)) / ystep);
1561  
      final int stopY = Math.round(
1562  
          (((roi == null ? imageHeight : Math.min(imageHeight, roi.y + roi.height)) - windowHeight)) / ystep);
1563  
1564  
      // prepare the cascade for this scale
1565  
      cascade.setScale(factor);
1566  
1567  
      detectAtScale(sat, startX, stopX, startY, stopY, ystep, windowWidth, windowHeight, results);
1568  
    }
1569  
1570  
    return results;
1571  
  }
1572  
1573  
  /**
1574  
   * Get the step size the detector will make if there is any hint of a
1575  
   * detection. This should be smaller than {@link #bigStep()}.
1576  
   * 
1577  
   * @return the amount to step on any hint of detection.
1578  
   */
1579  
  public int smallStep() {
1580  
    return smallStep;
1581  
  }
1582  
1583  
  /**
1584  
   * Get the step size the detector will make if there is definitely no
1585  
   * detection. This should be bigger than {@link #smallStep()}.
1586  
   * 
1587  
   * @return the amount to step when there is definitely no detection.
1588  
   */
1589  
  public int bigStep() {
1590  
    return bigStep;
1591  
  }
1592  
1593  
  /**
1594  
   * Set the step size the detector will make if there is any hint of a
1595  
   * detection. This should be smaller than {@link #bigStep()}.
1596  
   * 
1597  
   * @param smallStep
1598  
   *            The amount to step on any hint of detection.
1599  
   */
1600  
  public void setSmallStep(int smallStep) {
1601  
    this.smallStep = smallStep;
1602  
  }
1603  
1604  
  /**
1605  
   * Set the step size the detector will make if there is definitely no
1606  
   * detection. This should be bigger than {@link #smallStep()}.
1607  
   * 
1608  
   * @param bigStep
1609  
   *            The amount to step when there is definitely no detection.
1610  
   */
1611  
  public void bigStep(int bigStep) {
1612  
    this.bigStep = bigStep;
1613  
  }
1614  
1615  
  /**
1616  
   * Get the scale factor (the amount to change between scales
1617  
   * (multiplicative)).
1618  
   * 
1619  
   * @return the scaleFactor
1620  
   */
1621  
  public float getScaleFactor() {
1622  
    return scaleFactor;
1623  
  }
1624  
1625  
  /**
1626  
   * Set the scale factor (the amount to change between scales
1627  
   * (multiplicative)).
1628  
   * 
1629  
   * @param scaleFactor
1630  
   *            the scale factor to set
1631  
   */
1632  
  public void setScaleFactor(float scaleFactor) {
1633  
    this.scaleFactor = scaleFactor;
1634  
  }
1635  
1636  
  /**
1637  
   * Get the classifier tree or cascade used by this detector.
1638  
   * 
1639  
   * @return the classifier tree or cascade.
1640  
   */
1641  
  public StageTreeClassifier getClassifier() {
1642  
    return cascade;
1643  
  }
1644  
}
1645  
1646  
sclass HaarCascadeDetector {
1647  
  public enum BuiltInCascade {
1648  
    /**
1649  
     * A eye detector
1650  
     */
1651  
    eye("haarcascade_eye.xml"),
1652  
    /**
1653  
     * A eye with glasses detector
1654  
     */
1655  
    eye_tree_eyeglasses("haarcascade_eye_tree_eyeglasses.xml"),
1656  
    /**
1657  
     * A frontal face detector
1658  
     */
1659  
    frontalface_alt("haarcascade_frontalface_alt.xml"),
1660  
    /**
1661  
     * A frontal face detector
1662  
     */
1663  
    frontalface_alt2("haarcascade_frontalface_alt2.xml"),
1664  
    /**
1665  
     * A frontal face detector
1666  
     */
1667  
    frontalface_alt_tree("haarcascade_frontalface_alt_tree.xml"),
1668  
    /**
1669  
     * A frontal face detector
1670  
     */
1671  
    frontalface_default("haarcascade_frontalface_default.xml"),
1672  
    /**
1673  
     * A fullbody detector
1674  
     */
1675  
    fullbody("haarcascade_fullbody.xml"),
1676  
    /**
1677  
     * A left eye detector
1678  
     */
1679  
    lefteye_2splits("haarcascade_lefteye_2splits.xml"),
1680  
    /**
1681  
     * A lower body detector
1682  
     */
1683  
    lowerbody("haarcascade_lowerbody.xml"),
1684  
    /**
1685  
     * A detector for a pair of eyes
1686  
     */
1687  
    mcs_eyepair_big("haarcascade_mcs_eyepair_big.xml"),
1688  
    /**
1689  
     * A detector for a pair of eyes
1690  
     */
1691  
    mcs_eyepair_small("haarcascade_mcs_eyepair_small.xml"),
1692  
    /**
1693  
     * A left eye detector
1694  
     */
1695  
    mcs_lefteye("haarcascade_mcs_lefteye.xml"),
1696  
    /**
1697  
     * A mouth detector
1698  
     */
1699  
    mcs_mouth("haarcascade_mcs_mouth.xml"),
1700  
    /**
1701  
     * A nose detector
1702  
     */
1703  
    mcs_nose("haarcascade_mcs_nose.xml"),
1704  
    /**
1705  
     * A right eye detector
1706  
     */
1707  
    mcs_righteye("haarcascade_mcs_righteye.xml"),
1708  
    /**
1709  
     * An upper body detector
1710  
     */
1711  
    mcs_upperbody("haarcascade_mcs_upperbody.xml"),
1712  
    /**
1713  
     * A profile face detector
1714  
     */
1715  
    profileface("haarcascade_profileface.xml"),
1716  
    /**
1717  
     * A right eye detector
1718  
     */
1719  
    righteye_2splits("haarcascade_righteye_2splits.xml"),
1720  
    /**
1721  
     * An upper body detector
1722  
     */
1723  
    upperbody("haarcascade_upperbody.xml");
1724  
1725  
    private String classFile;
1726  
1727  
    private BuiltInCascade(String classFile) {
1728  
      this.classFile = classFile;
1729  
    }
1730  
1731  
    /**
1732  
     * @return The name of the cascade resource
1733  
     */
1734  
    public String classFile() {
1735  
      return classFile;
1736  
    }
1737  
1738  
    /**
1739  
     * Create a new detector with the this cascade.
1740  
     * 
1741  
     * @return A new {@link HaarCascadeDetector}
1742  
     */
1743  
    public HaarCascadeDetector load() {
1744  
      try {
1745  
        return new HaarCascadeDetector(classFile);
1746  
      } catch (final Exception e) {
1747  
        throw new RuntimeException(e);
1748  
      }
1749  
    }
1750  
  }
1751  
1752  
  protected Detector detector;
1753  
  protected DetectionFilter<Rectangle, ObjectIntPair<Rectangle>> groupingFilter;
1754  
  protected boolean histogramEqualize = false;
1755  
1756  
  /**
1757  
   * Construct with the given cascade resource. See
1758  
   * {@link #setCascade(String)} to understand how the cascade is loaded.
1759  
   * 
1760  
   * @param cas
1761  
   *            The cascade resource.
1762  
   * @see #setCascade(String)
1763  
   */
1764  
  public HaarCascadeDetector(String cas) {
1765  
    try {
1766  
      setCascade(cas);
1767  
    } catch (final Exception e) {
1768  
      throw new RuntimeException(e);
1769  
    }
1770  
    groupingFilter = new OpenCVGrouping();
1771  
  }
1772  
1773  
  /**
1774  
   * Construct with the {@link BuiltInCascade#frontalface_default} cascade.
1775  
   */
1776  
  public HaarCascadeDetector() {
1777  
    this(BuiltInCascade.frontalface_default.classFile());
1778  
  }
1779  
1780  
  /**
1781  
   * Construct with the {@link BuiltInCascade#frontalface_default} cascade and
1782  
   * the given minimum search window size.
1783  
   * 
1784  
   * @param minSize
1785  
   *            minimum search window size
1786  
   */
1787  
  public HaarCascadeDetector(int minSize) {
1788  
    this();
1789  
    this.detector.setMinimumDetectionSize(minSize);
1790  
  }
1791  
1792  
  /**
1793  
   * Construct with the given cascade resource and the given minimum search
1794  
   * window size. See {@link #setCascade(String)} to understand how the
1795  
   * cascade is loaded.
1796  
   * 
1797  
   * @param cas
1798  
   *            The cascade resource.
1799  
   * @param minSize
1800  
   *            minimum search window size.
1801  
   * 
1802  
   * @see #setCascade(String)
1803  
   */
1804  
  public HaarCascadeDetector(String cas, int minSize) {
1805  
    this(cas);
1806  
    this.detector.setMinimumDetectionSize(minSize);
1807  
  }
1808  
1809  
  /**
1810  
   * @return The minimum detection window size
1811  
   */
1812  
  public int getMinSize() {
1813  
    return this.detector.getMinimumDetectionSize();
1814  
  }
1815  
1816  
  /**
1817  
   * Set the minimum detection window size
1818  
   * 
1819  
   * @param size
1820  
   *            the window size
1821  
   */
1822  
  public void setMinSize(int size) {
1823  
    this.detector.setMinimumDetectionSize(size);
1824  
  }
1825  
1826  
  /**
1827  
   * @return The maximum detection window size
1828  
   */
1829  
  public int getMaxSize() {
1830  
    return this.detector.getMaximumDetectionSize();
1831  
  }
1832  
1833  
  /**
1834  
   * Set the maximum detection window size
1835  
   * 
1836  
   * @param size
1837  
   *            the window size
1838  
   */
1839  
  public void setMaxSize(int size) {
1840  
    this.detector.setMaximumDetectionSize(size);
1841  
  }
1842  
1843  
  /**
1844  
   * @return The grouping filter
1845  
   */
1846  
  public DetectionFilter<Rectangle, ObjectIntPair<Rectangle>> getGroupingFilter() {
1847  
    return groupingFilter;
1848  
  }
1849  
1850  
  /**
1851  
   * Set the filter for merging detections
1852  
   * 
1853  
   * @param grouping
1854  
   */
1855  
  public void setGroupingFilter(DetectionFilter<Rectangle, ObjectIntPair<Rectangle>> grouping) {
1856  
    this.groupingFilter = grouping;
1857  
  }
1858  
1859  
  @Override
1860  
  public List<DetectedFace> detectFaces(FImage image) {
1861  
    if (histogramEqualize)
1862  
      image.processInplace(new EqualisationProcessor());
1863  
1864  
    final List<Rectangle> rects = detector.detect(image);
1865  
    final List<ObjectIntPair<Rectangle>> filteredRects = groupingFilter.apply(rects);
1866  
1867  
    final List<DetectedFace> results = new ArrayList<DetectedFace>();
1868  
    for (final ObjectIntPair<Rectangle> r : filteredRects) {
1869  
      results.add(new DetectedFace(r.first, image.extractROI(r.first), r.second));
1870  
    }
1871  
1872  
    return results;
1873  
  }
1874  
1875  
  /**
1876  
   * @see Detector#getScaleFactor()
1877  
   * @return The detector scale factor
1878  
   */
1879  
  public double getScaleFactor() {
1880  
    return detector.getScaleFactor();
1881  
  }
1882  
1883  
  /**
1884  
   * Set the cascade classifier for this detector. The cascade file is first
1885  
   * searched for as a java resource, and if it is not found then a it is
1886  
   * assumed to be a file on the filesystem.
1887  
   * 
1888  
   * @param cascadeResource
1889  
   *            The cascade to load.
1890  
   * @throws Exception
1891  
   *             if there is a problem loading the cascade.
1892  
   */
1893  
  public void setCascade(String cascadeResource) throws Exception {
1894  
    // try to load serialized cascade from external XML file
1895  
    InputStream in = null;
1896  
    try {
1897  
      in = OCVHaarLoader.class.getResourceAsStream(cascadeResource);
1898  
1899  
      if (in == null) {
1900  
        in = new FileInputStream(new File(cascadeResource));
1901  
      }
1902  
      final StageTreeClassifier cascade = OCVHaarLoader.read(in);
1903  
1904  
      if (this.detector == null)
1905  
        this.detector = new Detector(cascade);
1906  
      else
1907  
        this.detector = new Detector(cascade, this.detector.getScaleFactor());
1908  
    } catch (final Exception e) {
1909  
      throw e;
1910  
    } finally {
1911  
      if (in != null) {
1912  
        try {
1913  
          in.close();
1914  
        } catch (final IOException e) {
1915  
        }
1916  
      }
1917  
    }
1918  
  }
1919  
1920  
  /**
1921  
   * Set the detector scale factor
1922  
   * 
1923  
   * @see Detector#setScaleFactor(float)
1924  
   * 
1925  
   * @param scaleFactor
1926  
   *            the scale factor
1927  
   */
1928  
  public void setScale(float scaleFactor) {
1929  
    this.detector.setScaleFactor(scaleFactor);
1930  
  }
1931  
1932  
  /**
1933  
   * Serialize the detector using java serialization to the given stream
1934  
   * 
1935  
   * @param os
1936  
   *            the stream
1937  
   * @throws IOException
1938  
   */
1939  
  public void save(OutputStream os) throws IOException {
1940  
    final ObjectOutputStream oos = new ObjectOutputStream(os);
1941  
    oos.writeObject(this);
1942  
  }
1943  
1944  
  /**
1945  
   * Deserialize the detector from a stream. The detector must have been
1946  
   * written with a previous invokation of {@link #save(OutputStream)}.
1947  
   * 
1948  
   * @param is
1949  
   * @return {@link HaarCascadeDetector} read from stream.
1950  
   * @throws IOException
1951  
   * @throws ClassNotFoundException
1952  
   */
1953  
  public static HaarCascadeDetector read(InputStream is) throws IOException, ClassNotFoundException {
1954  
    final ObjectInputStream ois = new ObjectInputStream(is);
1955  
    return (HaarCascadeDetector) ois.readObject();
1956  
  }
1957  
1958  
  @Override
1959  
  public int hashCode() {
1960  
    int hashCode = HashCodeUtil.SEED;
1961  
1962  
    hashCode = HashCodeUtil.hash(hashCode, this.detector.getMinimumDetectionSize());
1963  
    hashCode = HashCodeUtil.hash(hashCode, this.detector.getScaleFactor());
1964  
    hashCode = HashCodeUtil.hash(hashCode, this.detector.getClassifier().getName());
1965  
    hashCode = HashCodeUtil.hash(hashCode, this.groupingFilter);
1966  
    hashCode = HashCodeUtil.hash(hashCode, this.histogramEqualize);
1967  
1968  
    return hashCode;
1969  
  }
1970  
1971  
  @Override
1972  
  public void readBinary(DataInput in) throws IOException {
1973  
    this.detector = IOUtils.read(in);
1974  
    this.groupingFilter = IOUtils.read(in);
1975  
1976  
    histogramEqualize = in.readBoolean();
1977  
  }
1978  
1979  
  @Override
1980  
  public byte[] binaryHeader() {
1981  
    return "HAAR".getBytes();
1982  
  }
1983  
1984  
  @Override
1985  
  public void writeBinary(DataOutput out) throws IOException {
1986  
    IOUtils.write(detector, out);
1987  
    IOUtils.write(groupingFilter, out);
1988  
1989  
    out.writeBoolean(histogramEqualize);
1990  
  }
1991  
1992  
  @Override
1993  
  public String toString() {
1994  
    return "HaarCascadeDetector[cascade=" + detector.getClassifier().getName() + "]";
1995  
  }
1996  
1997  
  /**
1998  
   * @return the underlying Haar cascade.
1999  
   */
2000  
  public StageTreeClassifier getCascade() {
2001  
    return detector.getClassifier();
2002  
  }
2003  
2004  
  /**
2005  
   * @return the underlying {@link Detector}.
2006  
   */
2007  
  public Detector getDetector() {
2008  
    return detector;
2009  
  }
2010  
}
2011  
2012  
sclass HaarCascade_FaceDetector extends F1<BufferedImage, L<RectAndConfidence>> {
2013  
  new HaarCascadeDetector detector;
2014  
  
2015  
  public L<RectAndConfidence> get(BufferedImage img) {
2016  
    if (img == null) null;
2017  
    ret map(detector.detectFaces(ImageUtilities.createFImage(img)),
2018  
      func(DetectedFace f) -> RectAndConfidence {
2019  
        RectAndConfidence(openImajRectangleToRect(f.getBounds()), f.getConfidence())
2020  
      });
2021  
  }
2022  
}
2023  
2024  
module HCFD > DynSingleFunctionWithPrintLog {
2025  
  void doIt {
2026  
    pnl(new HaarCascade_FaceDetector().get(loadImage2(#1101409)));
2027  
  }
2028  
}

Author comment

Began life as a copy of #1019063

download  show line numbers  debug dex  old transpilations   

Travelled to 12 computer(s): bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, irmadwmeruwu, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1019064
Snippet name: Test HaarCascade_FaceDetector (copied in, dev.)
Eternal ID of this version: #1019064/9
Text MD5: 75ac6a20a2457a0401b9934b021dc439
Transpilation MD5: bb85e6ae0702edddfe11334bd29eed89
Author: stefan
Category: javax / stefan's os
Type: JavaX source code (Dynamic Module)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-09-08 04:39:16
Source code size: 57965 bytes / 2028 lines
Pitched / IR pitched: No / No
Views / Downloads: 289 / 352
Version history: 8 change(s)
Referenced in: [show references]