/** 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); } } } }
public void checkInner(ImageFloat32 image, int c_x, int c_y, int w, int h) { ImplDescribePointPixelRegionNCC_F32 alg = new ImplDescribePointPixelRegionNCC_F32(w, h); NccFeature desc = new NccFeature(alg.getDescriptorLength()); alg.setImage(image); assertTrue(alg.isInBounds(c_x, c_y)); alg.process(c_x, c_y, desc); int y0 = c_y - h / 2; int x0 = c_x - w / 2; double mean = 0; for (int y = y0; y < y0 + h; y++) { for (int x = x0; x < x0 + w; x++) { mean += image.get(x, y); } } mean /= w * h; double variance = 0; for (int y = y0; y < y0 + h; y++) { for (int x = x0; x < x0 + w; x++) { double a = image.get(x, y) - mean; variance += a * a; } } variance /= w * h; assertEquals(desc.mean, mean, 1e-8); assertEquals(desc.sigma, Math.sqrt(variance), 1e-8); int index = 0; for (int y = y0; y < y0 + h; y++) { for (int x = x0; x < x0 + w; x++, index++) { assertEquals(image.get(x, y) - mean, desc.value[index], 1e-4); } } }
@Test public void checkIntensity() { ImageUInt8 input = new ImageUInt8(40, 50); ImageFloat32 intensity = new ImageFloat32(input.width, input.height); int[] offsets = DiscretizedCircle.imageOffsets(3, input.stride); createCircle(4, 5, offsets, minContinuous, detectDifference + 1, input); createCircle(12, 20, offsets, minContinuous, detectDifference + 10, input); alg.process(input, intensity); assertTrue(intensity.get(4, 5) < intensity.get(12, 20)); }
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)); } } }
/** * Computes the mean squared error (MSE) between the two images. * * @param imgA first image. Not modified. * @param imgB second image. Not modified. * @return error between the two images. */ public static double computeMeanSquaredError(ImageFloat32 imgA, ImageFloat32 imgB) { final int h = imgA.getHeight(); final int w = imgA.getWidth(); double total = 0; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { double difference = imgA.get(x, y) - imgB.get(x, y); total += difference * difference; } } return total / (w * h); }
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 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); }
private void shiftCopy(int offX, int offY, ImageFloat32 src, ImageFloat32 dst) { for (int y = 0; y < src.height; y++) { for (int x = 0; x < src.width; x++) { int xx = x + offX; int yy = y + offY; if (xx >= 0 && xx < src.width && yy >= 0 && yy < src.height) { dst.set(xx, yy, src.get(x, y)); } } } }
/** 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); }
/** * Checks to see if the BufferedImage has the same intensity values as the ImageUInt8 * * @param imgA BufferedImage * @param imgB ImageUInt8 */ public static void checkEquals(BufferedImage imgA, ImageFloat32 imgB, float tol) { if (imgA.getRaster() instanceof ByteInterleavedRaster && imgA.getType() != BufferedImage.TYPE_BYTE_INDEXED) { ByteInterleavedRaster raster = (ByteInterleavedRaster) imgA.getRaster(); if (raster.getNumBands() == 1) { int strideA = raster.getScanlineStride(); int offsetA = raster.getDataOffset(0) - raster.getNumBands() + 1; // handle a special case where the RGB conversion is screwed for (int i = 0; i < imgA.getHeight(); i++) { for (int j = 0; j < imgA.getWidth(); j++) { float valB = imgB.get(j, i); int valA = raster.getDataStorage()[offsetA + i * strideA + j]; valA &= 0xFF; if (Math.abs(valA - valB) > tol) throw new RuntimeException("Images are not equal: A = " + valA + " B = " + valB); } } return; } } for (int y = 0; y < imgA.getHeight(); y++) { for (int x = 0; x < imgA.getWidth(); x++) { int rgb = imgA.getRGB(x, y); float gray = (((rgb >>> 16) & 0xFF) + ((rgb >>> 8) & 0xFF) + (rgb & 0xFF)) / 3.0f; float grayB = imgB.get(x, y); if (Math.abs(gray - grayB) > tol) { throw new RuntimeException("images are not equal: A = " + gray + " B = " + grayB); } } } }
private static BufferedImage grayMagnitude( ImageFloat32 src, BufferedImage dst, float maxAbsValue) { for (int y = 0; y < src.height; y++) { for (int x = 0; x < src.width; x++) { float v = Math.abs(src.get(x, y)); int rgb = (int) (255 * v / maxAbsValue); dst.setRGB(x, y, rgb << 16 | rgb << 8 | rgb); } } return dst; }
@Test public void checkRender() { // Easier to make up a plane in this direction Se3_F64 cameraToPlane = new Se3_F64(); ConvertRotation3D_F64.eulerToMatrix( EulerType.XYZ, UtilAngle.degreeToRadian(0), 0, 0, cameraToPlane.getR()); cameraToPlane.getT().set(0, -5, 0); Se3_F64 planeToCamera = cameraToPlane.invert(null); CreateSyntheticOverheadViewMS<ImageFloat32> alg = new CreateSyntheticOverheadViewMS<ImageFloat32>( TypeInterpolate.BILINEAR, 3, ImageFloat32.class); alg.configure(param, planeToCamera, centerX, centerY, cellSize, overheadW, overheadH); MultiSpectral<ImageFloat32> input = new MultiSpectral<ImageFloat32>(ImageFloat32.class, width, height, 3); for (int i = 0; i < 3; i++) ImageMiscOps.fill(input.getBand(i), 10 + i); MultiSpectral<ImageFloat32> output = new MultiSpectral<ImageFloat32>(ImageFloat32.class, overheadW, overheadH, 3); alg.process(input, output); for (int i = 0; i < 3; i++) { ImageFloat32 o = output.getBand(i); // check parts that shouldn't be in view assertEquals(0, o.get(0, 300), 1e-8); assertEquals(0, o.get(5, 0), 1e-8); assertEquals(0, o.get(5, 599), 1e-8); // check areas that should be in view assertEquals(10 + i, o.get(499, 300), 1e-8); } }
public void checkInner(ImageFloat32 image, int c_x, int c_y, int w, int h) { ImplDescribePointPixelRegion_F32 alg = new ImplDescribePointPixelRegion_F32(w, h); TupleDesc_F32 desc = new TupleDesc_F32(alg.getDescriptorLength()); alg.setImage(image); alg.process(c_x, c_y, desc); int index = 0; int y0 = c_y - h / 2; int x0 = c_x - w / 2; for (int y = y0; y < y0 + h; y++) { for (int x = x0; x < x0 + w; x++, index++) { assertEquals(image.get(x, y), desc.value[index], 1e-4); } } }
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; }
private static BufferedImage colorizeSign( ImageFloat32 src, BufferedImage dst, float maxAbsValue) { for (int y = 0; y < src.height; y++) { for (int x = 0; x < src.width; x++) { float v = src.get(x, y); int rgb; if (v > 0) { rgb = (int) (255 * v / maxAbsValue) << 16; } else { rgb = (int) (-255 * v / maxAbsValue) << 8; } dst.setRGB(x, y, rgb); } } return dst; }
public static void process(ImageFloat32 input, ImageFloat32 output, int radius, float storage[]) { int w = 2 * radius + 1; if (storage == null) { storage = new float[w * w]; } else if (storage.length < w * w) { throw new IllegalArgumentException("'storage' must be at least of length " + (w * w)); } for (int y = 0; y < radius; y++) { int minI = y - radius; int maxI = y + radius + 1; if (minI < 0) minI = 0; if (maxI > input.height) maxI = input.height; for (int x = 0; x < input.width; x++) { int minJ = x - radius; int maxJ = x + radius + 1; // bound it ot be inside the image if (minJ < 0) minJ = 0; if (maxJ > input.width) maxJ = input.width; int index = 0; for (int i = minI; i < maxI; i++) { for (int j = minJ; j < maxJ; j++) { storage[index++] = input.get(j, i); } } // use quick select to avoid sorting the whole list float median = QuickSelectArray.select(storage, index / 2, index); output.set(x, y, median); } } for (int y = input.height - radius; y < input.height; y++) { int minI = y - radius; int maxI = y + radius + 1; if (minI < 0) minI = 0; if (maxI > input.height) maxI = input.height; for (int x = 0; x < input.width; x++) { int minJ = x - radius; int maxJ = x + radius + 1; // bound it ot be inside the image if (minJ < 0) minJ = 0; if (maxJ > input.width) maxJ = input.width; int index = 0; for (int i = minI; i < maxI; i++) { for (int j = minJ; j < maxJ; j++) { storage[index++] = input.get(j, i); } } // use quick select to avoid sorting the whole list float median = QuickSelectArray.select(storage, index / 2, index); output.set(x, y, median); } } for (int y = radius; y < input.height - radius; y++) { int minI = y - radius; int maxI = y + radius + 1; for (int x = 0; x < radius; x++) { int minJ = x - radius; int maxJ = x + radius + 1; // bound it ot be inside the image if (minJ < 0) minJ = 0; if (maxJ > input.width) maxJ = input.width; int index = 0; for (int i = minI; i < maxI; i++) { for (int j = minJ; j < maxJ; j++) { storage[index++] = input.get(j, i); } } // use quick select to avoid sorting the whole list float median = QuickSelectArray.select(storage, index / 2, index); output.set(x, y, median); } } for (int y = radius; y < input.height - radius; y++) { int minI = y - radius; int maxI = y + radius + 1; for (int x = input.width - radius; x < input.width; x++) { int minJ = x - radius; int maxJ = x + radius + 1; // bound it ot be inside the image if (minJ < 0) minJ = 0; if (maxJ > input.width) maxJ = input.width; int index = 0; for (int i = minI; i < maxI; i++) { for (int j = minJ; j < maxJ; j++) { storage[index++] = input.get(j, i); } } // use quick select to avoid sorting the whole list float median = QuickSelectArray.select(storage, index / 2, index); output.set(x, y, median); } } }