@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);
  }
示例#6
0
  @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);
  }
示例#13
0
  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);
  }
示例#16
0
  @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);
  }
示例#17
0
  /** 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);
    }
  }
示例#19
0
  /** 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);
  }