@Test public void compareToWaveletTransformOps() { GrayS32 orig = new GrayS32(width, height); GImageMiscOps.fillUniform(orig, rand, 0, 20); GrayS32 origCopy = orig.clone(); int N = 3; ImageDimension dimen = UtilWavelet.transformDimension(orig, N); GrayS32 found = new GrayS32(dimen.width, dimen.height); GrayS32 expected = new GrayS32(dimen.width, dimen.height); WaveletDescription<WlCoef_I32> desc = FactoryWaveletDaub.biorthogonal_I32(5, BorderType.REFLECT); GrayS32 storage = new GrayS32(dimen.width, dimen.height); WaveletTransformOps.transformN(desc, orig.clone(), expected, storage, N); WaveletTransformInt<GrayS32> alg = new WaveletTransformInt<>(desc, N, 0, 255, GrayS32.class); alg.transform(orig, found); // make sure the original input was not modified like it is in WaveletTransformOps BoofTesting.assertEquals(origCopy, orig, 0); // see if the two techniques produced the same results BoofTesting.assertEquals(expected, found, 0); // test inverse transform GrayS32 reconstructed = new GrayS32(width, height); alg.invert(found, reconstructed); BoofTesting.assertEquals(orig, reconstructed, 0); // make sure the input has not been modified BoofTesting.assertEquals(expected, found, 0); }
/** * 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); } }
/** Checks to see if the two ways of specifying interpolation work */ @Test public void scale_InterpTypeStyle() { ImageFloat32 input = new ImageFloat32(width, height); ImageFloat32 output = new ImageFloat32(width, height); GImageMiscOps.fillUniform(input, rand, 0, 100); DistortImageOps.scale(input, output, TypeInterpolate.BILINEAR); InterpolatePixel<ImageFloat32> interp = FactoryInterpolation.bilinearPixel(input); interp.setImage(input); float scaleX = (float) input.width / (float) output.width; float scaleY = (float) input.height / (float) output.height; if (input.getTypeInfo().isInteger()) { for (int i = 0; i < output.height; i++) { for (int j = 0; j < output.width; j++) { float val = interp.get(j * scaleX, i * scaleY); assertEquals((int) val, output.get(j, i), 1e-4); } } } else { for (int i = 0; i < output.height; i++) { for (int j = 0; j < output.width; j++) { float val = interp.get(j * scaleX, i * scaleY); assertEquals(val, output.get(j, i), 1e-4); } } } }
/** See how well it processes an image which is not an GrayS32 */ @Test public void checkOtherType() { GrayS32 orig = new GrayS32(width, height); GImageMiscOps.fillUniform(orig, rand, 0, 20); GrayU8 orig8 = ConvertImage.convert(orig, (GrayU8) null); int N = 3; ImageDimension dimen = UtilWavelet.transformDimension(orig, N); GrayS32 found = new GrayS32(dimen.width, dimen.height); GrayS32 expected = new GrayS32(dimen.width, dimen.height); WaveletDescription<WlCoef_I32> desc = FactoryWaveletDaub.biorthogonal_I32(5, BorderType.REFLECT); GrayS32 storage = new GrayS32(dimen.width, dimen.height); WaveletTransformOps.transformN(desc, orig.clone(), expected, storage, N); WaveletTransformInt<GrayU8> alg = new WaveletTransformInt<>(desc, N, 0, 255, GrayU8.class); alg.transform(orig8, found); // see if the two techniques produced the same results BoofTesting.assertEquals(expected, found, 0); // see if it can convert it back GrayU8 reconstructed = new GrayU8(width, height); alg.invert(found, reconstructed); BoofTesting.assertEquals(orig8, reconstructed, 0); // make sure the input has not been modified BoofTesting.assertEquals(expected, found, 0); }
/** See if accessing the image edge causes it to blow up. */ @Test public void get_edges() { T img = createImage(width, height); GImageMiscOps.fillUniform(img, rand, 0, 100); BoofTesting.checkSubImage(this, "get_edges", false, img); }
@Test public void rgbToLab_F32() { MultiSpectral<ImageFloat32> input = new MultiSpectral<ImageFloat32>(ImageFloat32.class, 20, 25, 3); MultiSpectral<ImageFloat32> output = new MultiSpectral<ImageFloat32>(ImageFloat32.class, 20, 25, 3); GImageMiscOps.fillUniform(input, rand, 0, 255); ColorLab.rgbToLab_F32(input, output); float expected[] = new float[3]; for (int y = 0; y < input.height; y++) { for (int x = 0; x < input.width; x++) { float R = input.getBand(0).get(x, y); float G = input.getBand(1).get(x, y); float B = input.getBand(2).get(x, y); ColorLab.srgbToLab(R / 255f, G / 255f, B / 255f, expected); float L = output.getBand(0).get(x, y); float A = output.getBand(1).get(x, y); float B_ = output.getBand(2).get(x, y); assertEquals(expected[0], L, 1e-4f); assertEquals(expected[1], A, 1e-4f); assertEquals(expected[2], B_, 1e-4f); } } }
/** The XY and YX second derivatives should be indential */ private void testSecondDerivative(Method m1, Method m2) { Class params[] = m1.getParameterTypes(); ImageGray input = GeneralizedImageOps.createSingleBand(params[0], width, height); ImageGray derivX = GeneralizedImageOps.createSingleBand(params[1], width, height); ImageGray derivY = GeneralizedImageOps.createSingleBand(params[2], width, height); ImageGray derivXX = GeneralizedImageOps.createSingleBand(params[1], width, height); ImageGray derivYY = GeneralizedImageOps.createSingleBand(params[2], width, height); ImageGray derivXY = GeneralizedImageOps.createSingleBand(params[1], width, height); ImageGray derivYX = GeneralizedImageOps.createSingleBand(params[1], width, height); GImageMiscOps.fillUniform(input, rand, 0, 40); Object border; if (params[3] == ImageBorder_F32.class) { border = new ImageBorder1D_F32(BorderIndex1D_Wrap.class); } else { border = new ImageBorder1D_S32(BorderIndex1D_Wrap.class); } try { m1.invoke(null, input, derivX, derivY, border); m2.invoke(null, derivX, derivXX, derivXY, border); m2.invoke(null, derivY, derivYX, derivYY, border); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } // BoofTesting.printDiff(derivXY,derivYX); BoofTesting.assertEquals(derivXY, derivYX, 1e-3f); }
/** * Compare to a simplistic implementation of stereo disparity. Need to turn off special * configurations */ @Test public void compareToNaive() { int w = 20, h = 25; Image left = GeneralizedImageOps.createSingleBand(imageType, w, h); Image right = GeneralizedImageOps.createSingleBand(imageType, w, h); if (left.getDataType().isSigned()) { GImageMiscOps.fillUniform(left, rand, -20, 20); GImageMiscOps.fillUniform(right, rand, -20, 20); } else { GImageMiscOps.fillUniform(left, rand, 0, 20); GImageMiscOps.fillUniform(right, rand, 0, 20); } int radiusX = 3; int radiusY = 2; // compare to naive with different settings compareToNaive(left, right, 0, 10, radiusX, radiusY); compareToNaive(left, right, 4, 10, radiusX, radiusY); }
@Test public void basicTrackingCheck() { ImageFloat32 a = new ImageFloat32(30, 35); ImageFloat32 b = new ImageFloat32(30, 35); // randomize input image and move it GImageMiscOps.fillUniform(a, rand, 0, 200); GImageMiscOps.fillUniform(b, rand, 0, 200); CirculantTracker<ImageFloat32> alg = new CirculantTracker<ImageFloat32>(1f / 16, 0.2, 1e-2, 0.075, 1.0, 64, 255, interp); alg.initialize(a, 5, 6, 20, 25); shiftCopy(2, 4, a, b); alg.performTracking(b); double tolerance = 1; Rectangle2D_F32 r = alg.getTargetLocation(); assertEquals(5 + 2, r.x0, tolerance); assertEquals(6 + 4, r.y0, tolerance); }
/** * Interpolates the whole image and sees if the values returned are within the specified bounds */ @Test public void checkPixelValueBoundsHonored() { T img = createImage(20, 30); GImageMiscOps.fillUniform(img, rand, 0, 100); InterpolatePixel<T> interp = wrap(img, 0, 100); for (int y = 0; y < img.height; y++) { for (int x = 0; x < img.width; x++) { float v = interp.get(x, y); assertTrue(v >= 0 && v <= 100); } } }
/** * Check a few simple motions. It seems to be accurate to within 1 pixel. Considering alphas seems * to be the issue */ @Test public void updateTrackLocation() { ImageFloat32 a = new ImageFloat32(100, 100); ImageFloat32 b = new ImageFloat32(100, 100); // randomize input image and move it GImageMiscOps.fillUniform(a, rand, 0, 200); GImageMiscOps.fillUniform(b, rand, 0, 200); shiftCopy(0, 0, a, b); CirculantTracker<ImageFloat32> alg = new CirculantTracker<ImageFloat32>(1f / 16, 0.2, 1e-2, 0.075, 1.0, 64, 255, interp); alg.initialize(a, 5, 6, 20, 25); alg.updateTrackLocation(b); // only pixel level precision. float tolerance = 1f; // No motion motion Rectangle2D_F32 r = alg.getTargetLocation(); assertEquals(5, r.x0, tolerance); assertEquals(6, r.y0, tolerance); // check estimated motion GImageMiscOps.fillUniform(b, rand, 0, 200); shiftCopy(-3, 2, a, b); alg.updateTrackLocation(b); r = alg.getTargetLocation(); assertEquals(5 - 3, r.x0, tolerance); assertEquals(6 + 2, r.y0, tolerance); // try out of bounds case GImageMiscOps.fillUniform(b, rand, 0, 200); shiftCopy(-6, 0, a, b); alg.updateTrackLocation(b); assertEquals(5 - 6, r.x0, tolerance); assertEquals(6, r.y0, tolerance); }
/** Try the same get at a few border points and see if anything blows up */ @Test public void checkSafeGetAlongBorder() { T img = createImage(width, height); GImageMiscOps.fillUniform(img, rand, 0, 100); InterpolatePixel<T> interp = wrap(img, 0, 100); // will it blow up? interp.get(0, 0); interp.get(width / 2, 0); interp.get(0, height / 2); interp.get(width - 1, height - 1); interp.get(width / 2, height - 1); interp.get(width - 1, height / 2); }
private void checUpSample(int w, int h) { ImageFloat32 input = new ImageFloat32(w, h); ImageFloat32 output = new ImageFloat32(w * 2, h * 2); GImageMiscOps.fillUniform(input, rand, 0, 100); SiftImageScaleSpace.upSample(input, output); for (int i = 0; i < output.height; i++) { for (int j = 0; j < output.width; j++) { assertTrue(input.get(j / 2, i / 2) == output.get(j, i)); } } }
/** * Scans through the whole image and for each pixel which is "safe" it compares the safe value to * the unsafe value. */ @Test public void isInSafeBounds() { T img = createImage(width, height); GImageMiscOps.fillUniform(img, rand, 0, 100); InterpolatePixel<T> interp = wrap(img, 0, 100); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (interp.isInSafeBounds(x, y)) { float a = interp.get(x, y); float b = interp.get_unsafe(x, y); assertEquals(a, b, 1e-4); } } } }
/** Checks to see if it blows up when processing features */ @Test public void basicSanityCheck() { GrayU8 input = new GrayU8(30, 40); GImageMiscOps.fillUniform(input, rand, 0, 100); BlurFilter<GrayU8> filterBlur = FactoryBlurFilter.gaussian(GrayU8.class, -1, 1); Helper helper = new Helper(); DescribePointBrief<GrayU8> alg = new DescribePointBrief<>(helper, filterBlur); alg.setImage(input); alg.process(15, 20, null); assertEquals(1, helper.numInside); assertEquals(0, helper.numOutside); alg.process(0, 0, null); assertEquals(1, helper.numInside); assertEquals(1, helper.numOutside); }
@Test public void scaleSanityCheck() { ImageFloat32 input = new ImageFloat32(width, height); ImageFloat32 output = new ImageFloat32(width / 2, height / 2); GImageMiscOps.fillUniform(input, rand, 0, 100); DistortImageOps.scale(input, output, TypeInterpolate.BILINEAR); double error = 0; for (int y = 0; y < output.height; y++) { for (int x = 0; x < output.width; x++) { double e = input.get(x * 2, y * 2) - output.get(x, y); error += Math.abs(e); } } assertTrue(error / (output.width * output.height) < 0.1); }
/** Very simple test for rotation accuracy. */ @Test public void rotate_SanityCheck() { ImageFloat32 input = new ImageFloat32(width, height); ImageFloat32 output = new ImageFloat32(height, width); GImageMiscOps.fillUniform(input, rand, 0, 100); DistortImageOps.rotate(input, output, TypeInterpolate.BILINEAR, (float) Math.PI / 2f); double error = 0; // the outside pixels are ignored because numerical round off can cause those to be skipped for (int y = 1; y < input.height - 1; y++) { for (int x = 1; x < input.width - 1; x++) { int xx = output.width - y; int yy = x; double e = input.get(x, y) - output.get(xx, yy); error += Math.abs(e); } } assertTrue(error / (width * height) < 0.1); }
@Test public void compareToNaiveDetection() { ImageUInt8 input = new ImageUInt8(40, 50); GImageMiscOps.fillUniform(input, rand, 0, 50); ImageFloat32 intensity = new ImageFloat32(input.width, input.height); DetectorFastNaive validator = new DetectorFastNaive(3, minContinuous, detectDifference); validator.process(input); alg.process(input, intensity); assertEquals(validator.getCandidates().size, alg.getCandidates().size); for (int i = 0; i < validator.getCandidates().size(); i++) { Point2D_I16 v = validator.getCandidates().get(i); Point2D_I16 a = alg.getCandidates().get(i); assertEquals(v.x, a.x); assertEquals(v.y, a.y); } }
/** 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 void dense_gauss_kernel(int offX, int offY) { ImageFloat64 region = new ImageFloat64(32, 32); ImageFloat64 target = new ImageFloat64(32, 32); ImageFloat64 k = new ImageFloat64(32, 32); CirculantTracker<ImageFloat32> alg = new CirculantTracker<ImageFloat32>(1f / 16, 0.2, 1e-2, 0.075, 1.0, 32, 255, interp); alg.initialize(new ImageFloat32(32, 32), 0, 0, 32, 32); // create a shape inside the image GImageMiscOps.fillRectangle(region, 200, 10, 15, 5, 7); // copy a shifted portion of the region shiftCopy(offX, offY, region, target); // process and see if the peak is where it should be alg.dense_gauss_kernel(0.2f, region, target, k); int maxX = -1, maxY = -1; double maxValue = -1; for (int y = 0; y < k.height; y++) { for (int x = 0; x < k.width; x++) { if (k.get(x, y) > maxValue) { maxValue = k.get(x, y); maxX = x; maxY = y; } } } int expectedX = k.width / 2 - offX; int expectedY = k.height / 2 - offY; assertEquals(expectedX, maxX); assertEquals(expectedY, maxY); }