Java - 跟踪抽象形状的轮廓并使外部像素透明

标签 java image algorithm transparency pixel

我想将两个图像分层在一起。背景和前景。前景被拼接在一起作为较小图像的网格 (3x3)。作为一种解决方法,我已经能够使所有白色像素透明,但是形状的内部是白色的,我只希望形状外部的像素透明。

例如,图像网格的每个网格位置都包含一个圆形或正方形。有没有办法可以迭代每个像素并创建两个像素位置数组 - 图像外部的像素位置数组使它们透明,图像内部的像素位置数组可以设置颜色?

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

// Stitches a grid of images together, scales a background image to fit and layers them.
public class Layer {

    public static void layerImages() {

        // Grid layout of images to stitch.
        int rows = 3;
        int cols = 3;
        int chunks = rows * cols;
        int chunckWidth, chunkHeight;

        // Image files to stitch
        File[] imgFiles = new File[chunks];

        for(int i = 0; i < chunks; i++) {
            imgFiles[i] = new File("ocarina_sprite" + (i + 1) + ".png");
        }

        // Read images into array.
        try {
            BufferedImage[] buffImages = new BufferedImage[chunks];
            for (int i = 0; i < chunks; i++) {
                buffImages[i] = ImageIO.read(imgFiles[i]);
            }

            chunckWidth = buffImages[0].getWidth();
            chunkHeight = buffImages[0].getHeight();

            BufferedImage finalImage = new BufferedImage(chunckWidth * cols, chunkHeight*rows, BufferedImage.TYPE_INT_ARGB);

            // Calculate background width and height to cover stitched image.
            int bwidth = 0;
            int bheight = 0;

            for(int i = 0; i < rows; i++) {
                bwidth += buffImages[i].getWidth();
            }
            for(int i = 0; i < cols; i++) {
                bheight += buffImages[i].getHeight();
            }

            // Background image
            File dory = new File("dory.png");
            BufferedImage original = ImageIO.read(dory);
            // Scale background image.
            BufferedImage background = scale(original, bwidth, bheight);

            // Prepare final image by drawing background first.
            Graphics2D g = finalImage.createGraphics();
            g.drawImage(background, 0, 0, null);

            // Prepare foreground image.
            BufferedImage foreground = new BufferedImage(chunckWidth * cols, chunkHeight*rows, BufferedImage.TYPE_INT_ARGB);

            // Stitch foreground images together
            int num = 0;
            for(int i = 0; i < rows; i++) {
                for(int j = 0; j < rows; j++) {
                    foreground.createGraphics().drawImage(buffImages[num],chunckWidth * j, chunkHeight * i, null);
                    num++;
                }
            }

            // Set white pixels to transparent.
            for (int y = 0; y < foreground.getHeight(); ++y) {
                for (int x = 0; x < foreground.getWidth(); ++x) {
                    int argb = foreground.getRGB(x, y);
                    if ((argb & 0xFFFFFF) > 0xFFFFEE) {
                        foreground.setRGB(x, y, 0x00FFFFFF);
                    }
                }
            }

            // Draw foreground image to final image.
            Graphics2D g3 = finalImage.createGraphics();
            g3.drawImage(foreground, 0, 0, null);


            // Output final image
            ImageIO.write(finalImage, "png", new File("finalImage.png"));
        }
        catch (Exception e) {
            System.out.println(e);
        }
    }

    // Scale image
    public static BufferedImage scale(BufferedImage imageToScale, int dWidth, int dHeight) {
        BufferedImage scaledImage = null;
        if (imageToScale != null) {
            scaledImage = new BufferedImage(dWidth, dHeight, imageToScale.getType());
            Graphics2D graphics2D = scaledImage.createGraphics();
            graphics2D.drawImage(imageToScale, 0, 0, dWidth, dHeight, null);
            graphics2D.dispose();
        }
        return scaledImage;
    }
} 

最佳答案

评论中提到的洪水填充解决方案是我解决问题所需要的,但是超过一百万个像素的递归无法解决,因此我实现了森林火灾算法,该算法使用队列而不是递归进行洪水填充。

public static void forestFire(int width, int height, int x, int y) {
        // Check if already set
        int argb = foreground.getRGB(x, y);
        if (((argb >> 24) & 0xFF) == 0) {
            return;
        }
        coords.add(new Point(x, y));

        // Set transparent pixel
        foreground.setRGB(x, y, 0x00FFFFFF);

        Point currentCoord = new Point();

        while(!coords.isEmpty()) {
            currentCoord.setLocation(coords.poll());

            // Get current coordinates
            x = (int)currentCoord.getX();
            y = (int)currentCoord.getY();

            // North
            if(y != 0) {
                int north = foreground.getRGB(x, y - 1);
                // Check if transparent (already set) and check target colour (white)
                if (((north >> 24) & 0xFF) > 0 && (north & 0xFFFFFF) > 0x111100) {
                    // Set transparent pixel
                    foreground.setRGB(x, y - 1, 0x00FFFFFF);
                    coords.add(new Point(x, y - 1));
                }
            }

            // East
            if(x != width - 1) {
                int east = foreground.getRGB(x + 1, y);
                if (((east >> 24) & 0xFF) > 0 && (east & 0xFFFFFF) > 0x111100) {
                    foreground.setRGB(x + 1, y, 0x00FFFFFF);
                    coords.add(new Point(x + 1, y));
                }
            }

            // South
            if(y != height - 1) {
                int south = foreground.getRGB(x, y + 1);
                if (((south >> 24) & 0xFF) > 0 && (south & 0xFFFFFF) > 0x111100) {
                    foreground.setRGB(x, y + 1, 0x00FFFFFF);
                    coords.add(new Point(x, y + 1));
                }
            }

            // West
            if(x != 0) {
                int west = foreground.getRGB(x - 1, y);
                if (((west >> 24) & 0xFF) > 0 && (west & 0xFFFFFF) > 0x111100) {
                    foreground.setRGB(x - 1, y, 0x00FFFFFF);
                    coords.add(new Point(x - 1, y));
                }
            }
        }

关于Java - 跟踪抽象形状的轮廓并使外部像素透明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45709418/

相关文章:

java - 用java读取hex文件并将其转换为ascii

java - 找不到导入 BlobDomain 包

python - 带反向外环的 3SUM

image - Grails将参数传递给图像

algorithm - A*搜索邻居处理说明

c# - 用于记录分析的滑动时间窗口

java - Eclipse - 运行时错误 - java.lang.NoClassDefFoundError - 无法解决

java - 您可以打开一个 jar 文件,更改一些图标,然后再次关闭它吗?

java - GWT/ eclipse : ClassNotFoundException com/google/gwt/dev/Compiler

c++ - 保存 PNG 图像