Can this image processing code be optimised to use less memory?
I have a python function that takes a string s-expression like "(add (sub 10 5) 5)", where "add" and "sub" are actually image processing functions, and evaluates and creates the image represented in the string. The image processing functions take constants, variables, or other images (represented as lists of vectors), and return images represented the same way. PIL is used to convert the image represented as a list of vectors into an image file.
To evaluate the prefix notation s-expressions, I convert the s-expr to a list, reverse it, and iterate the tokens until a function is found, at which point the image processing function is performed and the resulting image replaces the function and its arguments in the list. This is done until only one element is left in the list, which is the final image.
The image processing functions are simple- most perform some mathematical operation to each of the (r,g,b) values in the image(s).
The problem is my computer comes to a standstill if I want to make decent sized images for more complex expressions. Can this be optimised to use less memory?
def createImage(self, sexpr, filename, (picWidth, picHeight)):
"""Use the image processing functions in ImgProcessing
to create an image from the procedural information
contained in the s-expression."""
img = Image.new("RGB",(picWidth,picHeight),(255,255,255))
ip = ImgProcessing(picWidth,picHeight)
# Split s-expression into list of tokens and reverse
sList = sexpr.replace("(","").replace(")","").split()
sList.reverse()
while len(sList) > 1:
for index,token in enumerate(sList开发者_如何学JAVA):
# If token is an image processing function
if type(token) == str and self.FuncSet.has_key(token):
# If this function takes one argument
if self.FuncSet[token] == 1:
rawImage = eval("ip." + token + "(" + "\"" + str(sList[index-1]) +
"\"" + ")")
sList = sList[:index-1] + [rawImage] + sList[index+1:]
break
# If this function takes two arguments
elif self.FuncSet[token] == 2:
rawImage = eval("ip." + token + "(" + "\"" + str(sList[index-1]) +
"\"" + "," + "\"" + str(sList[index-2]) + "\"" +
")")
sList = sList[:index-2] + [rawImage] + sList[index+1:]
break
img.putdata(sList[0])
img.save(filename)
Profiling can tell you where the program is spending most of its time.
Second, is str(sList[index-1])
converting an Image
into a string? Does ip.token(...)
return an Image? If so, you are converting between string and Image a number of times. That might be very slow.
It might help to change
rawImage = eval("ip." + token + "(" + "\"" + str(sList[index-1]) +
"\"" + ")")
to something like
getattr(ip,token)(sList[index-1])
but of course this depends on what type of argument ip.token
expects. I couldn't find any information on ImgProcessing
from Googling. Is this a custom class? If so, it might help to explain more about how it works.
If ip.token
can be changed from taking strings to taking Images, that might be a big improvement.
In my experience, anything that you do in pure Python or PIL pixel-by-pixel on a large image is going to be slow as molasses in January. Consider moving the low-level stuff into a Python extension written in C. I have used OpenCV, but it takes some learning.
精彩评论