在java中通过删除透明像素将图像裁剪为最小大小

在java中通过删除透明像素将图像裁剪为最小大小,java,image,image-processing,crop,Java,Image,Image Processing,Crop,我有一张sprite表,每张图像都集中在一个32x32的单元格中。实际图像不是32x32,而是稍小一些。我想做的是取一个细胞,裁剪透明像素,使图像尽可能小 在Java(JDK 6)中我将如何做到这一点 下面是一个示例,说明我当前如何将平铺表拆分为单元格: BufferedImage tilesheet = ImageIO.read(getClass().getResourceAsStream("/sheet.png"); for (int i = 0; i < 15; i++) { I

我有一张sprite表,每张图像都集中在一个32x32的单元格中。实际图像不是32x32,而是稍小一些。我想做的是取一个细胞,裁剪透明像素,使图像尽可能小

在Java(JDK 6)中我将如何做到这一点

下面是一个示例,说明我当前如何将平铺表拆分为单元格:

BufferedImage tilesheet = ImageIO.read(getClass().getResourceAsStream("/sheet.png");
for (int i = 0; i < 15; i++) {
  Image img = tilesheet.getSubimage(i * 32, 0, 32, 32);
  // crop here..
}
buffereImage tilesheet=ImageIO.read(getClass().getResourceAsStream(“/sheet.png”);
对于(int i=0;i<15;i++){
Image img=tilesheet.getSubimage(i*32,0,32,32);
//在这里收成。。
}

我目前的想法是从中心开始测试每个像素,看看它是否透明,但我想知道是否有更快/更干净的方法。我认为这正是你应该做的,在像素阵列中循环,检查alpha,然后丢弃。尽管例如,当你有一个星号时pe它不会将图像大小调整为更小。请注意这一点。

如果您的工作表已经有透明像素,则
getSubimage()
返回的
buffereImage
也将如此。默认的
Graphics2D
AlphaComposite.SRC\u OVER
,它应该满足
drawImage()
的要求

如果子图像具有不同的背景颜色,请使用带有四分量
LookupTable
的,将alpha分量设置为零以匹配背景的颜色

我只能在万不得已的情况下遍历像素光栅


补充:超透明像素可能会干扰碰撞检测等。裁剪它们需要直接使用a。与其从中间开始,我会从边框开始,使用一对
getPixels()
/
setPixels()
可以一次修改一行或一列的方法。如果整行或整列的alpha为零,请在以后获得子图像时将其标记为消除。

此代码适用于我。算法很简单,它从图片的左/上/右/下迭代,并在列/行中找到第一个不透明的像素。然后,它将e记住修剪图片的新角点,最后返回原始图像的子图像

有些事情是可以改进的

  • 算法期望数据中有alpha字节。如果没有,它将在索引超出数组异常时失败

  • 该算法要求图片中至少有一个不透明像素。如果图片完全透明,则该算法将失败

    private static BufferedImage trimImage(BufferedImage img) {
    final byte[] pixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
    int width = img.getWidth();
    int height = img.getHeight();
    int x0, y0, x1, y1;                      // the new corners of the trimmed image
    int i, j;                                // i - horizontal iterator; j - vertical iterator
    leftLoop:
    for (i = 0; i < width; i++) {
        for (j = 0; j < height; j++) {
            if (pixels[(j*width+i)*4] != 0) { // alpha is the very first byte and then every fourth one
                break leftLoop;
            }
        }
    }
    x0 = i;
    topLoop:
    for (j = 0; j < height; j++) {
        for (i = 0; i < width; i++) {
            if (pixels[(j*width+i)*4] != 0) {
                break topLoop;
            }
        }
    }
    y0 = j;
    rightLoop:
    for (i = width-1; i >= 0; i--) {
        for (j = 0; j < height; j++) {
            if (pixels[(j*width+i)*4] != 0) {
                break rightLoop;
            }
        }
    }
    x1 = i+1;
    bottomLoop:
    for (j = height-1; j >= 0; j--) {
        for (i = 0; i < width; i++) {
            if (pixels[(j*width+i)*4] != 0) {
                break bottomLoop;
            }
        }
    }
    y1 = j+1;
    return img.getSubimage(x0, y0, x1-x0, y1-y0);
    
    专用静态BuffereImage trimImage(BuffereImage img){
    最终字节[]像素=((DataBufferByte)img.getRaster().getDataBuffer()).getData();
    int width=img.getWidth();
    int height=img.getHeight();
    int x0,y0,x1,y1;//修剪图像的新角点
    int i,j;//i-水平迭代器;j-垂直迭代器
    左循环:
    对于(i=0;i=0;i--){
    对于(j=0;j=0;j--){
    对于(i=0;i
    }

  • 有一个简单的解决方案——扫描每个像素。下面的算法具有恒定的性能
    O(w•h)

    专用静态BuffereImage trimImage(BuffereImage图像){
    int width=image.getWidth();
    int height=image.getHeight();
    int top=高度/2;
    int底部=顶部;
    int left=宽度/2;
    int right=left;
    对于(int x=0;x
    但这要有效得多:

    private static BufferedImage trimImage(BufferedImage image) {
        WritableRaster raster = image.getAlphaRaster();
        int width = raster.getWidth();
        int height = raster.getHeight();
        int left = 0;
        int top = 0;
        int right = width - 1;
        int bottom = height - 1;
        int minRight = width - 1;
        int minBottom = height - 1;
    
        top:
        for (;top < bottom; top++){
            for (int x = 0; x < width; x++){
                if (raster.getSample(x, top, 0) != 0){
                    minRight = x;
                    minBottom = top;
                    break top;
                }
            }
        }
    
        left:
        for (;left < minRight; left++){
            for (int y = height - 1; y > top; y--){
                if (raster.getSample(left, y, 0) != 0){
                    minBottom = y;
                    break left;
                }
            }
        }
    
        bottom:
        for (;bottom > minBottom; bottom--){
            for (int x = width - 1; x >= left; x--){
                if (raster.getSample(x, bottom, 0) != 0){
                    minRight = x;
                    break bottom;
                }
            }
        }
    
        right:
        for (;right > minRight; right--){
            for (int y = bottom; y >= top; y--){
                if (raster.getSample(right, y, 0) != 0){
                    break right;
                }
            }
        }
    
        return image.getSubimage(left, top, right - left + 1, bottom - top + 1);
    }
    
    专用静态BuffereImage trimImage(BuffereImage图像){
    WritableRaster raster=image.getAlphaRaster();
    int width=graster.getWidth();
    int height=graster.getHeight();
    int左=0;
    int-top=0;
    int right=宽度-1;
    内底=高度-1;
    int minRight=宽度-1;
    int minBottom=高度-1;
    顶部:
    用于(;顶部<底部;顶部++){
    对于(int x=0;x顶部;y--){
    if(光栅.getSample(左,y,0)!=0){
    minBottom=y;
    向左转;
    }
    }
    }
    底部:
    对于(;底部>最小底部;底部--){
    对于(int x=width-1;x>=left;x--){
    if(graster.getSample(x,底部,0)!=0){
    minRight=x;
    打破谷底;
    }
    }
    }
    正确的:
    对于(;right>minRight;right--){
    对于(int y=底部;y>=顶部;y--){
    if(光栅.getSample(右,y,0)!=0){
    右转;
    }
    }
    }
    返回image.getSubimage(左、上、右-le
    
    private static BufferedImage trimImage(BufferedImage image) {
        WritableRaster raster = image.getAlphaRaster();
        int width = raster.getWidth();
        int height = raster.getHeight();
        int left = 0;
        int top = 0;
        int right = width - 1;
        int bottom = height - 1;
        int minRight = width - 1;
        int minBottom = height - 1;
    
        top:
        for (;top < bottom; top++){
            for (int x = 0; x < width; x++){
                if (raster.getSample(x, top, 0) != 0){
                    minRight = x;
                    minBottom = top;
                    break top;
                }
            }
        }
    
        left:
        for (;left < minRight; left++){
            for (int y = height - 1; y > top; y--){
                if (raster.getSample(left, y, 0) != 0){
                    minBottom = y;
                    break left;
                }
            }
        }
    
        bottom:
        for (;bottom > minBottom; bottom--){
            for (int x = width - 1; x >= left; x--){
                if (raster.getSample(x, bottom, 0) != 0){
                    minRight = x;
                    break bottom;
                }
            }
        }
    
        right:
        for (;right > minRight; right--){
            for (int y = bottom; y >= top; y--){
                if (raster.getSample(right, y, 0) != 0){
                    break right;
                }
            }
        }
    
        return image.getSubimage(left, top, right - left + 1, bottom - top + 1);
    }
    
    private static BufferedImage trim(BufferedImage img) {
        int width = img.getWidth();
        int height = img.getHeight();
    
        int top = height / 2;
        int bottom = top;
    
        int left = width / 2 ;
        int right = left;
    
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                if (isFg(img.getRGB(x, y))){
    
                    top    = Math.min(top, y);
                    bottom = Math.max(bottom, y);
    
                    left   = Math.min(left, x);
                    right  = Math.max(right, x);
    
                }
            }
        }
    
        return img.getSubimage(left, top, right - left, bottom - top);
    }
    
    private static boolean isFg(int v) {
        Color c = new Color(v);
        return(isColor((c.getRed() + c.getGreen() + c.getBlue())/2));
    }
    
    private static boolean isColor(int c) {
        return c > 0 && c < 255;
    }
    
    'BufferedImage tempImg = (ImageIO.read(new File(fileNPath)));
                    WritableRaster tempRaster = tempImg.getAlphaRaster();
                    int x1 = getX1(tempRaster);
                    int y1 = getY1(tempRaster);
                    int x2 = getX2(tempRaster);
                    int y2 = getY2(tempRaster);
                    System.out.println("x1:"+x1+" y1:"+y1+" x2:"+x2+" y2:"+y2);
                    BufferedImage temp = tempImg.getSubimage(x1, y1, x2 - x1, y2 - y1);
    
                    //for idle1.png
                    String filePath = fileChooser.getCurrentDirectory() + "\\"+"testing.png";
                    System.out.println("filePath:"+filePath);
                    ImageIO.write(temp,"png",new File(filePath));
    
        for (int y = 0; y < raster.getHeight(); y++) {
            for (int x = 0; x < raster.getWidth(); x++) {
                if (raster.getSample(x, y,0) != 0) {
                    if(y>0) {
                        return y - 1;
                    }else{
                        return y;
                    }
                }
            }
        }
        return 0;
    }
    
    public int getY2(WritableRaster raster) {
        //ground plane of character
    
        for (int y = raster.getHeight()-1; y > 0; y--) {
            for (int x = 0; x < raster.getWidth(); x++) {
                if (raster.getSample(x, y,0) != 0) {
                    return y + 1;
                }
            }
        }
        return 0;
    }
    
    public int getX1(WritableRaster raster) {
        //left side of character
    
        for (int x = 0; x < raster.getWidth(); x++) {
            for (int y = 0; y < raster.getHeight(); y++) {
                if (raster.getSample(x, y,0) != 0) {
                    if(x > 0){
                        return x - 1;
                    }else{
                        return x;
                    }
                }
            }
        }
        return 0;
    }
    
    public int getX2(WritableRaster raster) {
        //right side of character
    
        for (int x = raster.getWidth()-1; x > 0; x--) {
            for (int y = 0; y < raster.getHeight(); y++) {
                if (raster.getSample(x, y,0) != 0) {
                    return x + 1;
                }
            }
        }
        return 0;
    }'[Look at Idle1.png and the minimum bounding box idle = testing.png][1]