我有数以千计的角色精灵(但实际上他们只是具有透明度的PNG文件),这些精灵已从Maya中保存下来。
这些是角色动画,几乎所有动画都是12帧。每个动画都是从8个基本方向中的每个方向渲染的。
在每个动画中,角色已经在框架中居中(这是它从Maya导出的方式);但是,每个图像周围都有一堆白色/透明空间。
我需要从外部水平批量裁剪这些精灵 - >为了保留角色在帧中的中点。这样做的原因是如果它没有被保留,当游戏从一个动画切换到下一个动画时,角色就会移动或跳跃。因此,重要的是角色在所有动画的框架中水平居中(使用身体的中点)。
此外......理想情况下,角色总是在精灵的底边或非常靠近精灵的底边。
对于妙招......出于游戏引擎的原因,最终裁剪的图像需要是偶数,或者可以被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
我在处理精灵之前已经使用过它并且发现它非常好。我相信它也有命令行功能,虽然我自己没有使用它。它是跨平台的。