Este é um tutorial sobre Python e GeeXLab. O objetivo é dar uma olhada geral nas bibliotecas Python que podem ser úteis para demos GeeXLab E que funcionam no GeeXLab.
O GeeXLab tem uma maneira muito simples de trabalhar. Superficialmente falando, um demo é feito a partir de um script de inicialização (INIT, executado uma vez) e de um script por frame (FRAME, executado a cada frame). Esses scripts podem ser programados no Lua ou no Python. Em um script, você pode codificar o que quiser com ambas as linguagens. Não existe restrição: o GeeXLab pode ser visto como uma máquina virtual para o Lua ou o Python. É por isso que a maioria dos pacotes Python disponíveis irá funcionar com o GeeXLab.
Para interagir com os dados de cenário do GeeXLab (texturas, GLSL shaders, meshes etc.) existe o Host-API, que é simplesmente a API do GeeXLab para Lua e para Python. A descrição das funções do Host-API para GeeXLab está disponível aqui.
A rápida descrição do scripting do GeeXLab é importante, porque irei focar nas funcionalidades oferecidas por essas bibliotecas, e tentarei limitar o uso das funções GeeXLab ao mínimo. Dessa maneira, você poderá rapidamente reutilizar todos os fragmentos de códigos em seus próprios projetos Python.
Dito isso, vamos falar sobre a primeira biblioteca Python: PIL.
1 – PIL: biblioteca de imagens do Python
PIL ou Biblioteca de Imagens do Python é um pacote que expõe muitas funções para manipular imagens a partir de um script Python. A homepage oficial do PIL está aqui. Quando escrevi este artigo, a versão atual do PIL era PIL 1.1.7 e estava disponível para Python 2.3 até Python 2.7. Irei usar o PIL 1.1.7 for Python 2.6 neste artigo.
No Windows (XP, Vista ou 7), a instalação do PIL é bem simples: apenas inicie o PIL Windows installer e pronto. Claro que você precisa de uma instalação válida do Python 2.6.6 antes.
A documentação do PIL está disponível aqui:
2 – Carregando uma imagem
Aqui está um pequeno script INIT que usa o PIL para carregar uma imagem e exibi-la. Se você precisar, uma versão do PIL pode ser encontrada na variável Image.VERSION.
import HYP_Utils
import sys
from PIL import Image
scriptDir = HYP_Utils.GetDemoDir()
PIL_Version = Image.VERSION
img_filename = "%s/flower.jpg" % scriptDir
im = Image.open(img_filename)
im.show()
No Windows, a função Image.show() salva a imagem em um arquivo temporário e chama o visualizador de imagem padrão. No meu sistema, o Irfanview é chamado para visualizar a imagem:
Demo_Python_PIL_01.xml
3 – Salvando uma imagem
Apenas chame e função Image.save(). Você quer salvar no formato JPEG? Apenas adicione a extensão.jpg no nome do seu arquivo… Mesma coisa para os outros formatos.
Formatos suportados em leitura E escrita: *.bmp, *.gif, *.jpg, *.msp, *.pcx, *.png, *.ppm, *.tiff e .xbm.
Aqui está um simples conversor de JPG para BMP:
import HYP_Utils
from PIL import Image
scriptDir = HYP_Utils.GetDemoDir()
PIL_Version = Image.VERSION
img_filename = "%s/flower.jpg" % scriptDir
im = Image.open(img_filename)
im.save("%s/flower.bmp" % scriptDir)
4 – Lendo os pixels
Existem duas funções que possibilitam a leitura do mapa de pixels (ou pixel data): Image.getpixel() e Image.getdata().
Image.getpixel() retorna o valor de um único pixel. Apenas faça a enupla com as coordenadas X e Y e o getpixel() retornará um 3-tuple RGB para uma imagem RGB ou um único valor para uma imagem de luminância. O Image.getdata() retorna o mapa de pixels completo. Você precisa da função list() do Python para criar a lista do mapa de pixels das tuplenuplas RGB.
Aqui está um fragmento de código que carrega uma imagem com PIL, cria um objeto de textura com o GeeXLab Python API e preenche a textura com os pixels da imagem.
import HYP_Utils
import HYP_Texture
import HYP_Material
import sys
from PIL import Image
scriptDir = HYP_Utils.GetDemoDir()
PIL_Version = Image.VERSION
img_filename = "%s/flower.jpg" % scriptDir
im = Image.open(img_filename)
imageW = im.size[0]
imageH = im.size[1]
TEXTURE_2D = 2
RGB_BYTE = 2
texId = HYP_Texture.Create(TEXTURE_2D, RGB_BYTE, imageW, imageH, 0)
matId = HYP_Material.GetId("plane1_mat")
HYP_Material.AddTexture(matId, texId)
if (im.mode == "RGB"):
for y in range(0, imageH):
for x in range(0, imageW):
offset = y*imageW + x
xy = (x, y)
rgb = im.getpixel(xy)
HYP_Texture.SetValueTex2DByteRgb(texId, offset, rgb[0], rgb[1], rgb[2])
elif (imout.mode == "L"):
for y in range(0, imageH):
for x in range(0, imageW):
offset = y*imageW + x
xy = (x, y)
rgb = im.getpixel(xy)
HYP_Texture.SetValueTex2DByteRgb(texId, offset, rgb, rgb, rgb)
Com o Image.getdata(), as últimas linhas do script anterior seriam:
pixels = list(im.getdata())
if (im.mode == "RGB"):
for y in range(0, imageH):
for x in range(0, imageW):
offset = y*imageW + x
rgb = pixels[offset]
HYP_Texture.SetValueTex2DByteRgb(texId, offset, rgb[0], rgb[1], rgb[2])
elif (imout.mode == "L"):
for y in range(0, imageH):
for x in range(0, imageW):
offset = y*imageW + x
rgb = pixels[offset]
HYP_Texture.SetValueTex2DByteRgb(texId, offset, rgb, rgb, rgb)
Demo_Python_PIL_02.xml
5 – Processamento de imagem
Você pode facilmente aplicar filtros comuns de imagem com o PIL: blur, emboss, sharpen etc. Apenas importe o módulo ImageFilter:
from PIL import Image
from PIL import ImageFilter
...
i = Image.open(img_filename)
im = i.filter(ImageFilter.EMBOSS)
#im = i.filter(ImageFilter.FIND_EDGES)
...
Os filtros pré-definidos são: BLUR, CONTOUR, DETAIL, EDGE_ENHANCE, EDGE_ENHANCE_MORE, EMBOSS, FIND_EDGES, SMOOTH, SMOOTH_MORE, e SHARPEN.
Demo_Python_PIL_03.xml – EMBOSS
Demo_Python_PIL_03.xml – FIND_EDGES
Existe também um módulo chamado ImageOps que expõe as funções de processamento da imagem, como colorize(), flip(), grayscale(), invert(), mirror(), solarize(), ou posterize().
Demo_Python_PIL_04.xml – solarise()
Demo_Python_PIL_04.xml – posterize()
6 – Adicionando uma marca d’água
ImageDraw e ImageFont garantem ao PIL a capacidade de escrever textos em uma imagem, bem como desenhar linhas ou pontos. Aqui está o fragmento do código que mostra um simples conversor de lotes com PIL: ele lê todos os arquivos jpg de uma pasta, adiciona a marca d’água (uma cruz e a faixa “GEEXLAB”) e salva as imagens com o prefixo gxl_.
import HYP_Utils
import os, glob
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
scriptDir = HYP_Utils.GetDemoDir()
ft = ImageFont.load("timR24.pil")
os.chdir(scriptDir)
file_list = glob.glob("*.jpg")
for f in file_list:
im = Image.open(scriptDir + str(f))
draw = ImageDraw.Draw(im)
draw.line((0, 0) + im.size, fill=(255, 255, 255))
draw.line((0, im.size[1], im.size[0], 0), fill=(255, 255, 255))
wh = ft.getsize("G E E X L A B")
draw.text((im.size[0]/2 - wh[0]/2, im.size[1]/2 + 20), "G E E X L A B",
fill=(255, 255, 0), font=ft)
draw.text((im.size[0]/2 - wh[0]/2, im.size[1]/2 - 60), "G E E X L A B",
fill=(255, 255, 0), font=ft)
del draw
im.save(scriptDir + "gxl_" + str(f))
O arquivo timR24.pil vem com um pacote de fontes PIL. Você pode fazer o download aqui.
Demo_Python_PIL_05.xml
Existe também uma função legal ImageFont.truetype(), mas ela não funcionou no meu sistema porque essa função se apóia na biblioteca _imagingft.pyd (na verdade um DLL) que não pôde ser carregada devido a um problema de tempo de execução do Visual C. Aqui está o erro em um console GeeXLab:
# ERROR: Python – Script [initScene] has a runtime error. Error line: 29 – Error object: – Error data: DLL load failed: The application has failed to start because its side-by-side configuration is incorrect. Please see the application event log or use the command-line sxstrace.exe tool for more detail.. Script disabled.
Este link tem alguns detalhes sobre esse problema.
7 – Downloads
Se você quiser brincar com os demos GeeXLab, você pode encontrá-los no pacote de amostras demo disponíveis aqui. Os demos relacionados ao PIL estão na pasta Python_PIL/.
Aqui está um patch para o GeeXLab 0.2.5 + Python 2.6.6 que você deve usar para executar os demos. Apenas unzip o arquivo e copie o DLL para dentro da pasta GeeXLab_Python_Lua/.
PATCH DOWNLOAD: GeeXLabCore.dll
?
Texto original em inglês de JeGX, disponível em http://www.geeks3d.com/20100930/tutorial-first-steps-with-pil-python-imaging-library/