The Python Imaging Library (PIL) makes many tasks easy in digital photography. This recipe shows how to make a "contact sheet" of images, a single image with thumbnails of many different pictures. It's limited in that it will only work with pictures of the same shape, but you can make some really fun images.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | def make_contact_sheet(fnames,(ncols,nrows),(photow,photoh),
(marl,mart,marr,marb),
padding):
"""\
Make a contact sheet from a group of filenames:
fnames A list of names of the image files
ncols Number of columns in the contact sheet
nrows Number of rows in the contact sheet
photow The width of the photo thumbs in pixels
photoh The height of the photo thumbs in pixels
marl The left margin in pixels
mart The top margin in pixels
marr The right margin in pixels
marl The left margin in pixels
padding The padding between images in pixels
returns a PIL image object.
"""
# Read in all images and resize appropriately
imgs = [Image.open(fn).resize((photow,photoh)) for fn in fnames]
# Calculate the size of the output image, based on the
# photo thumb sizes, margins, and padding
marw = marl+marr
marh = mart+ marb
padw = (ncols-1)*padding
padh = (nrows-1)*padding
isize = (ncols*photow+marw+padw,nrows*photoh+marh+padh)
# Create the new image. The background doesn't have to be white
white = (255,255,255)
inew = Image.new('RGB',isize,white)
# Insert each thumb:
for irow in range(nrows):
for icol in range(ncols):
left = marl + icol*(photow+padding)
right = left + photow
upper = mart + irow*(photoh+padding)
lower = upper + photoh
bbox = (left,upper,right,lower)
try:
img = imgs.pop(0)
except:
break
inew.paste(img,bbox)
return inew
|
I recently used the blog entry at the URL: http://www.mikematas.com/blog/2005/01/how-to-make-life-poster.html to make a Life Poster with rather striking results. I started thinking about how to do this in Python (being that kind of person), and it turns out that PIL makes this very easy indeed.
The original recipe requires IPhoto, and uses it to crop a set of pictures to the same aspect ratio, and then build a contact sheet. That sheet is then printed as a PDF, and then converted to a TIFF by Photoshop, then imported back to IPhoto for printing as a poster.
This program assumes you have a set of pictures already cropped appropriately, and then uses PIL to assemble thumbnails into a single picture. The fun part is that since you own the code, you are free to play around with lots of different settings.
I haven't actually printed out a picture this way, so I can't guarantee that the results are in any way comparable to the IPhoto/Photoshop recipe, but the images certainly look nice on my computer.
I've been testing the code with something like the following: <pre> def test(): ncols,nrows = 7,14
files = glob.glob('*.TIFF')
# Don't bother reading in files we aren't going to use
if len(files) > ncols*nrows: files = files[:ncols*nrows]
# These are all in terms of pixels:
photow,photoh = 200,150
photo = (photow,photoh)
margins = [5,5,5,5]
padding = 1
inew = make_contact_sheet(files,(ncols,nrows),photo,margins,padding)
inew.save('bs.png')
#os.system('display bs.png')
os.system('open bs.png')
</pre>
Thanks for this, it's much, much quicker than using ImageMagick's
montage
.I've made a fork that vastly improves the memory performance: instead of loading in all the images at the start, just load them when needed.
imgs = [Image.open(fn).resize((photow,photoh)) for fn in fnames]
count = 0
before the loop.img = imgs.pop(0)
withimg = Image.open(fnames[count]).resize((photow,photoh))
count += 1
afterinew.paste(img,bbox)
See the fork here: http://code.activestate.com/recipes/578267-use-pil-to-make-a-contact-sheet-montage-of-images/