javaswingopenimaj

OpenImaj OutOfMemoryError during Resize Process


I have two photos, one zoomed in and the second a large, wide angle photo. Consider the first image a crop of the second(though it is not). I select a single pixel from each photo that represents the same thing in both pictures (say a man's nose). I overlay the first picture, with some transparency, on top of the second picture aligning the two selected pixels?

Now I want to scale the second image until the first image essentially disappears because the scale of the second image matches the scale of the first.

I am using OpenImaj and have successfully accomplished this using MBFImage.overlayInPlace(). The problem I have is that when I use ResizeProcessor to scale the second image, I get an "OutOfMemoryError: Java Heap Space" if I have to scale the second image too much ( >5x ).

I have bumped up the -Xmx to 12G using JDK 12 64bit. I have tried the ResizeProcessor, BilinearInterpolation and BicubicInterpolation resizers all with the same result.

Here is my method with my latest attempt. Depending on how much memory I give the JVM it sometimes fails on the resize, other times is fails on the toRGB():

private MBFImage scaleImage2(float scaleFactor) throws IOException {
    FImage img2Flat = image2.flatten();
    int width = (int)Math.round(img2Flat.getWidth() * scaleFactor);
    int height = (int)Math.round(img2Flat.getHeight() * scaleFactor);
    BilinearInterpolation resizer = new BilinearInterpolation(width, height, 1/scaleFactor);
    resizer.processImage(img2Flat);
    return img2Flat.toRGB();
}

Here is where I overlay the images:

private MBFImage createScaledOverlay() {
    MBFImage scaledImg2 = null;
    if(scaledLastCrop == null) {
        try {
            scaledLastCrop = scaleLastCrop();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    try {
        scaledImg2 = scaleImage2(image2ScaleFactor);
    } catch (IOException e) {
        e.printStackTrace();
    }
    int img2ScaledPixelx = Math.round(image2SelectedPixel.x * image2ScaleFactor);
    int img2ScaledPixely = Math.round(image2SelectedPixel.y * image2ScaleFactor);
    int lastCropScaledPixelx = (int)Math.round(lastCropSelectedPixel.x * lastCropScaleFactor);
    int lastCropScaledPixely = (int)Math.round(lastCropSelectedPixel.y * lastCropScaleFactor);
    scaledImg2.overlayInplace(scaledLastCrop, img2ScaledPixelx - lastCropScaledPixelx, img2ScaledPixely - lastCropScaledPixely);
    return scaledImg2;
}

I am ok with one of two paths forward:

  1. Fix OutOfMemoryError
  2. Another approach to overlay the two images

Solution

  • Sometimes a solution is so obvious it is embarrassing.

    My real goal, now that I think about it, is to find the scale factor between the two images. Instead of scaling up image2, I can scale down image1. This is much less memory intensive. Then with regards to image2 I can just invert this scale factor.