Hey,

I'm an experience programmer but new to Python. I'm doing a simple

implementation of a field morphing techinique due to Beier and Neely

(1992) and I have the simple case working in Python 2.3 - but it's

REALLY slow.

Basically, you specify two directed line segments in the coordinate

system of a raster image and use the difference between those two

lines to transform the image.

for a 400 x 600 image, python takes about 30 seconds to run the

algorithm. This seems way to slow - I would expect it to run in a

matter of a few seconds. Here's the code: what should I do to speed

things up? I know I'm going to get a "do it in C/make a C extension"

but that defeats the purpose: I'd like to know what Python can do

here.

Thanks for your help.

from Tkinter import *

import Image

import ImageTk

from sys import exit

from math import sqrt

class Point:

# A Point in the plane

def __init__(self, int1, int2):

# Constructor

self.x = float(int1)

self.y = float(int2)

def __add__(self, other):

# Add two points

return Point(self.x + other.x, self.y + other.y)

def __sub__(self, other):

# Sub two points

return Point(self.x - other.x, self.y - other.y)

def __mul__(self, other):

# Either mult by a constant or dot product

if type(other) == float or type(other) == int:

return Point(self.x*other, self.y*other)

else:

return self.x*other.x + self.y*other.y

def __div__(self,other):

# division by a constant

if type(other) == float or type(other) == int:

return Point(self.x/other, self.y/other)

def __rmul__(self, other):

# multiplication by a constant

return Point(self.x*other, self.y*other)

def __rdiv__(self, other):

# division by a constant

return Point(other/self.x, other/self.y)

def __str__(self):

# printing represenation

return '(%s, %s)' % (self.x, self.y)

def length(self):

# regular length

return sqrt(pow(self.x, 2) + pow(self.y, 2))

def perpindicular(self):

# 90 deg rotation

return Point(self.y, -self.x)

def to_tuple(self):

# makes a tuple of ints

return (int(self.x), int(self.y))

class WarpLine:

# The lines used to warp the image

def __init__(self, x0, y0, x1, y1, id):

# Constructor - just two points - id not used yet.

self.id = 0

self.point1 = Point(x0, y0)

self.point2 = Point(x1, y1)

def __str__(self):

# Printing

return '%s->%s' % (self.point1, self.point2)

def length(self):

# Segment length

return sqrt(pow(self.point2.x-self.point1.x, 2) +

pow(self.point2.y-self.point1.y, 2))

def getUV(self, point):

# v = shortest distance of point to line

# u = the parameterization of the closest point from v

diff = (self.point2 - self.point1)

u = ((point - self.point1) * diff) / (diff * diff)

v = ((point - self.point1) * diff.perpindicular()) / sqrt(diff

* diff)

return u, v

def transformPoint(self, line, point):

# finds transform of point based on self and line

diff = (line.point2 - line.point1)

u, v = self.getUV(point)

return line.point1 + u * diff + (v * diff.perpindicular()) /

sqrt(diff * diff)

class Picture:

# A simple image class

def __init__(self, file):

# Load up an image

self.data = Image.open(file)

def in_bounds(self, pt):

# is point in our bounds?

if pt.x < 0 or pt.y < 0 or pt.x > self.data.size[0] - 1 or

pt.y > self.data.size[1] - 1:

return 0

else:

return 1

def warp(self, source, line1, line2):

# Do transformPoint on each pixel, save results

# This is the slow part of the program

dest = list(self.data.getdata())

src = source.data.getdata()

for x in range(0, self.data.size[0] - 1):

for y in range(0, self.data.size[1] - 1):

xy = line1.transformPoint(line2,

Point(x,y)).to_tuple()

if self.in_bounds(Point(xy[0], xy[1])):

dest[x + y*self.data.size[0]] = src[xy[0] +

xy[1]*self.data.size[0]]

else:

dest[x + y*self.data.size[0]] = 0

self.data.putdata(dest)

def show(self):

# show the image

root = Tk()

canvas = Canvas(root, width=self.data.size[0],

height=self.data.size[1])

canvas.pack()

photo = ImageTk.PhotoImage(self.data)

disp = canvas.create_image(0, 0, anchor=NW, image=photo)

mainloop()