- 1 – PIL: Python Imaging Library
- 2 – Loading an image
- 3 – Saving an image
- 4 – Reading the pixels
- 5 – Image Processing
- 6 – Adding a Watermark
- 7 – Downloads
This is the first tutorial about Python and GeeXLab. The purpose of this series is to do an overview of the Python libraries that may be useful for GeeXLab demos AND that work with GeeXLab.
GeeXLab has a very simple way of working. Roughly speaking, a demo is made up of an initialization script (INIT, executed once) and a per frame script (FRAME, executed every frame). These scripts can be programmed either in Lua or in Python. In a script you can code what you want with both languages. There is no restriction: GeeXLab can be seen as a virtual machine for Lua and Python. That’s why, most the Python packages available will work with GeeXLab.
And to interact with GeeXLab scene data (textures, GLSL shaders, meshes, etc.) there is the Host-API which is simply GeeXLab API for Lua and Python. GeeXLab Host-API functions description is available HERE.
This quick description of GeeXLab scripting is important for this series of tutorials about Python libraries because I’m going to focuse on the functionalities offered by those libraries and I’ll try to limit the use of GeeXLab functions to the bare minimum. That way, you will be able to quickly re-use all code snippets in your own python projects.
That said, let’s talk about the first Python lib: PIL.
1 – PIL: Python Imaging Library
PIL or Python Imaging Library is a package that exposes many functions to manipulate images from a Python script. PIL official homepage is HERE. The current version of PIL is PIL 1.1.7 and is available for Python 2.3 up to Python 2.7. I’ll use PIL 1.1.7 for Python 2.6 in this article.
Under Windows (XP, Vista or Seven) the installation of PIL is rather simple: just launch the PIL Windows installer and you’re ok. Of course you need a valid Python 2.6.6 installation before.
PIL documentation is available here:
2 – Loading an image
Here is a small INIT script that uses PIL to load an image and display it. If you need it, PIL version can be found in the Image.VERSION variable.
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()
Under Windows, the Image.show() function saves the image to a temporary file and calls the default image viewer utility. On my system, Irfanview is called to display the image:
Demo_Python_PIL_01.xml
3 – Saving an image
Just call the Image.save() function. You want to save to JPEG format? Just add the .jpg extension to your image filename… Same thing for the other formats.
Formats supported in reading AND writing: *.bmp, *.gif, *.jpg, *.msp, *.pcx, *.png, *.ppm, *.tiff and .xbm.
Here is a simple JPG to BMP converter:
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 – Reading the pixels
There are two functions that make it possible to read the pixmap (or pixel data): Image.getpixel() and Image.getdata().
Image.getpixel() returns the value of a single pixel. Just give a tuple with the X and Y coordinates and getpixel() returns a 3-tuple RGB for a RGB image or a single value for a luminance image. Image.getdata() returns the complete pixmap. You need the Python function list() to create the pixmap list of RGB tuples.
Here is a code snippet that loads an image with PIL, creates a texture object with GeeXLab Python API and fills the texture with image pixels.
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)
With Image.getdata(), the last lines of the previous script would be:
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 – Image Processing
You can easily apply common image filters with PIL: blur, emboss, sharpen, etc. Just import the ImageFilter module:
from PIL import Image from PIL import ImageFilter ... i = Image.open(img_filename) im = i.filter(ImageFilter.EMBOSS) #im = i.filter(ImageFilter.FIND_EDGES) ...
Predefined filters are: BLUR, CONTOUR, DETAIL, EDGE_ENHANCE, EDGE_ENHANCE_MORE, EMBOSS, FIND_EDGES, SMOOTH, SMOOTH_MORE, and SHARPEN.
Demo_Python_PIL_03.xml – EMBOSS
Demo_Python_PIL_03.xml – FIND_EDGES
There is also a module called ImageOps that exposes image processing functions such as colorize(), flip(), grayscale(), invert(), mirror(), solarize(), or posterize().
Demo_Python_PIL_04.xml – solarise()
Demo_Python_PIL_04.xml – posterize()
6 – Adding a Watermark
ImageDraw and ImageFont give to PIL the capability to write text on an image as well as to draw lines or points. Here is a code snippet that shows a simple batch converter with PIL: it reads all jpg files of a folder, adds the watermark (a cross and the “GEEXLAB” string) and saves the images with the gxl_ prefix.
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))
The file timR24.pil comes from a PIL fonts package. You can download it HERE.
Demo_Python_PIL_05.xml
There is also a nice function ImageFont.truetype() but it didn’t work on my system because this function relies on the _imagingft.pyd library (actually a DLL) that could not be loaded due to a Visual C runtime problem. Here is the error in GeeXLab console:
# 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.
This link has some details about this problem.
7 – Downloads
If you want to play with the GeeXLab demos, you can find them in the code samples demo pack available HERE. The demos related to PIL are in the Python_PIL/ folder.
Here is a patch for GeeXLab 0.2.5 + Python 2.6.6 that you must use to run the demos. Just unzip the archive and copy the DLL into GeeXLab_Python_Lua/ folder.
PATCH DOWNLOAD: GeeXLabCore.dll
Pingback: [Demotool] GeeXLab 0.2.6 Released With Gamma Correction Support - 3D Tech News, Pixel Hacking, Data Visualization and 3D Programming - Geeks3D.com
Hi, in which case you run into Visual C runtime problem ?
I just tried Python_PIL example (toggled comment on #70-#71) and it runs with no problem. So I am curious what causes this kind of error.
This is fantastic examples such what I was searching for.
thank you
cool stuff! any ideas what I could use on a Linux machine to do some 2D image rotating in 3D space (not real time), ideally using python/PIL, but any other technologies are also cool…? thanks for the help in advance! hoff
hoff, you can do easy rotations with VPython.
Maybe they’re easy with GeexLab, I’m just about to start that and I don’t know what it can do yet. But VPython does that. VPython is extremely weak at saving images, though, so PIL and maybe GeexLab can fill in there — assuming there’s something VPython does that’s worth mixing it in with them.
how represent image into pixel matrix form… i have to represent image in 8*8 prxel matrix i have to perform operation on tht matrix using python so , please help me..
I tried looking at what you suggested. Things worked pretty fine, until I wrote im.show()..it gave an error with an empty window photo viewer opened……. window photo viewer cannot open the picture because picture is either deleted or moved… I can see the temp…TMPdfjfjs.BMP, there too…I am not good at these stuff either…..can you help me what exactly this is? I am running python 2.5, with PIL 1.1.7.(I am on window 7)
Thanks