[Tutor] speeding code along

Magnus Lycka magnus@thinkware.se
Sun Nov 17 20:33:01 2002


At 11:27 2002-11-18 +1300, Thomi Richards wrote:
>How can i speed up the following code?  take a look: it is called
>several thousand times, and i would like to speed it up just a little...

You are looking through all of the palette for each pixel
of the image for every file. That doesn't seem very effective.
A loop inside a loop inside a loop?

Perhaps you could precalculate the closest colour for each
input colour once for all, and store that in a dict or if need
be, some kind of database? Then you only make a quick lookup
for each pixel.

A compromise might be that once you have calculated a colur,
you store it in a dict, and then you check the dict, so that
you don't need to test again when you run into the same colour
several times in an image. This will give a big speedup for
images with few colours at least.

Apart from that, I imagine there are faster methods to find
the closest colour in a palette than the brute force method
you use.

>def convert(filename,inpalette,extension='-converted'):

         closestColour = {}

>         convfile = Image.open('input/%s' % (filename))
>         if convfile.mode != 'RGB':
>                 temp = convfile.convert('RGB')
>                 convfile = temp
>                 del(temp)
>
>         for x in range(convfile.size[0] - 1):
>                 for y in range(convfile.size[1] - 1):
>                         pixel = convfile.getpixel((x,y))

                         if closestColour.hasKey(pixel):
                                 convfile.putpixel((x,y),closestColour[pixel])
                                 continue

>                         tempdistance = 6000
>                         for color in inpalette:
>                                 distance = sqrt( (color[0] -
>pixel[0])**2 + (color[1] - pixel[1])**2 + (color[2] - pixel[2])**2 )
>                                 if distance < tempdistance:
>                                         tempdistance = distance
>                                         tempcolor = color
>                                 if tempdistance == 0:
>                                         break
>                         convfile.putpixel((x,y),tempcolor)

                         closestColour[pixel] = tempcolor

>
>         #now we save the file!
>         convfile.save('output/%s%s.bmp' %
>(split(filename,'.')[0],extension))
>         return 0

You could also put the dict outside the function (make it
global, don't forget "global closestColour" inside the
function) but then you need to use the palette in the
key as well as the particular pixel:

closestColour[(inpalette,pixel)] = tempcolor

and so on (if inpalette is hashable in a meaningful way).

To store the info persistently, you could pickle the dict
to a file, or use some other persistence mechanism.

I made a similar caching change to a python benchmarking
program that used recursion to calculate Fibonacci numbers.
That made the program roughly 6600 times faster...


-- 
Magnus Lycka, Thinkware AB
Alvans vag 99, SE-907 50 UMEA, SWEDEN
phone: int+46 70 582 80 65, fax: int+46 70 612 80 65
http://www.thinkware.se/  mailto:magnus@thinkware.se