Is there any way using the eval function in PIL to run through all pixels, while checking to see what each value is? The program runs through an image to see if each pixel is a certain rgb, and if it is, then it will turn that pixel into transparency. the eval function in PIL seems it would do the job, but can my function that converts the pixels check the value of the pixel it's on? Thanks in advance.
Updated: Ahh, I see what you want to do. Here is an example using only PIL. It converts all white pixels to red with 50% alpha:
import Image
img = Image.open('stack.png').convert('RGBA')
width, _ = img.size
for i, px in enumerate(img.getdata()):
if px[:3] == (255, 255, 255):
y = i / width
x = i % width
img.putpixel((x, y), (255, 0, 0, 127))
img.save('stack-red.png')


Orig answer: Yes, the Image.eval() function lets you pass in a function which evaluates each pixel, and lets you determine a new pixel value:
import Image
img1 = Image.open('foo.png')
# replace dark pixels with black
img2 = Image.eval(img1, lambda px: 0 if px <= 64 else px)
No, eval will not pass an RGB tuple to a function. It maps a function over each band. You could, however process each band using eval and then use an ImageChops operation to logically combine the bands and get a mask that will be pixel-tuple specific.
By the way, this could be done much more cleanly and efficiently in NumPy if you are so inclined..
import numpy as np
import Image
import ImageChops
im_and = ImageChops.lighter
im = Image.open('test.png')
a = np.array(im)
R,G,B,A = im.split()
color_matches = []
for level,band in zip((255,255,255), (R,G,B)):
b = Image.eval(band, lambda px: 255-(255*(px==level)))
color_matches.append(b)
r,g,b = color_matches
mask = im_and(r, im_and(g, b))
im.putalpha(mask)
im.save('test2.png')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With