How to auto crop an image white border in Java?

前端 未结 4 928
北荒
北荒 2020-12-15 11:04

What\'s the easiest way to auto crop the white border out of an image in java? Thanks in advance...

相关标签:
4条回答
  • 2020-12-15 11:31

    Here's a way to crop all 4 sides, using the color from the very top-left pixel as the baseline, and allow for a tolerance of color variation so that noise in the image won't make the crop useless

    public BufferedImage getCroppedImage(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();
    
       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);
    }
    
    0 讨论(0)
  • 2020-12-15 11:32

    img is original image source BufferedImage subImg = img.getSubimage(0, 0, img.getWidth() - 1, img.getHeight() - 1);

    0 讨论(0)
  • 2020-12-15 11:38

    And here just another Example

    private static BufferedImage autoCrop(BufferedImage sourceImage) {
        int left = 0;
        int right = 0;
        int top = 0;
        int bottom = 0;
        boolean firstFind = true;
        for (int x = 0; x < sourceImage.getWidth(); x++) {
            for (int y = 0; y < sourceImage.getWidth(); y++) {
                // pixel is not empty
                if (sourceImage.getRGB(x, y) != 0) {
    
                    // we walk from left to right, thus x can be applied as left on first finding
                    if (firstFind) {
                        left = x;
                    }
    
                    // update right on each finding, because x can grow only
                    right = x;
    
                    // on first find apply y as top
                    if (firstFind) {
                        top = y;
                    } else {
                        // on each further find apply y to top only if a lower has been found
                        top = Math.min(top, y);
                    }
    
                    // on first find apply y as bottom
                    if (bottom == 0) {
                        bottom = y;
                    } else {
                        // on each further find apply y to bottom only if a higher has been found
                        bottom = Math.max(bottom, y);
                    }
                    firstFind = false;
                }
            }
        }
    
        return sourceImage.getSubimage(left, top, right - left, bottom - top);
    }
    
    0 讨论(0)
  • 2020-12-15 11:42

    If you want the white parts to be invisible, best way is to use image filters and make white pixels transparent, it is discussed here by @PhiLho with some good samples, if you want to resize your image so it's borders won't have white colors, you can do it with four simple loops, this little method that I've write for you does the trick, note that it just crop upper part of image, you can write the rest,

        private Image getCroppedImage(String address) throws IOException{
        BufferedImage source = ImageIO.read(new File(address)) ;
    
        boolean flag = false ;
        int upperBorder = -1 ; 
        do{
            upperBorder ++ ;
            for (int c1 =0 ; c1 < source.getWidth() ; c1++){
                if(source.getRGB(c1, upperBorder) != Color.white.getRGB() ){
                    flag = true;
                    break ;
                }
            }
    
            if (upperBorder >= source.getHeight())
                flag = true ;
        }while(!flag) ;
    
        BufferedImage destination = new BufferedImage(source.getWidth(), source.getHeight() - upperBorder, BufferedImage.TYPE_INT_ARGB) ;
        destination.getGraphics().drawImage(source, 0, upperBorder*-1, null) ;
    
        return destination ;
    }
    
    0 讨论(0)
提交回复
热议问题