【问题标题】:How to auto crop an image white border in Java?如何在 Java 中自动裁剪图像白色边框?
【发布时间】:2012-05-27 12:38:04
【问题描述】:

在java中自动裁剪图像的白色边框的最简单方法是什么?提前谢谢...

【问题讨论】:

标签: java image-processing


【解决方案1】:

如果你想让白色部分不可见,最好的方法是使用图像过滤器并使白色像素透明,这是@PhiLho 的discussed here 有一些很好的样本, 如果你想调整你的图像大小,使它的边框不会有白色,你可以用四个简单的循环来完成, 我给你写的这个小方法可以解决问题,注意它只是裁剪图像的上部,剩下的你可以写,

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

【讨论】:

    【解决方案2】:

    这是一种裁剪所有 4 个边的方法,使用最左上角像素的颜色作为基线,并允许颜色变化的容差,这样图像中的噪点就不会使裁剪无用

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

    【讨论】:

    • 完美!非常感谢!
    • 这个公差是什么意思?
    • 容差允许仍然裁剪没有完美纯色背景颜色的图像。例如,如果您从一张纸上扫描绘图,则该纸不会显示为完全白色,而是由一系列接近白色的颜色组成。如果您尝试仅通过匹配一种特定的白色颜色来进行裁剪,则几乎不会裁剪(如果有的话)。通过允许裁剪背景颜色的一些变化,它可以删除所有不必要的周围背景,让您只剩下绘图。
    • @VinodLouis 这取决于您的用例和预期图像。对我来说,我使用 2.0,这意味着距离左上角像素颜色最多 2% 的颜色可以被容忍为可以裁剪的东西。 100% 会裁剪所有内容,0% 只会裁剪掉左上角像素的确切颜色。
    • 我认为裁剪后的图像区域在每个维度上都小 1px,因此缩放不正确:destination.getGraphics().drawImage(source, ... , topX, topY, bottomX + 1, bottomY + 1, null); 这在我的情况下产生了正确的结果。
    【解决方案3】:

    这里只是另一个例子

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

    【讨论】:

      【解决方案4】:

      img 为原始图片来源 BufferedImage subImg = img.getSubimage(0, 0, img.getWidth() - 1, img.getHeight() - 1);

      【讨论】:

        猜你喜欢
        • 2020-03-20
        • 2022-01-23
        • 1970-01-01
        • 1970-01-01
        • 2021-08-15
        • 1970-01-01
        • 2013-05-18
        • 2018-10-24
        • 2019-08-02
        相关资源
        最近更新 更多