如何在Java中自动裁剪图像白边?

10

在Java中,自动裁剪图像白边的最简单方法是什么?先行致谢...


1
尝试这个:http://stackoverflow.com/questions/273530/java-image-library-to-deskew-and-crop-images - user798182
4个回答

24

以下是一种方式可以裁剪图像的所有四个边缘,使用左上角像素的颜色作为基准,并允许颜色变化的容差,这样图像中的噪声不会使裁剪无效。

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);
}

这个“tolerence”是指什么意思? - Nishad K Ahamed
容差允许裁剪图像时背景色并非完全均匀的情况。例如,如果您从一张纸上扫描一幅图画,那么纸张不会表现出完美的白色,而是由接近白色的一系列颜色组成。如果您尝试仅通过匹配一个特定的白色色彩进行裁剪,则几乎无法裁剪任何内容。通过允许背景颜色有些变化来裁剪图像,可以去除所有不必要的周围背景,并只留下绘画部分。 - Todd
@Todd,在函数 getCroppedImage 中,公差的可接受值应该是多少? - Vinod Louis
1
@VinodLouis 这取决于您的用例和期望的图像。对我来说,我使用2.0,这意味着颜色与左上角像素的颜色相差不超过2%,被视为需要裁剪的内容。100%将裁剪所有内容,0%仅会裁剪掉左上角像素的确切颜色。 - Todd
1
我认为裁剪图像区域在每个维度上小了1像素,因此缩放不正确: destination.getGraphics().drawImage(source, ... , topX, topY, bottomX + 1, bottomY + 1, null); 这在我的情况下产生了正确的结果。 - Roben

7
如果您想让白色部分变为透明,最好的方法是使用图像过滤器并将白色像素设置为透明。@PhiLho在这里讨论了一些很好的示例。如果您想调整图像大小使边框不含白色颜色,则可以使用四个简单的循环来实现。我为您编写的这个小方法就能实现这一功能,注意它只是裁剪了图像的上部,您可以编写其余部分的代码。
    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

这里只是另一个例子

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);
}

-2

img 是原始图像源 BufferedImage subImg = img.getSubimage(0, 0, img.getWidth() - 1, img.getHeight() - 1);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接