-3

This question is linked to the following method for auto-cropping : https://stackoverflow.com/a/12645803/7623700

I get the following exception when attempting to run the following Java code in Eclipse:

     Exception in thread "main" java.lang.IllegalArgumentException: Width (-2147483647) and height (-2147483647) cannot be <= 0
at java.awt.image.DirectColorModel.createCompatibleWritableRaster(Unknown Source)
at java.awt.image.BufferedImage.<init>(Unknown Source)
at getCroppedImage.getCropImage(getCroppedImage.java:44)
at getCroppedImage.<init>(getCroppedImage.java:16)
at getCroppedImage.main(getCroppedImage.java:79)

The code has worked for others, so i suppose the problem may lie with the way I'm attempting to use it, here is my code:

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class getCroppedImage {
    getCroppedImage() throws IOException{
    String imagePath = "C:\\Users\\lah\\workspace\\Testing\\images";
    BufferedImage image = ImageIO.read(new   File("C:\\Users\\lah\\workspace\\Testing\\images\\image1.jpg"));

    BufferedImage resultImage1 = getCropImage(image,2.0);
    File outFile1 = new File(imagePath, "croppedimage.png");
    ImageIO.write(resultImage1, "PNG", outFile1);
    }

//start of original method in the above link
public BufferedImage getCropImage(BufferedImage source, double tolerance) {
       // Get our top-left pixel color as our "baseline" for cropping 
        int baseColor = source.getRGB(0, 0);
       int width = source.getWidth();
       int height = source.getHeight();
       //System.out.println(width+" "+height);
       int topY = Integer.MAX_VALUE, topX = Integer.MAX_VALUE;
       int bottomY = -1, bottomX = -1;
       for(int y=0; y<height; y++) {
          for(int x=0; x<width; x++) {
             if (colorWithinTolerance(baseColor, source.getRGB(x, y), tolerance)) {
                if (x < topX) topX = x;
                if (y < topY) topY = y;
                if (x > bottomX) bottomX = x;
                if (y > bottomY) bottomY = y;

             }
          }
       }
       BufferedImage destination = new BufferedImage( (bottomX-topX+1), 
                     (bottomY-topY+1), BufferedImage.TYPE_INT_ARGB);

       destination.getGraphics().drawImage(source, 0, 0, 
                   destination.getWidth(), destination.getHeight(), 
                   topX, topY, bottomX, bottomY, null);

       return destination;
    }

    private boolean colorWithinTolerance(int a, int b, double tolerance) {
        int aAlpha  = (int)((a & 0xFF000000) >>> 24);   // Alpha level
        int aRed    = (int)((a & 0x00FF0000) >>> 16);   // Red level
        int aGreen  = (int)((a & 0x0000FF00) >>> 8);    // Green level
        int aBlue   = (int)(a & 0x000000FF);            // Blue level

        int bAlpha  = (int)((b & 0xFF000000) >>> 24);   // Alpha level
        int bRed    = (int)((b & 0x00FF0000) >>> 16);   // Red level
        int bGreen  = (int)((b & 0x0000FF00) >>> 8);    // Green level
        int bBlue   = (int)(b & 0x000000FF);            // Blue level

        double distance = Math.sqrt((aAlpha-bAlpha)*(aAlpha-bAlpha) +
                                    (aRed-bRed)*(aRed-bRed) +
                                    (aGreen-bGreen)*(aGreen-bGreen) +
                                    (aBlue-bBlue)*(aBlue-bBlue));

        // 510.0 is the maximum distance between two colors 
        // (0,0,0,0 -> 255,255,255,255)
        double percentAway = distance / 510.0d;     

        return (percentAway > tolerance);
    }
    // end of original method in the above link
    public static void main(String[] args) throws IOException {
        getCroppedImage ci = new getCroppedImage();

    }
}

What could be causing the error? Any help is much appreciated.

Community
  • 1
  • 1
lahronin
  • 1
  • 1
  • I'm voting to close this question as a typo. OP, when you want to check if a value is in range of a certain tolerance, then you should check if that value is _lower_, not _higher_. – Tom Feb 26 '17 at 04:03

2 Answers2

0

I have ran your code and getting the error in the following line.

BufferedImage destination = new BufferedImage((bottomX - topX + 1),
                (bottomY - topY + 1), BufferedImage.TYPE_INT_ARGB);

When I add a print statement before this line as follows.

System.out.println((bottomX - topX + 1) + " " + (bottomY - topY + 1));

It printed - -2147483647 -2147483647. Then I saw, you have initialized topY and topX as follows.

int topY = Integer.MAX_VALUE, topX = Integer.MAX_VALUE;

Actually none of the variables - topX, topY, bottomX and bottomY are not getting updated because the following if condition never evaluates to True.

if (colorWithinTolerance(baseColor, source.getRGB(x, y), tolerance)) {
    // your code goes here
}

When I checked your colorWithinTolerance() function, I found the following problem.

private boolean colorWithinTolerance(int a, int b, double tolerance) {
    // your code
    return (percentAway > tolerance);
}

This condition should be - percentAway < tolerance. Because if percentAway is greater than tolerance, then your function should return False as you are checking if the distance is in range of the given tolerance limit.

I wrote my debugging process so that you can debug your code of your own from next time.

Wasi Ahmad
  • 35,739
  • 32
  • 114
  • 161
  • Hi i did check this, the width and height is not negative prior to triggering the problematic code. As in, if i were to print the width and height just before entering the if colour tolerance line that is causing the problem, it is not negative nor zero – lahronin Feb 26 '17 at 03:51
  • I have also tried with different image files with the same problem, could the problem be the way i'm reading the image files? – lahronin Feb 26 '17 at 03:52
  • can you mention in which line you are getting the error? – Wasi Ahmad Feb 26 '17 at 03:52
  • The "if (colorWithinTolerance(baseColor, source.getRGB(x, y), tolerance)) " is causing the problem – lahronin Feb 26 '17 at 03:55
  • @lahronin You're right, it's the `if` statement *(indirectly)*, because if the **condition is never `true`**, then `topY` and `bottomY` keep their initial values, so `bottomY - topY + 1` = `-1 - MAX_VALUE + 1` = `-MAX_VALUE` = `-2147483647`, which is what you see. *Oops!!* – Andreas Feb 26 '17 at 04:05
  • Thank you for the feedback. Now an image file can be written, but it simply distorts the color rather than cropping as intended, no cropping is done in fact. I don't suppose this has anything to do with the change, but rather the algorithm itself? – lahronin Feb 26 '17 at 04:37
  • @lahronin you are right. then you need to investigate the algorithm. – Wasi Ahmad Feb 26 '17 at 04:45
0

An explanation of the algorithm:

the algorithm takes the top-left point as being white and finds all pixels that are at least tolerance% different (away >) from it: this will result in the area that is different from white and since you want to crop out the white that should be your valid area.

The only problem is that tolerance should be a percent since

percentAway = distance / 510.0d

cannot be more than one (it's a normalized quantity of the distance of colors).

Therefore if you define tolerance as a decimal

for example

BufferedImage resultImage1 = getCropImage(image, 0.2);

should work.

(with the condition kept at percentAway > tolerance )

gpasch
  • 2,672
  • 3
  • 10
  • 12
  • Thank you for your explanation, I'm new to image processing and your comment certainly helped. Cropping does happen now, but I don't quite understand why is the output picture distorted, since the color tolerance portion is just meant to help determine the new x and y coordinates, I don't see how the code causes the colors to change? – lahronin Feb 27 '17 at 10:25
  • Just to give some context, I'm trying to crop out documents from photographs of documents, perhaps this was not the intended purpose. Nevertheless, do you think making a copy instead to determine the coordinates, before applying the new coordinates on the original would resolve this? Or converting this copy to black and white/ greyscale first would enhance accuracy? – lahronin Feb 27 '17 at 10:28