// grayscale, actually sclass BWIntegralImage > Meta implements IBWIntegralImage, IIntegralImage { int w, h; int[] data; // 1 entry per pixel ifdef BWIntegralImage_CountAccesses long accesses; endifdef // constructors *() {} *(File f) { this(loadImage2(f)); } *(MakesBufferedImage img) { this(toBufferedImage(img)); } *(BufferedImage image) { grab(image); } *(BufferedImage image, Decolorizer decolorizer) { grab(image, decolorizer); } *(GrabbableIntPixels gp) { grab(gp); } *(GrabbableRGBBytePixels gp) { grab(gp, new Decolorizer.Simple); } *(GrabbableGrayPixels gp) { grab(gp); } *(BWImage img) { grab(new GrabbableGrayPixels(img.pixels, img.width, img.height, 0, img.width); } // grab functions void grab(BufferedImage image, Decolorizer decolorizer default null) { if (image.getType() == BufferedImage.TYPE_BYTE_GRAY) grab(grabbableGrayPixels(image)); else { // rgb image var gp = grabbableRGBBytePixels(image); if (gp != null) grab(gp, decolorizer); else grab(grabbableIntPixels_fastOrSlow(image), decolorizer); } } void grab(GrabbableRGBBytePixels gp, Decolorizer decolorizer) { if (decolorizer == null) decolorizer = new Decolorizer.Simple; alloc(gp.w, gp.h); int w = this.w, h = this.h; ifdef BWIntegralImage_debug print("BWIntegralImage grabbing: " + gp); endifdef // first row int iImage = gp.offset, sum = 0, pixelStride = gp.pixelStride; byte[] image = gp.data; for x to w: { int packed = rgbInt(image[iImage], image[iImage+1], image[iImage+2]); iImage += pixelStride; int brightness = decolorizer.toGrayScale(packed); data[x] = (sum += brightness); } // subsequent rows var ping = pingSource(); int scanlineExtra = gp.scanlineStride-w*pixelStride; iImage = gp.offset+gp.scanlineStride; int i = w; for (int y = 1; y < h; y++) { sum = 0; for x to w: { int packed = rgbInt(image[iImage], image[iImage+1], image[iImage+2]); iImage += pixelStride; int brightness = decolorizer.toGrayScale(packed); sum += brightness; data[i] = sum + data[i-w]; i++; } iImage += scanlineExtra; ping?!; } // for y } void grab(GrabbableIntPixels gp, Decolorizer decolorizer) { if (isDefaultDecolorizer(decolorizer)) ret with grab(gp); alloc(gp.w, gp.h); int w = this.w, h = this.h; ifdef BWIntegralImage_debug print("BWIntegralImage grabbing: " + gp); endifdef int offset = gp.offset, sum = 0; int[] image = gp.data; for x to w: { int packed = image[offset+x]; int brightness = decolorizer.toGrayScale(packed); data[x] = (sum += brightness); } var ping = pingSource(); int scanlineExtra = gp.scanlineStride-w; int iImage = offset+gp.scanlineStride, i = w; for (int y = 1; y < h; y++) { sum = 0; for x to w: { int packed = image[iImage]; int brightness = decolorizer.toGrayScale(packed); sum += brightness; data[i] = sum + data[i-w]; iImage++; i++; } iImage += scanlineExtra; ping?!; } // for y } void grab(GrabbableIntPixels gp) { alloc(gp.w, gp.h); int w = this.w, h = this.h; ifdef BWIntegralImage_debug print("BWIntegralImage grabbing: " + gp); endifdef int offset = gp.offset, sum = 0; int[] image = gp.data; for x to w: { int packed = image[offset+x]; int brightness = packedToBrightness(packed); data[x] = (sum += brightness); } var ping = pingSource(); int scanlineExtra = gp.scanlineStride-w; int iImage = offset+gp.scanlineStride, i = w; for (int y = 1; y < h; y++) { sum = 0; for x to w: { int packed = image[iImage]; int brightness = packedToBrightness(packed); sum += brightness; data[i] = sum + data[i-w]; iImage++; i++; } iImage += scanlineExtra; ping?!; } // for y } void grab(GrabbableGrayPixels gp) { alloc(gp.w, gp.h); ifdef BWIntegralImage_debug print("BWIntegralImage grabbing: " + gp); endifdef int offset = gp.offset, sum = 0; byte[] image = gp.data; for x to w: { int brightness = image[offset+x]; data[x] = (sum += brightness); } var ping = pingSource(); int scanlineExtra = gp.scanlineStride-w; int iImage = offset+gp.scanlineStride, i = w; for (int y = 1; y < h; y++) { sum = 0; for x to w: { int brightness = image[iImage]; sum += brightness; data[i] = sum + data[i-w]; iImage++; i++; } iImage += scanlineExtra; ping?!; } // for y } private void alloc(int w, int h) { this.w = w; this.h = h; if (w*h > 8*1024*1024) fail("Image too large (more than 8 MP): " + w + "*" + h); data = new int[w*h]; } // pixels outside of image are considered black int get(int x, int y) { ifdef BWIntegralImage_CountAccesses ++accesses; endifdef ret x < 0 || y < 0 ? 0 : data[min(y, h-1)*w+min(x, w-1)]; } // precise version [TO TEST!] public double getIIValue(double x, double y) { int xFloor = ifloor(x), yFloor = ifloor(y); double val = getIIValue(xFloor, yFloor); // at integer coordinate? if (xFloor == x && yFloor == y) ret val; // at non-integer coordinate, perform subpixel calculation double val2 = getIIValue(xFloor+1, yFloor); double val3 = getIIValue(xFloor , yFloor+1); double val4 = getIIValue(xFloor+1, yFloor+1); ret blend2D(val, val2, val3, val4, x-xFloor, y-yFloor); } public int getIIValue(int x, int y) { ret get(x, y); } public double getIntegralValue(int x, int y, int channel) { ret get(x, y); } public double getPixelAverage(int x1, int y1, int x2, int y2) { int area = (x2-x1)*(y2-y1); ret doubleRatio(bwIntegralImage_sumRect(this, x1, y1, x2, y2), area); } public int getWidth() { ret w; } public int getHeight() { ret h; } int packedToBrightness(int packed) { int b = (packed & 0xFF); ifdef BWIntegralImage_brightnessCheat ret b; endifdef ifndef BWIntegralImage_brightnessCheat int r = ((packed >> 16) & 0xFF); int g = ((packed >> 8) & 0xFF); ret (r+g+b+1)/3; endifndef } // get brightness of pixel public int getInt(int x, int y) { ret iround(rectSum(x, y, x+1, y+1, 0)); } // returns RGB pixel without alpha public int getPixel(int x, int y) { ret rgbIntFromGrayscale(getInt(x, y)); } public BufferedImage getBufferedImage() { //ret scaleDownUsingIntegralImageBW(this, w).getBufferedImage(); O src = metaGet src(this); if (src cast BufferedImage) ret src; ret grayImageFromIBWIntegralImage(this); } }