Newbie question about tuples and list comprehensions
__peter__ at web.de
Thu Jun 26 10:11:49 CEST 2008
> On Jun 25, 7:26 pm, Terry Reedy <tjre... at udel.edu> wrote:
>> idiolect wrote:
>> > Hi all - Sorry to plague you with another newbie question from a
>> > lurker. Hopefully, this will be simple.
>> > I have a list full of RGB pixel values read from an image. I want to
>> > test each RGB band value per pixel, and set it to something else if it
>> > meets or falls below a certain threshold - i.e., a Red value of 0
>> > would be changed to 50.
>> > I've built my list by using a Python Image Library statement akin to
>> > the following:
>> > data = list(image.getdata())
>> > Which produces a very long list that looks like [(0,150,175),
>> > (50,175,225),...]. I'm trying to figure out a fast and pythonic way
>> > to perform my operation. The closest I've come so far to a succinct
>> > statement is a list comprehension along the syntax of:
>> Why are you trying to do this with a list comprehension? Learn the
>> basics first. Perhaps you have read too many of the recent threads
>> presenting diverting challenges for bored experienced programmers. Some
>> of these were definitely not Pythonic code for real use.
>> First question: do you really want to create a new 'very long list' or
>> modify list 'data' in place. Let's assume the latter.
>> for i,tup in enumerate(data):
>> data[i] = replace(tup)
>> where replace(tup) is an expression or function that produces a tuple
>> meeting your criteria. Simplest is
>> (max(tup,Rthresh), max(tup,Gthresh), max(tup,Bthresh)).
>> If nearly all your pixels are ok, add the following before the
>> assignment so you only make replacements when actually needed:
>> if tup < Rthresh or tup < Gthresh or tup < Bthresh:
>> Terry Jan Reedy
> A giant thank-you to all who've posted in response to my query - these
> are all much better approaches to my problem. I think I got hooked on
> using a list comprehension as it seemed the most concise approach vs.
> other techniques after a bunch of Google searches, but all of you have
> pointed out more efficient methods. I appreciate your willingness to
> indulge a n00b who hasn't thought his problem through, apparently.
> I'll try all of these approaches out over the next day and see what
> works best, although I suspect you've all posted sufficient solutions.
> Can't wait to try these suggestions out - cheers, idiolect
I'd like to emphasize Roger Miller's point with a small example script:
def transform_image_getdata(old, new):
image = Image.open(old)
image.putdata([(max(50, r), min(g*2, 255), 0) for r, g, b in
def transform_image_point(old, new):
image = Image.open(old)
transform_red = [max(50, i) for i in range(256)]
transform_green = [min(i*2, 255) for i in range(256)]
transform_blue = [0 for i in range(256)]
image.point(transform_red + transform_green + transform_blue).save(new)
if __name__ == "__main__":
import os, time
def g(*args, **kw):
start = time.time()
return f(*args, **kw)
print f.__name__, time.time() - start
for name in sys.argv[1:]:
a, b = os.path.splitext(name)
measure(transform_image_getdata)(name, a + ".getdata" + b)
measure(transform_image_point)(name, a + ".point" + b)
$ ./transform_image.py tmp.jpg
For the example Image.point() is about 60 times faster than getdata(). It's
the way to go if you can handle the color channels individually.
More information about the Python-list