import jdk.incubator.vector.*; // TODO: image w/h not divisible by 8 final sclass BWIntegralImage_doubleVectorized implements MakesBufferedImage, IBWIntegralImage { // dual logarithm of block size & corresponding int vector species replace blockShift with 3. replace species with IntVector.SPECIES_256. replace blockSize with (1 << blockShift). int w, h; // actual image size int blockW, blockH; // width and height of block array int[] sums; // per block int[][] blocks; ifdef BWIntegralImage_CountAccesses long accesses; endifdef *() {} *(File f) { this(loadImage2(f)); } *(MakesBufferedImage img) { this(toBufferedImage(img)); } *(BufferedImage image) ctex { alloc(image.getWidth(), image.getHeight()); // Grab image // TODO: could use grayscale color model here (faster?) int[] data = new[w*h]; PixelGrabber pixelGrabber = new PixelGrabber(image, 0, 0, w, h, data, 0, w); if (!pixelGrabber.grabPixels()) fail("Could not grab pixels"); // for brightness of pixels, // for now we cheat by just using one of the channels // calculate sum of each block int iBlock = 0; for by to blockH: { int iLine = (by << blockShift)*w; for bx to blockW: { // get sum base value int sumAbove = blockSum(bx, by-1); int sumLeft = blockSum(bx-1, by); int sumDiagonal = blockSum(bx-1, by-1); int sum = sumAbove+sumLeft-sumDiagonal; int i = iLine+(bx << blockShift); for (int y = 0; y < blockSize; y++) { IntVector v = IntVector.fromArray(species, data, i); v = v.and(255); int sum2 = sum+v.reduceLanes(VectorOperators.ADD); v.add(sum); v.intoArray(data, i); sum = sum2; i += h; } sums[iBlock++] = sum; } } } int blockSum(int bx, int by) { ret bx < 0 || by < 0 ? 0 : sums[by*blockW+bx]; } int[] getBlockData(int bx, int by) { int[] block = blocks[by*blockW+bx]; if (block == null) calcData(bx, by); ret block; } void calcData(int bx, int by) { todo(); } private void alloc(int w, int h) { if ((w % blockSize) != 0 || (h % blockSize) != 0) fail("Need image dimensions divisible by " + blockSize + ": " + w + "*" + h); this.w = w; this.h = h; blockW = ratioRoundUp(w, blockSize); blockH = ratioRoundUp(h, blockSize); sums = new int[blockW*blockH]; blocks = new int[blockW*blockH][]; } // get sum value at x, y // pixels outside of image are considered black public int getIIValue(int x, int y) { ifdef BWIntegralImage_CountAccesses ++accesses; endifdef if (x < 0 || y < 0 || x >= w || y >= h) ret 0; int idx = ((x & (blockSize-1)) << blockSize) | (y & (blockSize-1)); ret idx == 0 ? blockSum(x >> blockShift, y >> blockShift) : getBlockData(x >> blockShift, y >> blockShift)[idx]; } 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); } int getPixel(int x, int y) { ret bwIntegralImage_sumRect(this, x, y, x+1, y+1); } int getPixel(Pt p) { ret getPixel(p.x, p.y); } public int getWidth() { ret w; } public int getHeight() { ret h; } // unoptimized public BufferedImage getBufferedImage() { ret scaleDownUsingIntegralImageBW(this, w, h).getBufferedImage(); } }