需要裁剪数千张图像/精灵,同时保留中点

时间:2015-11-14 03:04:23

标签: image sprite crop maya 2d-games

我有数以千计的角色精灵(但实际上他们只是具有透明度的PNG文件),这些精灵已从Maya中保存下来。

这些是角色动画,几乎所有动画都是12帧。每个动画都是从8个基本方向中的每个方向渲染的。

在每个动画中,角色已经在框架中居中(这是它从Maya导出的方式);但是,每个图像周围都有一堆白色/透明空间。

我需要从外部水平批量裁剪这些精灵 - >为了保留角色在帧中的中点。这样做的原因是如果它没有被保留,当游戏从一个动画切换到下一个动画时,角色就会移动或跳跃。因此,重要的是角色在所有动画的框架中水平居中(使用身体的中点)。

此外......理想情况下,角色总是在精灵的底边或非常靠近精灵的底边。

对于妙招......出于游戏引擎的原因,最终裁剪的图像需要是偶数,或者可以被2整除。

有没有办法至少部分或完全自动化这个?或者是否有人可以推荐的程序来帮助实现这一目标的自动化;免费或付费。

2 个答案:

答案 0 :(得分:1)

我还不知道如果基于Python的答案适合你,但这就是我所得到的,通过一些工作,你可以将这个脚本复制并粘贴到Maya的脚本编辑器中,或者在Python解释器中执行它。

此脚本需要安装PIL库。

要在Maya上安装,您可以点击此链接Mistermatti's blog。解压缩file并在您的maya安装中粘贴PIL文件夹:Maya20XX\Python\Lib\site-packages 这适用于Maya2014,已经在其他版本上进行了测试。

from PIL import Image
import time
start_time = time.time()

#parses the image to find the first pixel on the x axis which is not blank
def parseXImage(pixelMap, resWidth, resHeight):
    for x in range(0, int(resWidth/2)):
        for y in range(0, int(resHeight/2)):
            if (pixelMap[x,y] != (0, 0, 0, 0)) or \
                (pixelMap[x,resHeight-y-1] != (0, 0, 0, 0)) or \
                (pixelMap[resWidth-x-1,y] != (0, 0, 0, 0)) or \
                (pixelMap[resWidth-x-1,resHeight-y-1] != (0, 0, 0, 0)):
                return x
    return None

#parses the image to find the first pixel on the y axis which is not blank
def parseYImage(pixelMap, resWidth, resHeight):
    topFound = False
    bottomFound = False
    yTop = None
    yBottom = None
    for y in range(0, int(resHeight/2)):
        for x in range(0, int(resWidth/2)):
            if not topFound:
                if (pixelMap[x,y] != (0, 0, 0, 0)) or \
                    (pixelMap[resWidth-x-1,y] != (0, 0, 0, 0)):
                    yTop = y
                    topFound = True
            if not bottomFound:
                if (pixelMap[x,resHeight-y-1] != (0, 0, 0, 0)) or \
                    (pixelMap[resWidth-x-1,resHeight-y-1] != (0, 0, 0, 0)):
                    yBottom = y
                    bottomFound = True
    return yTop, yBottom

imageList = [r"Path\To\Image\Mod_Turn.001.png",
    r"Path\To\Image\Mod_Turn.002.png",
    r"Path\To\Image\Mod_Turn.003.png",
    r"Path\To\Image\Mod_Turn.004.png",
    r"Path\To\Image\Mod_Turn.005.png"]

#get images resolution
imagePil = Image.open(imageList[0]) 
resWidth, resHeight = imagePil.size #get the resolution of the first image in the list
imagePil.close()

valueWidthList = [] 
valueHeightTopList = []
valueHeightBottomList = []
for imageListIndex, imagePath in enumerate(imageList):
    imagePil = Image.open(imagePath)
    pixelMap = imagePil.load()

    xValue = parseXImage(pixelMap, resWidth, resHeight) #now parse the image to find x
    yTopValue, yBottomValue = parseYImage(pixelMap, resWidth, resHeight) #now parse the image to find y
    valueWidthList.append(xValue) #Store it
    valueHeightTopList.append(yTopValue) #Store it
    valueHeightBottomList.append(yBottomValue) #Store it
    imagePil.close()

xValueToCrop = min(valueWidthList)  #Get the minimal value of X crop among all the entries
yTopValueToCrop = min(valueHeightTopList) #Get the minimal value of Y crop among all the entries
yBottomValueToCrop = min(valueHeightBottomList) #Get the minimal value of Y crop among all the entries
#This is the crop square we will use
cropSquare = (xValueToCrop, yTopValueToCrop, resWidth-xValueToCrop, resHeight-yBottomValueToCrop  )

for imagePath in imageList:
    imagePil = Image.open(imagePath)
    #Replace Turn by something in the name of your image
    imagePil.crop(cropSquare).save(imagePath.replace("Turn", "Turn_Cropped")) #Crop dans save the image
    imagePil.close()

print("--- %s seconds ---" % (time.time() - start_time))

您需要使用自己的图像路径更改imageList dict,并在脚本的最后更改"Turn", "Turn_Cropped"

仅供参考,处理300张@ 720p图像大约需要250秒。这可以改进。

答案 1 :(得分:0)

或许可以尝试使用TexturePacker https://www.codeandweb.com/texturepacker

我在处理精灵之前已经使用过它并且发现它非常好。我相信它也有命令行功能,虽然我自己没有使用它。它是跨平台的。