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()