set flag BWIntegralImage_useVectorAPI. // grayscale, actually final sclass BWIntegralImage extends Meta implements MakesBufferedImage, IBWIntegralImage, IIntegralImage { int w, h; int[] data; // 1 entry per pixel ifdef BWIntegralImage_CountAccesses long accesses; endifdef *() {} *(File f) { this(loadImage2(f)); } *(MakesBufferedImage img) { this(toBufferedImage(img)); } //*(BufferedImage img) { this(BWImage(img)); } *(BufferedImage image) ctex { alloc(image.getWidth(), image.getHeight()); pcall { GrabbableIntPixels gp = grabbableIntPixels(image); if (gp != null) ret with grab(gp); } // Use pixelGrabber if quick method fails PixelGrabber pixelGrabber = new(image, 0, 0, w, h, data, 0, w); if (!pixelGrabber.grabPixels()) fail("Could not grab pixels"); grab(GrabbableIntPixels(data, w, h, 0, w)); } *(GrabbableIntPixels gp) { alloc(gp.w, gp.h); grab(gp); } void grab(GrabbableIntPixels gp) { ifdef BWIntegralImage_debug print("BWIntegralImage grabbing: " + gp); endifdef int offset = gp.offset; int[] image = gp.data; int sum = 0; for x to w: { int packed = image[offset+x]; int brightness = packedToBrightness(packed); data[x] = (sum += brightness); } ifdef BWIntegralImage_useVectorAPI import jdk.incubator.vector.*; VectorSpecies species = IntVector.SPECIES_PREFERRED; int upperBound = species.loopBound(w); endifdef int scanlineExtra = gp.scanlineStride-w; int iImage = offset+gp.scanlineStride, i = w; for (int y = 1; y < h; y++) { sum = 0; ifdef BWIntegralImage_useVectorAPI int x = 0; for (; x < upperBound; x += species.length(), iImage += species.length(), i += species.length()) { for (int sub = 0; sub < species.length(); sub++) { sum += packedToBrightness(image[iImage+sub]); data[i+sub] = sum; } IntVector v = IntVector.fromArray(species, data, i); IntVector v_last = IntVector.fromArray(species, data, i-w); v = v.add(v_last); v.intoArray(data, i); } for (; x < w; x++, iImage++, i++) { int packed = image[iImage]; int brightness = packedToBrightness(packed); sum += brightness; data[i] = sum + data[i-w]; } endifdef ifndef BWIntegralImage_useVectorAPI for x to w: { int packed = image[iImage]; int brightness = packedToBrightness(packed); sum += brightness; data[i] = sum + data[i-w]; iImage++; i++; } endifndef iImage += scanlineExtra; } // for y } *(BWImage img) { alloc(img.w(), img.h()); data = new int[w*h]; int i = 0; for y to h: { int sum = 0; for x to w: { sum += img.getByte(x, y) & 0xFF; data[i] = y > 0 ? sum + data[i-w] : sum; i++; } } } 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 || x >= w || y >= h ? 0 : data[min(y, h-1)*w+min(x, w-1)]; } 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; } // unoptimized public BufferedImage getBufferedImage() { ret scaleDownUsingIntegralImageBW(this, w).getBufferedImage(); } 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 } // returns RGB pixel without alpha public int getPixel(int x, int y) { int r = iround(rectSum(x, y, x+1, y+1, 0)); int g = iround(rectSum(x, y, x+1, y+1, 1)); int b = iround(rectSum(x, y, x+1, y+1, 2)); ret rgbInt(r, g, b); } }