Java - 跟踪抽象形状的轮廓并使外部像素透明
Posted
技术标签:
【中文标题】Java - 跟踪抽象形状的轮廓并使外部像素透明【英文标题】:Java - Tracing outline of abstract shapes and making outer pixels transparent 【发布时间】:2017-08-16 09:07:22 【问题描述】:我想将两张图片叠加在一起。背景和前景。前景被拼接为较小图像的网格 (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;
【问题讨论】:
我猜你可以floodfill图像的外部区域,将边界条件设置为遇到非白色像素时 为什么不能在编辑器中手动预处理前景图像以利用 Alpha 通道? 感谢 cmets。 Floodfill 正是我想要的,我编写了一个递归算法来使边界周围的像素透明。唯一的问题是我得到了一个***。有任何想法吗?我在开始时进行检查,以确保我没有两次覆盖同一个像素,只是向北、南、东和西移动以检查边界。 【参考方案1】:评论中提到的洪水填充解决方案是我解决问题所需要的,但是超过一百万像素的递归没有解决,所以我实现了森林火灾算法,它使用队列而不是递归进行洪水填充。
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 - 跟踪抽象形状的轮廓并使外部像素透明的主要内容,如果未能解决你的问题,请参考以下文章