У меня есть функция python, которая принимает строковое s-выражение типа "(add (sub 10 5) 5)", где "add" и "sub" являются фактически функциями обработки изображений, а также оценивает и создает изображение, представленное в Струна. Функции обработки изображений принимают константы, переменные или другие изображения (представленные в виде списков векторов), а обратные изображения - одинаково. PIL используется для преобразования изображения, представленного в виде списка векторов, в файл изображения.
Чтобы оценить префиксные обозначения s-выражений, я конвертирую s-expr в список, реверсирую его и повторяю токены до тех пор, пока не будет найдена функция, после чего выполняется обработка изображения, и полученное изображение заменяет функции и ее аргументы в списке. Это делается до тех пор, пока в списке не останется только один элемент, который является окончательным изображением.
Функции обработки изображений просты: большинство из них выполняют некоторую математическую операцию для каждого из значений (r, g, b) в изображении (ых).
Проблема заключается в том, что мой компьютер замирает, если я хочу сделать приличные изображения для более сложных выражений. Может ли это быть оптимизировано для использования меньше памяти?
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):
# 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 может рассказать вам, где программа тратит большую часть своего времени.
Во-вторых, str(sList[index-1])
преобразование Image
в строку? Возвращает ли ip.token(...)
изображение? Если это так, вы конвертируете между строкой и изображением несколько раз. Это может быть очень медленно.
Это может помочь изменить
rawImage = eval("ip." + token + "(" + "\"" + str(sList[index-1]) +
"\"" + ")")
к чему-то вроде
getattr(ip,token)(sList[index-1])
но, конечно, это зависит от того, какой тип аргумента ip.token
ожидает. Я не смог найти информацию о ImgProcessing
из Google. Является ли это обычным классом? Если это так, это может помочь объяснить больше о том, как это работает.
Если ip.token
можно изменить, взяв строки для съемки, это может быть большим улучшением.
По моему опыту, все, что вы делаете в чистом Python или PIL пиксельном пикселе на большом изображении, будет медленным, как меласса в январе. Рассмотрим перемещение материала низкого уровня в расширение Python, написанное на C. Я использовал OpenCV, но он требует некоторого обучения.
eval
, но 99% реального использованияeval
- включая это - крайне неуместно. Если вы думаете, что должны использоватьeval
, хорошее правило - вы ошибаетесь. Прежде чем использоватьeval
, потому что вам нужно использоватьeval
, пройдите курс CS362 «Выявление нескольких случаев, когда вы действительно должны использоватьeval
, и опубликуйте свой заполненный экзаменационный кредит и плату за подачу заявления в Обществе по управлению доступом кeval
В тех очень немногих случаях. Случаи, в которых вы действительно нуждаетесь, для получения письменного разрешения на использованиеeval
в очень немногих случаях, когда это действительно необходимо.