ImageUtils { public static double[] countSubpixel(BufferedImage bimage) { int width = bimage.getWidth(); int height = bimage.getHeight(); int bgColor = detectBackgroundColor(bimage); int count = 0; int total = 0; boolean wasBackground = true; boolean inside = false; int[] previous = null; int[] countPerLine = new int[height]; for (int y = 0; y < height; y++) { int numberOfUpdown = 0; for (int x = 0; x < width; x++) { int pixel = bimage.getRGB(x, y); int[] argb = toARGB(pixel); if (norm(pixel, bgColor) < 25) { if (!wasBackground) { if (previous[1] > previous[2] || previous[2] > previous[3] || previous[1] == previous[3]) { } else { if (inside) { count++; } } inside = false; total++; } numberOfUpdown++; wasBackground = true; } else { if (wasBackground) { if (argb[1] < argb[2] || argb[2] < argb[3] || argb[1] == argb[3]) { } else { inside = true; } } wasBackground = false; } previous = argb; } countPerLine[y] = numberOfUpdown; } double rate = (double) count / total; double avg = 0; int countValid = 0; for (int i = 0; i < countPerLine.length; i++) { avg += countPerLine[i]; if (countPerLine[i] != 0) { countValid++; } } avg /= countValid; return new double[] { rate, avg }; } private  ImageUtils(); static ImageComparedResult compare(BufferedImage image1, Rectangle imageArea1, BufferedImage image2,
			Rectangle imageArea2, CompareOption[] options); static boolean isContained(BufferedImage entireImage, BufferedImage partImage); static double[][] calcIntegralImage(BufferedImage source); static boolean imageEquals(BufferedImage image1, BufferedImage image2); static BufferedImage getMaskedImage(BufferedImage image, List<Rectangle> maskAreas); static BufferedImage getMarkedImage(BufferedImage image, DiffPoints diffPoints); static BufferedImage getDiffImage(BufferedImage leftImage, BufferedImage rightImage, DiffPoints diffPoints); static BufferedImage trim(BufferedImage image, int trimTop, int trimLeft, int trimBottom, int trimRight); static BufferedImage verticalMerge(List<BufferedImage> images); static BufferedImage merge(List<List<BufferedImage>> images); static int[] getRGB(BufferedImage image, int width, int height); static int[] toARGB(int pixel); static int toPixel(int[] argb); static int toPixel(int r, int g, int b); static int toPixel(int a, int r, int g, int b); static int detectBackgroundColor(BufferedImage b); static boolean getObjectRectangle(BufferedImage image, Rectangle rectangle); static double norm(int pixel1, int pixel2); static double[] countSubpixel(BufferedImage bimage); static void removeRedundantRectangles(List<Rectangle> rectangles, int xLimit, int yLimit); static void removeOverlappingRectangles(List<Rectangle> rectangles); static void reshapeRect(Rectangle rectangle, int xLimit, int yLimit); static Rectangle getTightDiffArea(Rectangle rectangle, int xLimit, int yLimit); static List<Rectangle> convertObjectGroupsToAreas(List<ObjectGroup> objectGroups); static List<ObjectGroup> convertDiffPointsToObjectGroups(DiffPoints DP, int group_distance); static BufferedImage getSubImage(BufferedImage image, Rectangle rectangle); static Offset findDominantOffset(BufferedImage expectedImage, BufferedImage actualImage, double diffThreshold); static BufferedImage getDominantImage(BufferedImage expectedImage, BufferedImage actualImage, Offset offset); static int getSizeRelationType(int expectedWidth, int expectedHeight, int actualWidth, int actualHeight);  }
@Test public void testCountSubpixel() throws Exception { BufferedImage bimage = ImageIO.read(getClass().getResource("ImageUtilsTest_count_subpixel.png")); double[] expected = { 1.0, 124.01960784313725 }; double[] actual = ImageUtils.countSubpixel(bimage); assertThat(actual, is(expected)); }