我正在开发一个程序,其中我需要分离 spritesheet,或者换句话说,将图像分离成连续的颜色区域。
我以前从未做过任何图像处理,所以我想知道我将如何处理这个问题。测试像素颜色后我会做什么?确定每个 Sprite 对应哪个像素的最佳方法是什么?
所有输入图像都有统一的背景,与背景不同的alpha channel 算作颜色。输出图像的顺序需要从左到右,从上到下。我的项目是用 PySide 编写的,所以我也希望将它用于此任务,但如果需要,我可以导入更多库。
感谢您的回复!
附言: 我不确定 PySide 标签是否合适,因为我使用的是 PySide,但问题不涉及它的 GUI 方面。如果某个模组觉得它不属于自己,请随时将其删除。
例如,我有一个如下所示的 spritesheet:
我想把它分成这些:
最佳答案
这听起来像是应该在任何处理 sprite 的东西中实现的东西,但在这里我们将实现我们自己的 sprite-spliter。
我们在这里需要做的第一件事是提取单个对象。在这种情况下,只需要确定一个像素是否为背景像素即可。如果我们假设原点是背景像素,那么我们就完成了:
from PIL import Image
def sprite_mask(img, bg_point=(0, 0)):
width, height = img.size
im = img.load()
bg = im[bg_point]
mask_img = Image.new('L', img.size)
mask = mask_img.load()
for x in xrange(width):
for y in xrange(height):
if im[x, y] != bg:
mask[x, y] = 255
return mask_img, bg
如果您保存上面创建的 mask
图像并打开它,您将在上面看到以下内容(我在您的空窗口中添加了一个矩形):
有了上面的图像,如果我们想加入其他 Sprite 内部的 Sprite ,接下来我们需要填充它的洞(比如添加的矩形,见上图)。这是另一个简单的规则:如果一个点不能从 [0, 0] 处的点到达,那么它就是一个洞,必须被填充。剩下的就是将单个图像中的每个 Sprite 分开。这是通过连接组件标记完成的。对于每个组件,我们获取其轴对齐的边界框以定义片段的尺寸,然后我们从原始图像复制属于给定组件的点。为简短起见,以下代码使用 scipy
来完成这些任务:
import sys
import numpy
from scipy.ndimage import label, morphology
def split_sprite(img, mask, bg, join_interior=True, basename='sprite_%d.png'):
im = img.load()
m = numpy.array(mask, dtype=numpy.uint8)
if join_interior:
m = morphology.binary_fill_holes(m)
lbl, ncc = label(m, numpy.ones((3, 3)))
for i in xrange(1, ncc + 1):
px, py = numpy.nonzero(lbl == i)
xmin, xmax, ymin, ymax = px.min(), px.max(), py.min(), py.max()
sprite = Image.new(img.mode, (ymax - ymin + 1, xmax - xmin + 1), bg)
sp = sprite.load()
for x, y in zip(px, py):
x, y = int(x), int(y)
sp[y - int(ymin), x - int(xmin)] = im[y, x]
name = basename % i
sprite.save(name)
print "Wrote %s" % name
sprite = Image.open(sys.argv[1])
mask, bg = sprite_mask(sprite)
split_sprite(sprite, mask, bg)
现在您拥有了与问题中完全相同的所有部分(sprite_1.png、sprite_2.png、...、sprite_8.png)。
关于python - PySide:将 spritesheet 分离/将图像分离为连续的颜色区域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14432021/