Here's an interesting bit of Python code I hacked together – it's a script that takes an image and warps it so that it is tileable (making it suitable for a repeating backgound or a texture in a game).

A fractal

A Mandlebrot fractal

If you use it on a photograph, it will come out looking like a fair-ground mirror. But it works well when applied to a pattern, or something more abstract, such as the fractal image on the left.

The code is public domain – use it for whatever the heck you want!

Example Output

Update: Here's another, more interesting example, The original is here.

The Code

import Image
from math import *

def maketilable(src_path, dst_path):
    src = Image.open(src_path)
    src = src.convert('RGB')
    src_w, src_h = src.size

    dst = Image.new('RGB', (src_w, src_h))
    w, h = dst.size

    def warp(p, l, dl):
        i = float(p) / l
        i = sin(i*pi*2 + pi)
        i = i / 2.0 + .5
        return abs(i * dl)

    warpx = [warp(x, w-1, src_w-1) for x in range(w)]
    warpy = [warp(y, h-1, src_h-1) for y in range(h)]

    get = src.load()
    put = dst.load()

    def getpixel(x, y):

        frac_x = x - floor(x)
        frac_y = y - floor(y)

        x1 = (x+1)%src_w
        y1 = (y+1)%src_h

        a = get[x, y]
        b = get[x1, y]
        c = get[x, y1]
        d = get[x1, y1]

        area_d = frac_x * frac_y
        area_c = (1.-frac_x) * frac_y
        area_b = frac_x * (1. - frac_y)
        area_a = (1.-frac_x) * (1. - frac_y)

        a = [n*area_a for n in a]
        b = [n*area_b for n in b]
        c = [n*area_c for n in c]
        d = [n*area_d for n in d]

        return tuple(int(sum(s)) for s in zip(a,b,c,d))


    old_status_msg = None
    status_msg = ''
    for y in xrange(h):

        status_msg = '%2d%% complete' % ((float(y) / h)*100.0)
        if status_msg != old_status_msg:
            print status_msg
        old_status_msg = status_msg

        for x in xrange(w):
            put[x, y] = getpixel(warpx[x], warpy[y])

    dst.save(dst_path)


if __name__ == "__main__":

    import sys
    try:
        src_path = sys.argv[1]
        dst_path = sys.argv[2]
    except IndexError:
        print "<source image path>, <destination image path>"
    else:
        maketilable(src_path, dst_path)
This blog post was posted to It's All Geek to Me on Saturday July 18th, 2009 at 6:06PM
 

3 Responses to "Making tileable images with Python"

  • Pauli Virtanen
    July 18th, 2009, 9:37 p.m.

    Smells like a job for Numpy (http://www.scipy.org [scipy.org]):

    import Image
    import numpy as np

    def maketilable(src_path, dst_path, w=None, h=None):
    src_img = Image.open(src_path)
    src_img = src_img.convert('RGB')
    src = np.asarray(src_img)

    src_w, src_h, ncolors = src.shape

    if w is None:
    w = src_w
    if h is None:
    h = src_h

    def warp(p, l, dl):
    i = p * 1.0 / l
    i = np.sin(i*np.pi*2 + np.pi)
    i = i / 2.0 + .5
    return abs(i * dl)

    xp = warp(np.arange(w), w-1, src_w-1)[:,np.newaxis]
    yp = warp(np.arange(h), h-1, src_h-1)[np.newaxis,:]

    x = xp.astype(int)
    y = yp.astype(int)

    x1 = (x + 1) % src_w
    y1 = (y + 1) % src_h

    a = src[x, y]
    b = src[x1, y]
    c = src[x, y1]
    d = src[x1, y1]

    frac_x = (xp - np.floor(xp))[...,np.newaxis]
    frac_y = (yp - np.floor(yp))[...,np.newaxis]

    d *= frac_x * frac_y
    c *= (1.-frac_x) * frac_y
    b *= frac_x * (1. - frac_y)
    a *= (1.-frac_x) * (1. - frac_y)

    dst = a + b + c + d
    dst_img = Image.fromarray(dst, 'RGB')
    dst_img.save(dst_path)

    if __name__ == "__main__":
    import sys
    try:
    src_path = sys.argv[1]
    dst_path = sys.argv[2]
    except IndexError:
    print "<source image path>, <destination image path>"
    else:
    maketilable(src_path, dst_path)
  • July 18th, 2009, 9:49 p.m.

    Pauli, Nice! I think it is a job for Numpy.

  • Pauli Virtanen
    July 18th, 2009, 10:11 p.m.

    Once more, this time demonstrating the use of scipy.ndimage for the interpolation:

    import Image
    import numpy as np
    import scipy.ndimage

    def maketilable(src_path, dst_path, w=None, h=None):
    src_img = Image.open(src_path)
    src_img = src_img.convert('RGB')
    src = np.asarray(src_img)

    src_w, src_h, ncolors = src.shape

    if w is None:
    w = src_w
    if h is None:
    h = src_h

    def warp(p, l, dl):
    i = p * 1.0 / l
    i = np.sin(i*np.pi*2 + np.pi)
    i = i / 2.0 + .5
    return abs(i * dl)

    x = warp(np.arange(w), w-1, src_w-1)
    y = warp(np.arange(h), h-1, src_h-1)

    coords = np.broadcast_arrays(*np.ix_(x, y))

    dst = np.empty((w, h, 3), src.dtype)
    for j in xrange(3):
    dst[:,:,j] = \
    scipy.ndimage.map_coordinates(src[:,:,j],
    coords,
    mode='wrap',
    order=3)

    dst_img = Image.fromarray(dst, 'RGB')
    dst_img.save(dst_path)

    if __name__ == "__main__":
    import sys
    try:
    src_path = sys.argv[1]
    dst_path = sys.argv[2]
    except IndexError:
    print "<source image path>, <destination image path>"
    else:
    maketilable(src_path, dst_path)

Leave a Comment

You can use bbcode in the comment: e.g. [b]This is bold[/b], [url]http://www.willmcgugan.com[/url], [code python]import this[/code]
Preview Posting...
Previewing comment, please wait a moment...
Will McGugan

My name is Will McGugan. I am an unabashed geek, an author, a hacker and a Python expert – amongst other things!

You are reading my tech blog. See the homepage for my other blogs.

Search for Posts
Possibly related posts
Tags
Popular Tags
 
Archives
2010
 
Recent Comments
http://www.iclshoes.com/alexander-mcqueen-c-13.html [iclshoes.com] http://www.iclshoes.com/jimmy-choo-shoes-c-2.html [iclshoes.com] http://www.iclshoes.com/ [iclshoes.com] http://www.zentai-mart.com/Play-Costumes-c-5.html [zentai-mart.com] http://www.zentai-mart.com/Latex-Catsuits-Clothes-c-3.html [zentai-mart.com] http://www.zentai-mart.com/PVC-Catsuits-Clothes-c-6.html [zentai-mart.com] http://www.zentai-mart.com/ [zentai-mart.com] http://www.hereshoes.com/miu-miu-shoes-c-31.html [hereshoes.com] http://www.hereshoes.com/giuseppe-zanotti-c-43.html [hereshoes.com] http://www.hereshoes.com/lanvin-shoes-c-50.html [hereshoes.com] ...
- Christian Louboutin on Turning website favicons in to 3D
What are the charmings of?a href="http://www.iclshoes.com [iclshoes.com]cl shoes/a?They are quality,comfort and style.The a href=http://www.iclshoes.com/jimmy-choo-shoes-c-2.html [iclshoes.com]Jimmy Choo shoes/a are made from ...
- Christian Louboutin on Turning website favicons in to 3D
Thanks a lot for that: I had first tried sudo aptitude purge adobe-flashplugin then sudo aptitude install flashplugin-nonfree but that ...
Andre, the name is derived from the class name (camel case converted to lower case with underscores). But, you can ...
is this using some kind of name mangling to map sorethumb:rounded_corners_edged to the RoundedCornersEdged class? that seems a little unnecessary ...
 
© 2008 Will McGugan.

A technoblog blog, design by Will McGugan