Possible Duplicate:
PySide: Separating a spritesheet / Separating an image into contiguous regions of color
给定一个具有透明像素的 .png 图像和一个由各个动画帧组成的网格(其中最后一行不需要填满),您如何自动找到每个单独帧的尺寸,并检测 .png 图像中有多少帧。 .png?
我正在尝试转换 Glitch 创意共享宝库中的资源转换为我们的内部格式,但我在将帧信息与原始 .png 分离时遇到问题。
(由 Glitch 根据 http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US 许可证发布)
在这种情况下,我可以发现框架是 189 x 230 px;但查找此内容需要时间,并且可能有很多图像需要查找。
我想将图像分割成帧,以便在 Java Swing 桌面应用程序中使用。我可以使用 ImageIO
加载图像进入BufferedImage
,并轻松检查像素透明度。只有几种可能的帧大小:给定示例中的 945x690 帧,并假设最小边长为 50px,唯一合理的帧宽度是 5 x 189(正确)、7 x 135 或 9 x 105。
那么,如何找到框架尺寸?这不需要非常高效,因为资源转换是一次性问题。伪代码答案很好;我最感兴趣的是算法。
注意: PySide: Separating a spritesheet / Separating an image into contiguous regions of color解释如何处理非动画 Sprite 表,其中包含不规则大小的图像。我对检测行 x 列感兴趣,这可以用更简单的算法来解决(请参阅接受的答案)。
最佳答案
由于所有图像均由单一颜色构成,因此您可以在较大图像的列和行中查找“框架边框颜色”条。
使用获得的列数和行数与图像尺寸(宽 x 高)的关系来确定每个子图像的像素尺寸。
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.net.*;
import java.net.URL;
import java.util.ArrayList;
import javax.imageio.ImageIO;
class TileSetUtility {
/** Divide the tile into tiles based on the number of cols & rows
* supplied. Exclude any images that are a solid color. */
public static ArrayList<BufferedImage> getTiles(
BufferedImage tile, int cols, int rows) {
int w = tile.getWidth();
int h = tile.getHeight();
int wT = w / cols;
int hT = h / rows;
if (wT * cols != w || hT * rows != h) {
throw new IllegalArgumentException("Tile is not an even " +
"multiple of pixels of WxCols or HxRows!");
}
ArrayList<BufferedImage> tiles = new ArrayList<BufferedImage>();
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
BufferedImage i = tile.getSubimage(x * wT, y * hT, wT, hT);
if (!isImageSolidColor(i)) {
tiles.add(i);
}
}
}
return tiles;
}
/** Takes an image that represents tiles of a tile set, and infers the
* number of columns based on the assumption that the color at 0x0 in the
* image represents a border color or frame for the contained tiles. */
public static int inferNumberColumns(BufferedImage img) {
boolean[] columnClear = new boolean[img.getWidth()];
// after this loop, we should have a series of contiguous regions
// of 'true' in the array.
for (int ii = 0; ii < columnClear.length; ii++) {
columnClear[ii] = isLineEmpty(img, ii, false);
}
return countContiguousRegions(columnClear);
}
/** Takes an image that represents tiles of a tile set, and infers the
* number of rows based on the assumption that the color at 0x0 in the
* image represents a border color or frame for the contained tiles. */
public static int inferNumberRows(BufferedImage img) {
boolean[] columnClear = new boolean[img.getHeight()];
// after this loop, we should have a series of contiguous regions
// of 'true' in the array.
for (int ii = 0; ii < columnClear.length; ii++) {
columnClear[ii] = isLineEmpty(img, ii, true);
}
return countContiguousRegions(columnClear);
}
/** Count the number of contiguous regions of 'true' */
public static int countContiguousRegions(boolean[] array) {
boolean newRegion = false;
int count = 0;
for (boolean bool : array) {
if (bool) {
if (newRegion) {
count++;
}
newRegion = false;
} else {
newRegion = true;
}
}
return count;
}
/** Determine if this entire column or row of image pixels is empty. */
public static boolean isLineEmpty(
BufferedImage img, int pos, boolean row) {
if (!row) {
for (int y = 0; y < img.getHeight(); y++) {
if (img.getRGB(pos, y) != img.getRGB(0, 0)) {
return false;
}
}
} else {
for (int x = 0; x < img.getWidth(); x++) {
if (img.getRGB(x, pos) != img.getRGB(0, 0)) {
return false;
}
}
}
return true;
}
/** Determine if this image is one solid color (implies redundant tile) */
public static boolean isImageSolidColor(BufferedImage img) {
int c = img.getRGB(0,0);
for (int x=0; x<img.getWidth(); x++) {
for (int y=0; y<img.getHeight(); y++) {
if (c!=img.getRGB(x,y)) {
return false;
}
}
}
return true;
}
public static void main(String[] args) throws Exception {
URL url = new URL("/image/ttXm6.png");
final BufferedImage tileSet = ImageIO.read(url);
Runnable r = new Runnable() {
@Override
public void run() {
JPanel gui = new JPanel(new BorderLayout(5, 5));
int cols = inferNumberColumns(tileSet);
System.out.println("tileSet cols: " + cols);
int rows = inferNumberRows(tileSet);
System.out.println("tileSet rows: " + rows);
ArrayList<BufferedImage> tiles = getTiles(tileSet, cols, rows);
JPanel p = new JPanel(new GridLayout(0, 7, 1, 1));
for (BufferedImage tile : tiles) {
JLabel l = new JLabel(new ImageIcon(tile));
l.setBorder(new LineBorder(Color.BLACK));
p.add(l);
}
gui.add(new JLabel(new ImageIcon(tileSet)));
JOptionPane.showMessageDialog(null, p);
}
};
// Swing GUIs should be created and updated on the EDT
SwingUtilities.invokeLater(r);
}
}
关于java - 自动从 png sprite 表中查找帧尺寸,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14649528/