crayZsaaron crayZsaaron - 5 months ago 24
Python Question

Optimization of color inversion - Python Tkinter library

I attempted today to create a Python code to invert the colors of a .gif image using the Tkinter library. The code works and does exactly what I expected, but it takes about 50 seconds to run on a 3.4ghz processor. I'm having trouble seeing what I could change to optimize this. Basically, I loop through every pixel in the image , grab the color values, convert them to a list of integers (in order to manipulate them mathematically), invert each color value (new color value = 255 - old color value), convert them back to a string so that PhotoImage's "put" method can process them and rewrite the image, and finally display the inverted image. I can't think of what to change. I mean, looping through every single pixel must be a part of the slowness, but isn't this process completely necessary?

from Tkinter import *
import tkMessageBox

class GUIFramework(Frame):
def __init__(self, master=None):

Frame.__init__(self, master)

self.grid(padx=0, pady=0)
self.btnDisplay = Button(self, text="Display!", command=self.Display)
self.btnDisplay.grid(row=0, column=0)

def Display(self):
a = ''
b = []
self.imageDisplay = PhotoImage(file='C:\image.gif')
for x in range(0, self.imageDisplay.width()):
for y in range(0, self.imageDisplay.height()):
value = self.imageDisplay.get(x,y)
for i in value:
try:
c = int(i)
a += (i)
except:
b.append(int(a))
a = ''
b.append(int(a))
for i in range(0,3):
b[i] = (255 - b[i])
self.imageDisplay.put('#%02x%02x%02x' %tuple(b), (x,y))
b = []
a = ''
c = Canvas(self, width=700, height=700); c.pack()
c.grid(padx=0,pady=0, column=0, row=0)
c.create_image(0,0, image = self.imageDisplay, anchor = NW)

if __name__ == "__main__":
guiFrame = GUIFramework()
guiFrame.mainloop()


Thanks in advance for your help.
-Seth

Answer

Try this:

def Display(self):
    self.imageDisplay = PhotoImage(file='C:\image.gif')
    for x in xrange(0, self.imageDisplay.width()):
        for y in xrange(0, self.imageDisplay.height()):
            raw = self.imageDisplay.get(x, y)
            rgb = tuple(255 - int(component) for component in raw.split())
            self.imageDisplay.put('#%02x%02x%02x' % rgb, (x, y))
    c = Canvas(self, width=700, height=700); c.pack()
    c.grid(padx=0,pady=0, column=0, row=0)
    c.create_image(0,0, image = self.imageDisplay, anchor = NW)

Edit: New version (faster and with optimizations from Justin Peel).

def Display(self):
    self.imageDisplay = PhotoImage(file='C:\image.gif')

    wrange = xrange(0, self.imageDisplay.width())
    hrange = xrange(0, self.imageDisplay.height())
    get = self.imageDisplay.get
    put = self.imageDisplay.put

    def convert_pixel(raw):
        return ('#%02x%02x%02x' %
            tuple(255 - int(component) for component in raw.split(' ')))

    for y in hrange:
        put('{' + ' '.join(convert_pixel(get(x, y)) for x in wrange) + '}', (0, y))

    c = Canvas(self, width=700, height=700);
    c.pack()
    c.grid(padx=0, pady=0, column=0, row=0)
    c.create_image(0, 0, image=self.imageDisplay, anchor=NW)