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).

!7

!include once #1010056 // OpenIMAJ

import org.openimaj.image.Image;
import org.openimaj.image.processor.*;
import static org.openimaj.image.processor.SinglebandImageProcessor.Processable;

replace Rectangle with RectangleO.

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> {
    private static final long serialVersionUID = 1L;
    public int height;
    public int width;

    public SingleBandImage() {
    }

    public int getHeight() {
        return this.height;
    }

    public int getWidth() {
        return this.width;
    }

    public I process(KernelProcessor<Q, I> p) {
        return this.process(p, false);
    }

    public I process(KernelProcessor<Q, I> p, boolean pad) {
        I newImage = (I) this.newInstance(this.width, this.height);
        I tmp = (I) this.newInstance(p.getKernelWidth(), p.getKernelHeight());
        int hh = p.getKernelHeight() / 2;
        int hw = p.getKernelWidth() / 2;
        int y;
        int x;
        if (!pad) {
            for(y = hh; y < this.getHeight() - (p.getKernelHeight() - hh); ++y) {
                for(x = hw; x < this.getWidth() - (p.getKernelWidth() - hw); ++x) {
                    newImage.setPixel(x, y, p.processKernel(this.extractROI(x, y, tmp)));
                }
            }
        } else {
            for(y = 0; y < this.getHeight(); ++y) {
                for(x = 0; x < this.getWidth(); ++x) {
                    newImage.setPixel(x, y, p.processKernel(this.extractROI(x, y, tmp)));
                }
            }
        }

        return newImage;
    }

    public I process(SinglebandKernelProcessor<Q, I> p) {
        return this.process(p, false);
    }

    public I process(SinglebandKernelProcessor<Q, I> p, boolean pad) {
        I newImage = (SingleBandImage)this.newInstance(this.width, this.height);
        I tmp = (SingleBandImage)this.newInstance(p.getKernelWidth(), p.getKernelHeight());
        int hh = p.getKernelHeight() / 2;
        int hw = p.getKernelWidth() / 2;
        int y;
        int x;
        if (!pad) {
            for(y = hh; y < this.getHeight() - (p.getKernelHeight() - hh); ++y) {
                for(x = hw; x < this.getWidth() - (p.getKernelWidth() - hw); ++x) {
                    newImage.setPixel(x, y, p.processKernel(this.extractROI(x, y, tmp)));
                }
            }
        } else {
            for(y = 0; y < this.getHeight(); ++y) {
                for(x = 0; x < this.getWidth(); ++x) {
                    newImage.setPixel(x, y, p.processKernel(this.extractROI(x, y, tmp)));
                }
            }
        }

        return newImage;
    }

    public I processInplace(SinglebandKernelProcessor<Q, I> p) {
        return this.processInplace(p, false);
    }

    public I processInplace(SinglebandKernelProcessor<Q, I> p, boolean pad) {
        I newImage = this.process(p, pad);
        this.internalAssign(newImage);
        return this;
    }

    public I process(SinglebandImageProcessor<Q, I> p) {
        I newImage = this.clone();
        newImage.processInplace(p);
        return newImage;
    }

    public I processInplace(SinglebandImageProcessor<Q, I> p) {
        p.processImage(this);
        return this;
    }

    public I fill(Q colour) {
        for(int y = 0; y < this.getHeight(); ++y) {
            for(int x = 0; x < this.getWidth(); ++x) {
                this.setPixel(x, y, colour);
            }
        }

        return this;
    }

    public abstract I clone();

    public boolean equals(Object obj) {
        I that = (SingleBandImage)obj;

        for(int y = 0; y < this.getHeight(); ++y) {
            for(int x = 0; x < this.getWidth(); ++x) {
                boolean fail = !((Comparable)this.getPixel(x, y)).equals(that.getPixel(x, y));
                if (fail) {
                    return false;
                }
            }
        }

        return true;
    }
}


sclass FImage extends SingleBandImage<Float, FImage> {
    private static final long serialVersionUID = 1L;
    protected static Logger logger = Logger.getLogger(FImage.class);
    protected static final float DEFAULT_GAUSS_TRUNCATE = 4.0F;
    public float[][] pixels;

    public FImage(float[] array, int width, int height) {
        assert array.length == width * height;

        this.pixels = new float[height][width];
        this.height = height;
        this.width = width;

        for(int y = 0; y < height; ++y) {
            for(int x = 0; x < width; ++x) {
                this.pixels[y][x] = array[y * width + x];
            }
        }

    }

    public FImage(double[] array, int width, int height) {
        assert array.length == width * height;

        this.pixels = new float[height][width];
        this.height = height;
        this.width = width;

        for(int y = 0; y < height; ++y) {
            for(int x = 0; x < width; ++x) {
                this.pixels[y][x] = (float)array[y * width + x];
            }
        }

    }

    public FImage(double[] array, int width, int height, int offset) {
        assert array.length == width * height;

        this.pixels = new float[height][width];
        this.height = height;
        this.width = width;

        for(int y = 0; y < height; ++y) {
            for(int x = 0; x < width; ++x) {
                this.pixels[y][x] = (float)array[offset + y * width + x];
            }
        }

    }

    public FImage(float[][] array) {
        this.pixels = array;
        this.height = array.length;
        this.width = array[0].length;
    }

    public FImage(int width, int height) {
        this.pixels = new float[height][width];
        this.height = height;
        this.width = width;
    }

    public FImage(int[] data, int width, int height) {
        this.internalAssign(data, width, height);
    }

    public FImage(int[] data, int width, int height, ARGBPlane plane) {
        this.width = width;
        this.height = height;
        this.pixels = new float[height][width];

        for(int y = 0; y < height; ++y) {
            for(int x = 0; x < width; ++x) {
                int rgb = data[x + y * width];
                int colour = 0;
                switch(plane) {
                case RED:
                    colour = rgb >> 16 & 255;
                    break;
                case GREEN:
                    colour = rgb >> 8 & 255;
                    break;
                case BLUE:
                    colour = rgb & 255;
                }

                this.pixels[y][x] = (float)colour;
            }
        }

    }

    public FImage abs() {
        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                this.pixels[r][c] = Math.abs(this.pixels[r][c]);
            }
        }

        return this;
    }

    public FImage add(FImage im) {
        if (!ImageUtilities.checkSameSize(new Image[]{this, im})) {
            throw new AssertionError("images must be the same size");
        } else {
            FImage newImage = new FImage(im.width, im.height);

            for(int r = 0; r < im.height; ++r) {
                for(int c = 0; c < im.width; ++c) {
                    newImage.pixels[r][c] = this.pixels[r][c] + im.pixels[r][c];
                }
            }

            return newImage;
        }
    }

    public FImage add(Float num) {
        FImage newImage = new FImage(this.width, this.height);
        float fnum = num;

        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                newImage.pixels[r][c] = this.pixels[r][c] + fnum;
            }
        }

        return newImage;
    }

    public FImage add(Image<?, ?> im) {
        if (im instanceof FImage) {
            return this.add((FImage)im);
        } else {
            throw new UnsupportedOperationException("Unsupported Type");
        }
    }

    public FImage addInplace(FImage im) {
        if (!ImageUtilities.checkSameSize(new Image[]{this, im})) {
            throw new AssertionError("images must be the same size");
        } else {
            for(int r = 0; r < im.height; ++r) {
                for(int c = 0; c < im.width; ++c) {
                    this.pixels[r][c] += im.pixels[r][c];
                }
            }

            return this;
        }
    }

    public FImage addInplace(Float num) {
        float fnum = num;

        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                this.pixels[r][c] += fnum;
            }
        }

        return this;
    }

    public FImage addInplace(Image<?, ?> im) {
        if (im instanceof FImage) {
            return this.addInplace((FImage)im);
        } else {
            throw new UnsupportedOperationException("Unsupported Type");
        }
    }

    public FImage clip(Float min, Float max) {
        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                if (this.pixels[r][c] < min) {
                    this.pixels[r][c] = 0.0F;
                }

                if (this.pixels[r][c] > max) {
                    this.pixels[r][c] = 1.0F;
                }
            }
        }

        return this;
    }

    public FImage clipMax(Float thresh) {
        float fthresh = thresh;

        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                if (this.pixels[r][c] > fthresh) {
                    this.pixels[r][c] = 1.0F;
                }
            }
        }

        return this;
    }

    public FImage clipMin(Float thresh) {
        float fthresh = thresh;

        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                if (this.pixels[r][c] < fthresh) {
                    this.pixels[r][c] = 0.0F;
                }
            }
        }

        return this;
    }

    public FImage clone() {
        FImage cpy = new FImage(this.width, this.height);

        for(int r = 0; r < this.height; ++r) {
            System.arraycopy(this.pixels[r], 0, cpy.pixels[r], 0, this.width);
        }

        return cpy;
    }

    public FImageRenderer createRenderer() {
        return new FImageRenderer(this);
    }

    public FImageRenderer createRenderer(RenderHints options) {
        return new FImageRenderer(this, options);
    }

    public FImage divide(FImage im) {
        if (!ImageUtilities.checkSameSize(new Image[]{this, im})) {
            throw new AssertionError("images must be the same size");
        } else {
            FImage newImage = new FImage(im.width, im.height);

            for(int r = 0; r < im.height; ++r) {
                for(int c = 0; c < im.width; ++c) {
                    newImage.pixels[r][c] = this.pixels[r][c] / im.pixels[r][c];
                }
            }

            return newImage;
        }
    }

    public FImage divideInplace(FImage im) {
        if (!ImageUtilities.checkSameSize(new Image[]{this, im})) {
            throw new AssertionError("images must be the same size");
        } else {
            for(int y = 0; y < this.height; ++y) {
                for(int x = 0; x < this.width; ++x) {
                    this.pixels[y][x] /= im.pixels[y][x];
                }
            }

            return this;
        }
    }

    public FImage divideInplace(Float val) {
        float fval = val;

        for(int y = 0; y < this.height; ++y) {
            for(int x = 0; x < this.width; ++x) {
                this.pixels[y][x] /= fval;
            }
        }

        return this;
    }

    public FImage divideInplace(float fval) {
        for(int y = 0; y < this.height; ++y) {
            for(int x = 0; x < this.width; ++x) {
                this.pixels[y][x] /= fval;
            }
        }

        return this;
    }

    public FImage divideInplace(Image<?, ?> im) {
        if (im instanceof FImage) {
            return this.divideInplace((FImage)im);
        } else {
            throw new UnsupportedOperationException("Unsupported Type");
        }
    }

    public FImage extractROI(int x, int y, FImage out) {
        int r = y;

        for(int rr = 0; rr < out.height; ++rr) {
            int c = x;

            for(int cc = 0; cc < out.width; ++cc) {
                if (r >= 0 && r < this.height && c >= 0 && c < this.width) {
                    out.pixels[rr][cc] = this.pixels[r][c];
                } else {
                    out.pixels[rr][cc] = 0.0F;
                }

                ++c;
            }

            ++r;
        }

        return out;
    }

    public FImage extractROI(int x, int y, int w, int h) {
        FImage out = new FImage(w, h);
        int r = y;

        for(int rr = 0; rr < h; ++rr) {
            int c = x;

            for(int cc = 0; cc < w; ++cc) {
                if (r >= 0 && r < this.height && c >= 0 && c < this.width) {
                    out.pixels[rr][cc] = this.pixels[r][c];
                } else {
                    out.pixels[rr][cc] = 0.0F;
                }

                ++c;
            }

            ++r;
        }

        return out;
    }

    public FImage fill(Float colour) {
        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                this.pixels[r][c] = colour;
            }
        }

        return this;
    }

    public FImage fill(float colour) {
        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                this.pixels[r][c] = colour;
            }
        }

        return this;
    }

    public Rectangle getContentArea() {
        int minc = this.width;
        int maxc = 0;
        int minr = this.height;
        int maxr = 0;

        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                if (this.pixels[r][c] > 0.0F) {
                    if (c < minc) {
                        minc = c;
                    }

                    if (c > maxc) {
                        maxc = c;
                    }

                    if (r < minr) {
                        minr = r;
                    }

                    if (r > maxr) {
                        maxr = r;
                    }
                }
            }
        }

        return new Rectangle((float)minc, (float)minr, (float)(maxc - minc + 1), (float)(maxr - minr + 1));
    }

    public double[] getDoublePixelVector() {
        double[] f = new double[this.height * this.width];

        for(int y = 0; y < this.height; ++y) {
            for(int x = 0; x < this.width; ++x) {
                f[x + y * this.width] = (double)this.pixels[y][x];
            }
        }

        return f;
    }

    public FImage getField(Field f) {
        FImage img = new FImage(this.width, this.height / 2);
        int init = f.equals(Field.ODD) ? 1 : 0;
        int r = init;

        for(int r2 = 0; r < this.height && r2 < this.height / 2; ++r2) {
            for(int c = 0; c < this.width; ++c) {
                img.pixels[r2][c] = this.pixels[r][c];
            }

            r += 2;
        }

        return img;
    }

    public FImage getFieldCopy(Field f) {
        FImage img = new FImage(this.width, this.height);

        for(int r = 0; r < this.height; r += 2) {
            for(int c = 0; c < this.width; ++c) {
                if (f.equals(Field.EVEN)) {
                    img.pixels[r][c] = this.pixels[r][c];
                    img.pixels[r + 1][c] = this.pixels[r][c];
                } else {
                    img.pixels[r][c] = this.pixels[r + 1][c];
                    img.pixels[r + 1][c] = this.pixels[r + 1][c];
                }
            }
        }

        return img;
    }

    public FImage getFieldInterpolate(Field f) {
        FImage img = new FImage(this.width, this.height);

        for(int r = 0; r < this.height; r += 2) {
            for(int c = 0; c < this.width; ++c) {
                if (f.equals(Field.EVEN)) {
                    img.pixels[r][c] = this.pixels[r][c];
                    if (r + 2 == this.height) {
                        img.pixels[r + 1][c] = this.pixels[r][c];
                    } else {
                        img.pixels[r + 1][c] = 0.5F * (this.pixels[r][c] + this.pixels[r + 2][c]);
                    }
                } else {
                    img.pixels[r + 1][c] = this.pixels[r + 1][c];
                    if (r == 0) {
                        img.pixels[r][c] = this.pixels[r + 1][c];
                    } else {
                        img.pixels[r][c] = 0.5F * (this.pixels[r - 1][c] + this.pixels[r + 1][c]);
                    }
                }
            }
        }

        return img;
    }

    public float[] getFloatPixelVector() {
        float[] f = new float[this.height * this.width];

        for(int y = 0; y < this.height; ++y) {
            for(int x = 0; x < this.width; ++x) {
                f[x + y * this.width] = this.pixels[y][x];
            }
        }

        return f;
    }

    public Float getPixel(int x, int y) {
        return this.pixels[y][x];
    }

    public Comparator<? super Float> getPixelComparator() {
        return new Comparator<Float>() {
            public int compare(Float o1, Float o2) {
                return o1.compareTo(o2);
            }
        };
    }

    public Float getPixelInterp(double x, double y) {
        int x0 = (int)Math.floor(x);
        int x1 = x0 + 1;
        int y0 = (int)Math.floor(y);
        int y1 = y0 + 1;
        if (x0 < 0) {
            x0 = 0;
        }

        if (x0 >= this.width) {
            x0 = this.width - 1;
        }

        if (y0 < 0) {
            y0 = 0;
        }

        if (y0 >= this.height) {
            y0 = this.height - 1;
        }

        if (x1 < 0) {
            x1 = 0;
        }

        if (x1 >= this.width) {
            x1 = this.width - 1;
        }

        if (y1 < 0) {
            y1 = 0;
        }

        if (y1 >= this.height) {
            y1 = this.height - 1;
        }

        float f00 = this.pixels[y0][x0];
        float f01 = this.pixels[y1][x0];
        float f10 = this.pixels[y0][x1];
        float f11 = this.pixels[y1][x1];
        float dx = (float)(x - (double)x0);
        float dy = (float)(y - (double)y0);
        if (dx < 0.0F) {
            ++dx;
        }

        if (dy < 0.0F) {
            ++dy;
        }

        return Interpolation.bilerp(dx, dy, f00, f01, f10, f11);
    }

    public Float getPixelInterp(double x, double y, Float background) {
        int x0 = (int)Math.floor(x);
        int x1 = x0 + 1;
        int y0 = (int)Math.floor(y);
        int y1 = y0 + 1;
        boolean ty1 = true;
        boolean tx1 = true;
        boolean ty0 = true;
        boolean tx0 = true;
        if (x0 < 0) {
            tx0 = false;
        }

        if (x0 >= this.width) {
            tx0 = false;
        }

        if (y0 < 0) {
            ty0 = false;
        }

        if (y0 >= this.height) {
            ty0 = false;
        }

        if (x1 < 0) {
            tx1 = false;
        }

        if (x1 >= this.width) {
            tx1 = false;
        }

        if (y1 < 0) {
            ty1 = false;
        }

        if (y1 >= this.height) {
            ty1 = false;
        }

        double f00 = (double)(ty0 && tx0 ? this.pixels[y0][x0] : background);
        double f01 = (double)(ty1 && tx0 ? this.pixels[y1][x0] : background);
        double f10 = (double)(ty0 && tx1 ? this.pixels[y0][x1] : background);
        double f11 = (double)(ty1 && tx1 ? this.pixels[y1][x1] : background);
        double dx = x - (double)x0;
        double dy = y - (double)y0;
        if (dx < 0.0D) {
            ++dx;
        }

        if (dy < 0.0D) {
            ++dy;
        }

        double interpVal = Interpolation.bilerp(dx, dy, f00, f01, f10, f11);
        return (float)interpVal;
    }

    public float getPixelInterpNative(float x, float y, float background) {
        int x0 = (int)Math.floor((double)x);
        int x1 = x0 + 1;
        int y0 = (int)Math.floor((double)y);
        int y1 = y0 + 1;
        boolean ty1 = true;
        boolean tx1 = true;
        boolean ty0 = true;
        boolean tx0 = true;
        if (x0 < 0) {
            tx0 = false;
        }

        if (x0 >= this.width) {
            tx0 = false;
        }

        if (y0 < 0) {
            ty0 = false;
        }

        if (y0 >= this.height) {
            ty0 = false;
        }

        if (x1 < 0) {
            tx1 = false;
        }

        if (x1 >= this.width) {
            tx1 = false;
        }

        if (y1 < 0) {
            ty1 = false;
        }

        if (y1 >= this.height) {
            ty1 = false;
        }

        float f00 = ty0 && tx0 ? this.pixels[y0][x0] : background;
        float f01 = ty1 && tx0 ? this.pixels[y1][x0] : background;
        float f10 = ty0 && tx1 ? this.pixels[y0][x1] : background;
        float f11 = ty1 && tx1 ? this.pixels[y1][x1] : background;
        float dx = x - (float)x0;
        float dy = y - (float)y0;
        if (dx < 0.0F) {
            ++dx;
        }

        if (dy < 0.0F) {
            ++dy;
        }

        float interpVal = Interpolation.bilerpf(dx, dy, f00, f01, f10, f11);
        return interpVal;
    }

    public FImage internalCopy(FImage im) {
        int h = im.height;
        int w = im.width;
        float[][] impixels = im.pixels;

        for(int r = 0; r < h; ++r) {
            System.arraycopy(impixels[r], 0, this.pixels[r], 0, w);
        }

        return this;
    }

    public FImage internalAssign(FImage im) {
        this.pixels = im.pixels;
        this.height = im.height;
        this.width = im.width;
        return this;
    }

    public FImage internalAssign(int[] data, int width, int height) {
        if (this.height != height || this.width != width) {
            this.height = height;
            this.width = width;
            this.pixels = new float[height][width];
        }

        for(int y = 0; y < height; ++y) {
            for(int x = 0; x < width; ++x) {
                int rgb = data[x + width * y];
                int red = rgb >> 16 & 255;
                int green = rgb >> 8 & 255;
                int blue = rgb & 255;
                float fpix = 0.299F * (float)red + 0.587F * (float)green + 0.114F * (float)blue;
                this.pixels[y][x] = ImageUtilities.BYTE_TO_FLOAT_LUT[(int)fpix];
            }
        }

        return this;
    }

    public FImage inverse() {
        float max = this.max();

        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                this.pixels[r][c] = max - this.pixels[r][c];
            }
        }

        return this;
    }

    public Float max() {
        float max = 1.4E-45F;

        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                if (max < this.pixels[r][c]) {
                    max = this.pixels[r][c];
                }
            }
        }

        return max;
    }

    public FValuePixel maxPixel() {
        FValuePixel max = new FValuePixel(-1, -1);
        max.value = -3.4028235E38F;

        for(int y = 0; y < this.height; ++y) {
            for(int x = 0; x < this.width; ++x) {
                if (max.value < this.pixels[y][x]) {
                    max.value = this.pixels[y][x];
                    max.x = x;
                    max.y = y;
                }
            }
        }

        return max;
    }

    public Float min() {
        float min = 3.4028235E38F;

        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                if (min > this.pixels[r][c]) {
                    min = this.pixels[r][c];
                }
            }
        }

        return min;
    }

    public FValuePixel minPixel() {
        FValuePixel min = new FValuePixel(-1, -1);
        min.value = 3.4028235E38F;

        for(int y = 0; y < this.height; ++y) {
            for(int x = 0; x < this.width; ++x) {
                if (min.value > this.pixels[y][x]) {
                    min.value = this.pixels[y][x];
                    min.x = x;
                    min.y = y;
                }
            }
        }

        return min;
    }

    public FImage multiply(Float num) {
        return (FImage)super.multiply(num);
    }

    public FImage multiplyInplace(FImage im) {
        if (!ImageUtilities.checkSameSize(new Image[]{this, im})) {
            throw new AssertionError("images must be the same size");
        } else {
            for(int r = 0; r < this.height; ++r) {
                for(int c = 0; c < this.width; ++c) {
                    this.pixels[r][c] *= im.pixels[r][c];
                }
            }

            return this;
        }
    }

    public FImage multiplyInplace(Float num) {
        float fnum = num;

        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                this.pixels[r][c] *= fnum;
            }
        }

        return this;
    }

    public FImage multiplyInplace(float fnum) {
        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                this.pixels[r][c] *= fnum;
            }
        }

        return this;
    }

    public FImage multiplyInplace(Image<?, ?> im) {
        if (im instanceof FImage) {
            return this.multiplyInplace((FImage)im);
        } else {
            throw new UnsupportedOperationException("Unsupported Type");
        }
    }

    public FImage newInstance(int width, int height) {
        return new FImage(width, height);
    }

    public FImage normalise() {
        float min = this.min();
        float max = this.max();
        if (max == min) {
            return this;
        } else {
            for(int r = 0; r < this.height; ++r) {
                for(int c = 0; c < this.width; ++c) {
                    this.pixels[r][c] = (this.pixels[r][c] - min) / (max - min);
                }
            }

            return this;
        }
    }

    public FImage process(KernelProcessor<Float, FImage> p) {
        return this.process(p, false);
    }

    public FImage process(KernelProcessor<Float, FImage> p, boolean pad) {
        FImage newImage = new FImage(this.width, this.height);
        int kh = p.getKernelHeight();
        int kw = p.getKernelWidth();
        FImage tmp = new FImage(kw, kh);
        int hh = kh / 2;
        int hw = kw / 2;
        int y;
        int x;
        if (!pad) {
            for(y = hh; y < this.height - (kh - hh); ++y) {
                for(x = hw; x < this.width - (kw - hw); ++x) {
                    newImage.pixels[y][x] = (Float)p.processKernel(this.extractROI(x - hw, y - hh, tmp));
                }
            }
        } else {
            for(y = 0; y < this.height; ++y) {
                for(x = 0; x < this.width; ++x) {
                    newImage.pixels[y][x] = (Float)p.processKernel(this.extractROI(x - hw, y - hh, tmp));
                }
            }
        }

        return newImage;
    }

    public FImage processInplace(PixelProcessor<Float> p) {
        for(int y = 0; y < this.height; ++y) {
            for(int x = 0; x < this.width; ++x) {
                this.pixels[y][x] = (Float)p.processPixel(this.pixels[y][x]);
            }
        }

        return this;
    }

    public void analyseWith(PixelAnalyser<Float> p) {
        p.reset();

        for(int y = 0; y < this.height; ++y) {
            for(int x = 0; x < this.width; ++x) {
                p.analysePixel(this.pixels[y][x]);
            }
        }

    }

    public void setPixel(int x, int y, Float val) {
        if (x >= 0 && x < this.width && y >= 0 && y < this.height) {
            this.pixels[y][x] = val;
        }

    }

    public FImage subtract(FImage im) {
        if (!ImageUtilities.checkSameSize(new Image[]{this, im})) {
            throw new AssertionError("images must be the same size");
        } else {
            FImage newImage = new FImage(im.width, im.height);

            for(int r = 0; r < im.height; ++r) {
                for(int c = 0; c < im.width; ++c) {
                    newImage.pixels[r][c] = this.pixels[r][c] - im.pixels[r][c];
                }
            }

            return newImage;
        }
    }

    public FImage subtract(Float num) {
        FImage newImage = new FImage(this.width, this.height);

        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                newImage.pixels[r][c] = this.pixels[r][c] - num;
            }
        }

        return newImage;
    }

    public FImage subtract(Image<?, ?> input) {
        if (input instanceof FImage) {
            return this.subtract((FImage)input);
        } else {
            throw new UnsupportedOperationException("Unsupported Type");
        }
    }

    public FImage subtractInplace(FImage im) {
        if (!ImageUtilities.checkSameSize(new Image[]{this, im})) {
            throw new AssertionError("images must be the same size");
        } else {
            float[][] pix1 = this.pixels;
            float[][] pix2 = im.pixels;

            for(int r = 0; r < this.height; ++r) {
                for(int c = 0; c < this.width; ++c) {
                    pix1[r][c] -= pix2[r][c];
                }
            }

            return this;
        }
    }

    public FImage subtractInplace(Float num) {
        float fnum = num;

        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                this.pixels[r][c] -= fnum;
            }
        }

        return this;
    }

    public FImage subtractInplace(Image<?, ?> im) {
        if (im instanceof FImage) {
            return this.subtractInplace((FImage)im);
        } else {
            throw new UnsupportedOperationException("Unsupported Type");
        }
    }

    public FImage threshold(Float thresh) {
        float fthresh = thresh;

        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                if (this.pixels[r][c] <= fthresh) {
                    this.pixels[r][c] = 0.0F;
                } else {
                    this.pixels[r][c] = 1.0F;
                }
            }
        }

        return this;
    }

    public byte[] toByteImage() {
        byte[] pgmData = new byte[this.height * this.width];

        for(int j = 0; j < this.height; ++j) {
            for(int i = 0; i < this.width; ++i) {
                int v = (int)(255.0F * this.pixels[j][i]);
                v = Math.max(0, Math.min(255, v));
                pgmData[i + j * this.width] = (byte)(v & 255);
            }
        }

        return pgmData;
    }

    public int[] toPackedARGBPixels() {
        int[] bimg = new int[this.width * this.height];

        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                int v = Math.max(0, Math.min(255, (int)(this.pixels[r][c] * 255.0F)));
                int rgb = -16777216 | v << 16 | v << 8 | v;
                bimg[c + this.width * r] = rgb;
            }
        }

        return bimg;
    }

    public String toString() {
        String imageString = "";

        for(int y = 0; y < this.height; ++y) {
            for(int x = 0; x < this.width; ++x) {
                imageString = imageString + String.format("%+.3f ", this.pixels[y][x]);
                if (x == 16 && this.width - 16 > x) {
                    imageString = imageString + "... ";
                    x = this.width - 16;
                }
            }

            imageString = imageString + "\n";
            if (y == 16 && this.height - 16 > y) {
                y = this.height - 16;
                imageString = imageString + "... \n";
            }
        }

        return imageString;
    }

    public String toString(String format) {
        String imageString = "";

        for(int y = 0; y < this.height; ++y) {
            for(int x = 0; x < this.width; ++x) {
                imageString = imageString + String.format(format, this.pixels[y][x]);
            }

            imageString = imageString + "\n";
        }

        return imageString;
    }

    public FImage transform(Matrix transform) {
        return (FImage)super.transform(transform);
    }

    public FImage zero() {
        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                this.pixels[r][c] = 0.0F;
            }
        }

        return this;
    }

    public boolean equals(Object o) {
        return !(o instanceof FImage) ? false : this.equalsThresh((FImage)o, 0.0F);
    }

    public boolean equalsThresh(FImage o, float thresh) {
        FImage that = o;
        if (o.height == this.height && o.width == this.width) {
            for(int i = 0; i < this.height; ++i) {
                for(int j = 0; j < this.width; ++j) {
                    if (Math.abs(that.pixels[i][j] - this.pixels[i][j]) > thresh) {
                        return false;
                    }
                }
            }

            return true;
        } else {
            return false;
        }
    }

    public float getPixelNative(Pixel p) {
        return this.getPixelNative(p.x, p.y);
    }

    public float getPixelNative(int x, int y) {
        return this.pixels[y][x];
    }

    public float[] getPixelVectorNative(float[] f) {
        for(int y = 0; y < this.getHeight(); ++y) {
            for(int x = 0; x < this.getWidth(); ++x) {
                f[x + y * this.getWidth()] = this.pixels[y][x];
            }
        }

        return f;
    }

    public void setPixelNative(int x, int y, float val) {
        this.pixels[y][x] = val;
    }

    public static FImage[] createArray(int num, int width, int height) {
        FImage[] array = new FImage[num];

        for(int i = 0; i < num; ++i) {
            array[i] = new FImage(width, height);
        }

        return array;
    }

    public float sum() {
        float sum = 0.0F;
        float[][] var2 = this.pixels;
        int var3 = var2.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            float[] row = var2[var4];

            for(int i = 0; i < row.length; ++i) {
                sum += row[i];
            }
        }

        return sum;
    }

    public MBFImage toRGB() {
        return new MBFImage(ColourSpace.RGB, new FImage[]{this.clone(), this.clone(), this.clone()});
    }

    public FImage flipX() {
        int hwidth = this.width / 2;

        for(int y = 0; y < this.height; ++y) {
            for(int x = 0; x < hwidth; ++x) {
                int xx = this.width - x - 1;
                float tmp = this.pixels[y][x];
                this.pixels[y][x] = this.pixels[y][xx];
                this.pixels[y][xx] = tmp;
            }
        }

        return this;
    }

    public FImage flipY() {
        int hheight = this.height / 2;

        for(int y = 0; y < hheight; ++y) {
            int yy = this.height - y - 1;

            for(int x = 0; x < this.width; ++x) {
                float tmp = this.pixels[y][x];
                this.pixels[y][x] = this.pixels[yy][x];
                this.pixels[yy][x] = tmp;
            }
        }

        return this;
    }

    public FImage overlayInplace(FImage img, FImage alpha, int x, int y) {
        int sx = Math.max(x, 0);
        int sy = Math.max(y, 0);
        int ex = Math.min(this.width, x + img.getWidth());
        int ey = Math.min(this.height, y + img.getHeight());

        for(int yc = sy; yc < ey; ++yc) {
            for(int xc = sx; xc < ex; ++xc) {
                float a = alpha.pixels[yc - sy][xc - sx];
                this.pixels[yc][xc] = a * img.pixels[yc - sy][xc - sx] + (1.0F - a) * this.pixels[yc][xc];
            }
        }

        return this;
    }

    public FImage overlayInplace(FImage image, int x, int y) {
        return this.overlayInplace(image, this.clone().fill(1.0F), x, y);
    }

    public static FImage randomImage(int width, int height) {
        FImage img = new FImage(width, height);

        for(int y = 0; y < height; ++y) {
            for(int x = 0; x < width; ++x) {
                img.pixels[y][x] = (float)Math.random();
            }
        }

        return img;
    }

    public FImage replace(Float target, Float replacement) {
        return this.replace(target, replacement);
    }

    public FImage replace(float target, float replacement) {
        for(int r = 0; r < this.height; ++r) {
            for(int c = 0; c < this.width; ++c) {
                if (this.pixels[r][c] == target) {
                    this.pixels[r][c] = replacement;
                }
            }
        }

        return this;
    }

    public FImage extractCentreSubPix(float cx, float cy, FImage out) {
        int width = out.width;
        int height = out.height;

        for(int y = 0; y < height; ++y) {
            for(int x = 0; x < width; ++x) {
                float ix = (float)((double)((float)x + cx) - (double)(width - 1) * 0.5D);
                float iy = (float)((double)((float)y + cy) - (double)(height - 1) * 0.5D);
                out.pixels[y][x] = this.getPixelInterpNative(ix, iy, 0.0F);
            }
        }

        return out;
    }
}


static abstract class AbstractMultiScaleObjectDetector<IMAGE extends Image<?, IMAGE>, DETECTED_OBJECT> implements MultiScaleObjectDetector<IMAGE, DETECTED_OBJECT> {
    protected Rectangle roi;
    protected int minSize = 0;
    protected int maxSize = 0;

    protected AbstractMultiScaleObjectDetector() {
    }

    protected AbstractMultiScaleObjectDetector(int minSize, int maxSize) {
        this.minSize = minSize;
        this.maxSize = maxSize;
    }

    public void setROI(Rectangle roi) {
        this.roi = roi;
    }

    public void setMinimumDetectionSize(int size) {
        this.minSize = size;
    }

    public void setMaximumDetectionSize(int size) {
        this.maxSize = size;
    }

    public int getMinimumDetectionSize() {
        return this.minSize;
    }

    public int getMaximumDetectionSize() {
        return this.maxSize;
    }
}

sclass Detector extends AbstractMultiScaleObjectDetector<FImage, Rectangle> {
  /**
   * Default step size to make when there is a hint of detection.
   */
  public static final int DEFAULT_SMALL_STEP = 1;

  /**
   * Default step size to make when there is definitely no detection.
   */
  public static final int DEFAULT_BIG_STEP = 2;

  /**
   * Default scale factor multiplier.
   */
  public static final float DEFAULT_SCALE_FACTOR = 1.1f;

  protected StageTreeClassifier cascade;
  protected float scaleFactor = 1.1f;
  protected int smallStep = 1;
  protected int bigStep = 2;

  /**
   * Construct the {@link Detector} with the given parameters.
   * 
   * @param cascade
   *            the cascade or tree of stages.
   * @param scaleFactor
   *            the amount to change between scales (multiplicative)
   * @param smallStep
   *            the amount to step when there is a hint of detection
   * @param bigStep
   *            the amount to step when there is definitely no detection
   */
  public Detector(StageTreeClassifier cascade, float scaleFactor, int smallStep, int bigStep) {
    super(Math.max(cascade.width, cascade.height), 0);

    this.cascade = cascade;
    this.scaleFactor = scaleFactor;
    this.smallStep = smallStep;
    this.bigStep = bigStep;
  }

  /**
   * Construct the {@link Detector} with the given tree of stages and scale
   * factor. The default step sizes are used.
   * 
   * @param cascade
   *            the cascade or tree of stages.
   * @param scaleFactor
   *            the amount to change between scales
   */
  public Detector(StageTreeClassifier cascade, float scaleFactor) {
    this(cascade, scaleFactor, DEFAULT_SMALL_STEP, DEFAULT_BIG_STEP);
  }

  /**
   * Construct the {@link Detector} with the given tree of stages, and the
   * default parameters for step sizes and scale factor.
   * 
   * @param cascade
   *            the cascade or tree of stages.
   */
  public Detector(StageTreeClassifier cascade) {
    this(cascade, DEFAULT_SCALE_FACTOR, DEFAULT_SMALL_STEP, DEFAULT_BIG_STEP);
  }

  /**
   * Perform detection at a single scale. Subclasses may override this to
   * customise the spatial search. The given starting and stopping coordinates
   * take into account any region of interest set on this detector.
   * 
   * @param sat
   *            the summed area table(s)
   * @param startX
   *            the starting x-ordinate
   * @param stopX
   *            the stopping x-ordinate
   * @param startY
   *            the starting y-ordinate
   * @param stopY
   *            the stopping y-ordinate
   * @param ystep
   *            the amount to step
   * @param windowWidth
   *            the window width at the current scale
   * @param windowHeight
   *            the window height at the current scale
   * @param results
   *            the list to store detection results in
   */
  protected void detectAtScale(final SummedSqTiltAreaTable sat, final int startX, final int stopX, final int startY,
      final int stopY, final float ystep, final int windowWidth, final int windowHeight,
      final List<Rectangle> results)
  {
    for (int iy = startY; iy < stopY; iy++) {
      final int y = Math.round(iy * ystep);

      for (int ix = startX, xstep = 0; ix < stopX; ix += xstep) {
        final int x = Math.round(ix * ystep);

        final int result = cascade.classify(sat, x, y);

        if (result > 0) {
          results.add(new Rectangle(x, y, windowWidth, windowHeight));
        }

        // if there is no detection, then increase the step size
        xstep = (result > 0 ? smallStep : bigStep);

        // TODO: think about what to do if there isn't a detection, but
        // we're very close to having one based on the ratio of stages
        // passes to total stages.
      }
    }
  }

  @Override
  public List<Rectangle> detect(FImage image) {
    final List<Rectangle> results = new ArrayList<Rectangle>();

    final int imageWidth = image.getWidth();
    final int imageHeight = image.getHeight();

    final SummedSqTiltAreaTable sat = new SummedSqTiltAreaTable(image, cascade.hasTiltedFeatures);

    // compute the number of scales to test and the starting factor
    int nFactors = 0;
    int startFactor = 0;
    for (float factor = 1; factor * cascade.width < imageWidth - 10 &&
        factor * cascade.height < imageHeight - 10; factor *= scaleFactor)
    {
      final float width = factor * cascade.width;
      final float height = factor * cascade.height;

      if (width < minSize || height < minSize) {
        startFactor++;
      }

      if (maxSize > 0 && (width > maxSize || height > maxSize)) {
        break;
      }

      nFactors++;
    }

    // run the detection at each scale
    float factor = (float) Math.pow(scaleFactor, startFactor);
    for (int scaleStep = startFactor; scaleStep < nFactors; factor *= scaleFactor, scaleStep++) {
      final float ystep = Math.max(2, factor);

      final int windowWidth = (int) (factor * cascade.width);
      final int windowHeight = (int) (factor * cascade.height);

      // determine the spatial range, taking into account any ROI.
      final int startX = (int) (roi == null ? 0 : Math.max(0, roi.x));
      final int startY = (int) (roi == null ? 0 : Math.max(0, roi.y));
      final int stopX = Math.round(
          (((roi == null ? imageWidth : Math.min(imageWidth, roi.x + roi.width)) - windowWidth)) / ystep);
      final int stopY = Math.round(
          (((roi == null ? imageHeight : Math.min(imageHeight, roi.y + roi.height)) - windowHeight)) / ystep);

      // prepare the cascade for this scale
      cascade.setScale(factor);

      detectAtScale(sat, startX, stopX, startY, stopY, ystep, windowWidth, windowHeight, results);
    }

    return results;
  }

  /**
   * Get the step size the detector will make if there is any hint of a
   * detection. This should be smaller than {@link #bigStep()}.
   * 
   * @return the amount to step on any hint of detection.
   */
  public int smallStep() {
    return smallStep;
  }

  /**
   * Get the step size the detector will make if there is definitely no
   * detection. This should be bigger than {@link #smallStep()}.
   * 
   * @return the amount to step when there is definitely no detection.
   */
  public int bigStep() {
    return bigStep;
  }

  /**
   * Set the step size the detector will make if there is any hint of a
   * detection. This should be smaller than {@link #bigStep()}.
   * 
   * @param smallStep
   *            The amount to step on any hint of detection.
   */
  public void setSmallStep(int smallStep) {
    this.smallStep = smallStep;
  }

  /**
   * Set the step size the detector will make if there is definitely no
   * detection. This should be bigger than {@link #smallStep()}.
   * 
   * @param bigStep
   *            The amount to step when there is definitely no detection.
   */
  public void bigStep(int bigStep) {
    this.bigStep = bigStep;
  }

  /**
   * Get the scale factor (the amount to change between scales
   * (multiplicative)).
   * 
   * @return the scaleFactor
   */
  public float getScaleFactor() {
    return scaleFactor;
  }

  /**
   * Set the scale factor (the amount to change between scales
   * (multiplicative)).
   * 
   * @param scaleFactor
   *            the scale factor to set
   */
  public void setScaleFactor(float scaleFactor) {
    this.scaleFactor = scaleFactor;
  }

  /**
   * Get the classifier tree or cascade used by this detector.
   * 
   * @return the classifier tree or cascade.
   */
  public StageTreeClassifier getClassifier() {
    return cascade;
  }
}

sclass HaarCascadeDetector {
  public enum BuiltInCascade {
    /**
     * A eye detector
     */
    eye("haarcascade_eye.xml"),
    /**
     * A eye with glasses detector
     */
    eye_tree_eyeglasses("haarcascade_eye_tree_eyeglasses.xml"),
    /**
     * A frontal face detector
     */
    frontalface_alt("haarcascade_frontalface_alt.xml"),
    /**
     * A frontal face detector
     */
    frontalface_alt2("haarcascade_frontalface_alt2.xml"),
    /**
     * A frontal face detector
     */
    frontalface_alt_tree("haarcascade_frontalface_alt_tree.xml"),
    /**
     * A frontal face detector
     */
    frontalface_default("haarcascade_frontalface_default.xml"),
    /**
     * A fullbody detector
     */
    fullbody("haarcascade_fullbody.xml"),
    /**
     * A left eye detector
     */
    lefteye_2splits("haarcascade_lefteye_2splits.xml"),
    /**
     * A lower body detector
     */
    lowerbody("haarcascade_lowerbody.xml"),
    /**
     * A detector for a pair of eyes
     */
    mcs_eyepair_big("haarcascade_mcs_eyepair_big.xml"),
    /**
     * A detector for a pair of eyes
     */
    mcs_eyepair_small("haarcascade_mcs_eyepair_small.xml"),
    /**
     * A left eye detector
     */
    mcs_lefteye("haarcascade_mcs_lefteye.xml"),
    /**
     * A mouth detector
     */
    mcs_mouth("haarcascade_mcs_mouth.xml"),
    /**
     * A nose detector
     */
    mcs_nose("haarcascade_mcs_nose.xml"),
    /**
     * A right eye detector
     */
    mcs_righteye("haarcascade_mcs_righteye.xml"),
    /**
     * An upper body detector
     */
    mcs_upperbody("haarcascade_mcs_upperbody.xml"),
    /**
     * A profile face detector
     */
    profileface("haarcascade_profileface.xml"),
    /**
     * A right eye detector
     */
    righteye_2splits("haarcascade_righteye_2splits.xml"),
    /**
     * An upper body detector
     */
    upperbody("haarcascade_upperbody.xml");

    private String classFile;

    private BuiltInCascade(String classFile) {
      this.classFile = classFile;
    }

    /**
     * @return The name of the cascade resource
     */
    public String classFile() {
      return classFile;
    }

    /**
     * Create a new detector with the this cascade.
     * 
     * @return A new {@link HaarCascadeDetector}
     */
    public HaarCascadeDetector load() {
      try {
        return new HaarCascadeDetector(classFile);
      } catch (final Exception e) {
        throw new RuntimeException(e);
      }
    }
  }

  protected Detector detector;
  protected DetectionFilter<Rectangle, ObjectIntPair<Rectangle>> groupingFilter;
  protected boolean histogramEqualize = false;

  /**
   * Construct with the given cascade resource. See
   * {@link #setCascade(String)} to understand how the cascade is loaded.
   * 
   * @param cas
   *            The cascade resource.
   * @see #setCascade(String)
   */
  public HaarCascadeDetector(String cas) {
    try {
      setCascade(cas);
    } catch (final Exception e) {
      throw new RuntimeException(e);
    }
    groupingFilter = new OpenCVGrouping();
  }

  /**
   * Construct with the {@link BuiltInCascade#frontalface_default} cascade.
   */
  public HaarCascadeDetector() {
    this(BuiltInCascade.frontalface_default.classFile());
  }

  /**
   * Construct with the {@link BuiltInCascade#frontalface_default} cascade and
   * the given minimum search window size.
   * 
   * @param minSize
   *            minimum search window size
   */
  public HaarCascadeDetector(int minSize) {
    this();
    this.detector.setMinimumDetectionSize(minSize);
  }

  /**
   * Construct with the given cascade resource and the given minimum search
   * window size. See {@link #setCascade(String)} to understand how the
   * cascade is loaded.
   * 
   * @param cas
   *            The cascade resource.
   * @param minSize
   *            minimum search window size.
   * 
   * @see #setCascade(String)
   */
  public HaarCascadeDetector(String cas, int minSize) {
    this(cas);
    this.detector.setMinimumDetectionSize(minSize);
  }

  /**
   * @return The minimum detection window size
   */
  public int getMinSize() {
    return this.detector.getMinimumDetectionSize();
  }

  /**
   * Set the minimum detection window size
   * 
   * @param size
   *            the window size
   */
  public void setMinSize(int size) {
    this.detector.setMinimumDetectionSize(size);
  }

  /**
   * @return The maximum detection window size
   */
  public int getMaxSize() {
    return this.detector.getMaximumDetectionSize();
  }

  /**
   * Set the maximum detection window size
   * 
   * @param size
   *            the window size
   */
  public void setMaxSize(int size) {
    this.detector.setMaximumDetectionSize(size);
  }

  /**
   * @return The grouping filter
   */
  public DetectionFilter<Rectangle, ObjectIntPair<Rectangle>> getGroupingFilter() {
    return groupingFilter;
  }

  /**
   * Set the filter for merging detections
   * 
   * @param grouping
   */
  public void setGroupingFilter(DetectionFilter<Rectangle, ObjectIntPair<Rectangle>> grouping) {
    this.groupingFilter = grouping;
  }

  @Override
  public List<DetectedFace> detectFaces(FImage image) {
    if (histogramEqualize)
      image.processInplace(new EqualisationProcessor());

    final List<Rectangle> rects = detector.detect(image);
    final List<ObjectIntPair<Rectangle>> filteredRects = groupingFilter.apply(rects);

    final List<DetectedFace> results = new ArrayList<DetectedFace>();
    for (final ObjectIntPair<Rectangle> r : filteredRects) {
      results.add(new DetectedFace(r.first, image.extractROI(r.first), r.second));
    }

    return results;
  }

  /**
   * @see Detector#getScaleFactor()
   * @return The detector scale factor
   */
  public double getScaleFactor() {
    return detector.getScaleFactor();
  }

  /**
   * Set the cascade classifier for this detector. The cascade file is first
   * searched for as a java resource, and if it is not found then a it is
   * assumed to be a file on the filesystem.
   * 
   * @param cascadeResource
   *            The cascade to load.
   * @throws Exception
   *             if there is a problem loading the cascade.
   */
  public void setCascade(String cascadeResource) throws Exception {
    // try to load serialized cascade from external XML file
    InputStream in = null;
    try {
      in = OCVHaarLoader.class.getResourceAsStream(cascadeResource);

      if (in == null) {
        in = new FileInputStream(new File(cascadeResource));
      }
      final StageTreeClassifier cascade = OCVHaarLoader.read(in);

      if (this.detector == null)
        this.detector = new Detector(cascade);
      else
        this.detector = new Detector(cascade, this.detector.getScaleFactor());
    } catch (final Exception e) {
      throw e;
    } finally {
      if (in != null) {
        try {
          in.close();
        } catch (final IOException e) {
        }
      }
    }
  }

  /**
   * Set the detector scale factor
   * 
   * @see Detector#setScaleFactor(float)
   * 
   * @param scaleFactor
   *            the scale factor
   */
  public void setScale(float scaleFactor) {
    this.detector.setScaleFactor(scaleFactor);
  }

  /**
   * Serialize the detector using java serialization to the given stream
   * 
   * @param os
   *            the stream
   * @throws IOException
   */
  public void save(OutputStream os) throws IOException {
    final ObjectOutputStream oos = new ObjectOutputStream(os);
    oos.writeObject(this);
  }

  /**
   * Deserialize the detector from a stream. The detector must have been
   * written with a previous invokation of {@link #save(OutputStream)}.
   * 
   * @param is
   * @return {@link HaarCascadeDetector} read from stream.
   * @throws IOException
   * @throws ClassNotFoundException
   */
  public static HaarCascadeDetector read(InputStream is) throws IOException, ClassNotFoundException {
    final ObjectInputStream ois = new ObjectInputStream(is);
    return (HaarCascadeDetector) ois.readObject();
  }

  @Override
  public int hashCode() {
    int hashCode = HashCodeUtil.SEED;

    hashCode = HashCodeUtil.hash(hashCode, this.detector.getMinimumDetectionSize());
    hashCode = HashCodeUtil.hash(hashCode, this.detector.getScaleFactor());
    hashCode = HashCodeUtil.hash(hashCode, this.detector.getClassifier().getName());
    hashCode = HashCodeUtil.hash(hashCode, this.groupingFilter);
    hashCode = HashCodeUtil.hash(hashCode, this.histogramEqualize);

    return hashCode;
  }

  @Override
  public void readBinary(DataInput in) throws IOException {
    this.detector = IOUtils.read(in);
    this.groupingFilter = IOUtils.read(in);

    histogramEqualize = in.readBoolean();
  }

  @Override
  public byte[] binaryHeader() {
    return "HAAR".getBytes();
  }

  @Override
  public void writeBinary(DataOutput out) throws IOException {
    IOUtils.write(detector, out);
    IOUtils.write(groupingFilter, out);

    out.writeBoolean(histogramEqualize);
  }

  @Override
  public String toString() {
    return "HaarCascadeDetector[cascade=" + detector.getClassifier().getName() + "]";
  }

  /**
   * @return the underlying Haar cascade.
   */
  public StageTreeClassifier getCascade() {
    return detector.getClassifier();
  }

  /**
   * @return the underlying {@link Detector}.
   */
  public Detector getDetector() {
    return detector;
  }
}

sclass HaarCascade_FaceDetector extends F1<BufferedImage, L<RectAndConfidence>> {
  new HaarCascadeDetector detector;
  
  public L<RectAndConfidence> get(BufferedImage img) {
    if (img == null) null;
    ret map(detector.detectFaces(ImageUtilities.createFImage(img)),
      func(DetectedFace f) -> RectAndConfidence {
        RectAndConfidence(openImajRectangleToRect(f.getBounds()), f.getConfidence())
      });
  }
}

module HCFD > DynSingleFunctionWithPrintLog {
  void doIt {
    pnl(new HaarCascade_FaceDetector().get(loadImage2(#1101409)));
  }
}

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: 356 / 436
Version history: 8 change(s)
Referenced in: [show references]