Using PIL for transparency of all white pixels?

I am trying to make all white pixels transparent using the Python image library. (I'm a hacker trying to learn python, so be careful) I have a conversion (at least the pixel values ​​look right), but I can’t figure out how to convert the list to a buffer to recreate the image. Here is the code

img = Image.open('img.png') imga = img.convert("RGBA") datas = imga.getdata() newData = list() for item in datas: if item[0] == 255 and item[1] == 255 and item[2] == 255: newData.append([255, 255, 255, 0]) else: newData.append(item) imgb = Image.frombuffer("RGBA", imga.size, newData, "raw", "RGBA", 0, 1) imgb.save("img2.png", "PNG") 
+43
python image python-imaging-library
Apr 19 '09 at 17:13
source share
5 answers

You need to make the following changes:

  • add a tuple (255, 255, 255, 0) , not a list [255, 255, 255, 0]
  • use img.putdata(newData)

This is the working code:

 from PIL import Image img = Image.open('img.png') img = img.convert("RGBA") datas = img.getdata() newData = [] for item in datas: if item[0] == 255 and item[1] == 255 and item[2] == 255: newData.append((255, 255, 255, 0)) else: newData.append(item) img.putdata(newData) img.save("img2.png", "PNG") 
+59
Apr 19 '09 at 17:38
source share

You can also use the pixel access mode to change the image in place:

 from PIL import Image img = Image.open('img.png') img = img.convert("RGBA") pixdata = img.load() width, height = image.size for y in xrange(height): for x in xrange(width): if pixdata[x, y] == (255, 255, 255, 255): pixdata[x, y] = (255, 255, 255, 0) img.save("img2.png", "PNG") 
+39
Apr 19 '09 at 18:17
source share
 import Image import ImageMath def distance2(a, b): return (a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) + (a[2] - b[2]) * (a[2] - b[2]) def makeColorTransparent(image, color, thresh2=0): image = image.convert("RGBA") red, green, blue, alpha = image.split() image.putalpha(ImageMath.eval("""convert(((((t - d(c, (r, g, b))) >> 31) + 1) ^ 1) * a, 'L')""", t=thresh2, d=distance2, c=color, r=red, g=green, b=blue, a=alpha)) return image if __name__ == '__main__': import sys makeColorTransparent(Image.open(sys.argv[1]), (255, 255, 255)).save(sys.argv[2]); 
+6
Dec 25 '10 at 19:34
source share

Python 3 version with all files in a directory

 import glob from PIL import Image def transparent(myimage): img = Image.open(myimage) img = img.convert("RGBA") pixdata = img.load() width, height = img.size for y in range(height): for x in range(width): if pixdata[x, y] == (255, 255, 255, 255): pixdata[x, y] = (255, 255, 255, 0) img.save(myimage, "PNG") for image in glob.glob("*.png"): transparent(image) 
0
Nov 29 '18 at 6:36
source share

Since this is currently Google’s first result when searching for "Pillow from white to transparent", I would like to add that the same can be achieved with numpy, and in my test (one 8MP image with a lot of white background) about 10 times faster (about 300 ms versus 3.28 s for the proposed solution). The code is also a bit shorter:

 import numpy as np def white_to_transparency(img): x = np.asarray(img.convert('RGBA')).copy() x[:, :, 3] = (255 * (x[:, :, :3] != 255).any(axis=2)).astype(np.uint8) return Image.fromarray(x) 

It is also easy to replace it with a version in which “almost white” (for example, one channel 254 instead of 255) is “almost transparent”. Of course, this will make the whole picture partially transparent, except for pure black:

 def white_to_transparency_gradient(img): x = np.asarray(img.convert('RGBA')).copy() x[:, :, 3] = (255 - x[:, :, :3].mean(axis=2)).astype(np.uint8) return Image.fromarray(x) 

Note: .copy() necessary because, by default, pillow images are converted to read-only arrays.

0
Jan 11 '19 at 14:24
source share



All Articles