/** * The number of octaves is too large for input image and should stop processing before it gets * too small */ @Test public void smallImages() { SiftImageScaleSpace ss = new SiftImageScaleSpace(1.6f, 5, 4, false); ImageFloat32 input = new ImageFloat32(10, 15); GImageMiscOps.fillUniform(input, rand, 0, 100); ss.constructPyramid(input); ss.computeFeatureIntensity(); ss.computeDerivatives(); assertEquals(2, ss.actualOctaves); // images in rest of the octaves should be zero int index = 3 * 5; for (; index < ss.scale.length; index++) { ImageFloat32 s = ss.scale[index]; ImageFloat32 gx = ss.derivX[index]; ImageFloat32 gy = ss.derivY[index]; assertTrue(ImageStatistics.sum(s) == 0); assertTrue(ImageStatistics.sum(gx) == 0); assertTrue(ImageStatistics.sum(gy) == 0); } index = 3 * 4; for (; index < ss.dog.length; index++) { ImageFloat32 dog = ss.dog[index]; assertTrue(ImageStatistics.sum(dog) == 0); } }
public static BufferedImage standard(ImageSingleBand<?> src, BufferedImage dst) { if (src.getDataType().isInteger()) { ImageInteger srcInt = (ImageInteger) src; if (src.getDataType().isSigned()) { double max = GImageStatistics.maxAbs(srcInt); return colorizeSign(srcInt, dst, (int) max); } else { if (src.getDataType().getNumBits() == 8) { dst = ConvertBufferedImage.convertTo((ImageUInt8) src, dst); } else { double max = GImageStatistics.maxAbs(srcInt); dst = grayUnsigned(srcInt, dst, (int) max); } } } else if (ImageFloat32.class.isAssignableFrom(src.getClass())) { ImageFloat32 img = (ImageFloat32) src; float max = ImageStatistics.maxAbs(img); boolean hasNegative = false; for (int i = 0; i < img.getHeight(); i++) { for (int j = 0; j < img.getWidth(); j++) { if (img.get(j, i) < 0) { hasNegative = true; break; } } } if (hasNegative) return colorizeSign(img, dst, (int) max); else return grayMagnitude((ImageFloat32) src, dst, max); } return dst; }
@Test public void performLearning() { float interp_factor = 0.075f; ImageFloat32 a = new ImageFloat32(20, 25); ImageFloat32 b = new ImageFloat32(20, 25); ImageMiscOps.fill(a, 100); ImageMiscOps.fill(b, 200); CirculantTracker<ImageFloat32> alg = new CirculantTracker<ImageFloat32>(1f / 16, 0.2, 1e-2, 0.075, 1.0, 64, 255, interp); alg.initialize(a, 0, 0, 20, 25); // copy its internal value ImageFloat64 templateC = new ImageFloat64(alg.template.width, alg.template.height); templateC.setTo(alg.template); // give it two images alg.performLearning(b); // make sure the images aren't full of zero assertTrue(Math.abs(ImageStatistics.sum(templateC)) > 0.1); assertTrue(Math.abs(ImageStatistics.sum(alg.template)) > 0.1); int numNotSame = 0; // the result should be an average of the two for (int i = 0; i < a.data.length; i++) { if (Math.abs(a.data[i] - alg.templateNew.data[i]) > 1e-4) numNotSame++; // should be more like the original one than the new one double expected = templateC.data[i] * (1 - interp_factor) + interp_factor * alg.templateNew.data[i]; double found = alg.template.data[i]; assertEquals(expected, found, 1e-4); } // make sure it is actually different assertTrue(numNotSame > 100); }
/** Process two images, one is a sub-image of the first. See if it produces the same results */ @Test public void checkSubImage() { SiftImageScaleSpace ss1 = new SiftImageScaleSpace(1.6f, 5, 4, false); SiftImageScaleSpace ss2 = new SiftImageScaleSpace(1.6f, 5, 4, false); ImageFloat32 input = new ImageFloat32(60, 70); GImageMiscOps.fillUniform(input, rand, 0, 100); ImageFloat32 sub = BoofTesting.createSubImageOf(input); ss1.constructPyramid(input); ss2.constructPyramid(sub); for (int index = 0; index < ss1.scale.length; index++) { ImageFloat32 s1 = ss1.scale[index]; ImageFloat32 s2 = ss2.scale[index]; float sum1 = ImageStatistics.sum(s1); float sum2 = ImageStatistics.sum(s2); assertTrue(sum1 != 0); assertEquals(sum1, sum2, 1e-6); } }
public static BufferedImage graySign(ImageFloat32 src, BufferedImage dst, float maxAbsValue) { dst = checkInputs(src, dst); if (maxAbsValue < 0) maxAbsValue = ImageStatistics.maxAbs(src); for (int y = 0; y < src.height; y++) { for (int x = 0; x < src.width; x++) { float v = src.get(x, y); int rgb = 127 + (int) (127 * v / maxAbsValue); dst.setRGB(x, y, rgb << 16 | rgb << 8 | rgb); } } return dst; }
/** Fits polygons to found contours around binary blobs. */ public static void fitBinaryImage(ImageFloat32 input) { ImageUInt8 binary = new ImageUInt8(input.width, input.height); BufferedImage polygon = new BufferedImage(input.width, input.height, BufferedImage.TYPE_INT_RGB); // the mean pixel value is often a reasonable threshold when creating a binary image double mean = ImageStatistics.mean(input); // create a binary image by thresholding ThresholdImageOps.threshold(input, binary, (float) mean, true); // reduce noise with some filtering ImageUInt8 filtered = BinaryImageOps.erode8(binary, null); filtered = BinaryImageOps.dilate8(filtered, null); // Find the contour around the shapes List<Contour> contours = BinaryImageOps.contour(filtered, 8, null); // Fit a polygon to each shape and draw the results Graphics2D g2 = polygon.createGraphics(); g2.setStroke(new BasicStroke(2)); for (Contour c : contours) { // Fit the polygon to the found external contour. Note loop = true List<PointIndex_I32> vertexes = ShapeFittingOps.fitPolygon(c.external, true, toleranceDist, toleranceAngle, 100); g2.setColor(Color.RED); VisualizeShapes.drawPolygon(vertexes, true, g2); // handle internal contours now g2.setColor(Color.BLUE); for (List<Point2D_I32> internal : c.internal) { vertexes = ShapeFittingOps.fitPolygon(internal, true, toleranceDist, toleranceAngle, 100); VisualizeShapes.drawPolygon(vertexes, true, g2); } } ShowImages.showWindow(polygon, "Binary Blob Contours"); }