Martin Thoma
Martin Thoma

Reputation: 136177

Change specific RGB color pixels to another color, in image file

I would like to change a single color with Python.

If a fast solution with PIL exists, I would prefer this solution.

At the moment, I use

convert -background black -opaque '#939393' MyImage.png MyImage.png

Upvotes: 19

Views: 41828

Answers (4)

Joe Kington
Joe Kington

Reputation: 284552

If numpy is available on your machine, try doing something like:

import numpy as np
from PIL import Image

im = Image.open('fig1.png')
data = np.array(im)

r1, g1, b1 = 0, 0, 0 # Original value
r2, g2, b2 = 255, 255, 255 # Value that we want to replace it with

red, green, blue = data[:,:,0], data[:,:,1], data[:,:,2]
mask = (red == r1) & (green == g1) & (blue == b1)
data[:,:,:3][mask] = [r2, g2, b2]

im = Image.fromarray(data)
im.save('fig1_modified.png')

It will use a bit (3x) more memory, but it should be considerably (~5x, but more for bigger images) faster.

Also note that the code above is slightly more complicated than it needs to be if you only have RGB (and not RGBA) images. However, this example will leave the alpha band alone, whereas a simpler version wouldn't have.

Upvotes: 33

TankorSmash
TankorSmash

Reputation: 12747

This solution uses glob to edit all pngs in a folder, removing a color and swapping it out with another, but uses RGBA.

import glob
from PIL import Image

old_color = 255, 0, 255, 255
new_color = 0, 0, 0, 0

for path in glob.glob("*.png"):
    if "__out" in path:
        print "skipping on", path
        continue

    print "working on", path

    im = Image.open(path)
    im = im.convert("RGBA")
    width, height = im.size
    colortuples = im.getcolors()

    pix = im.load()
    for x in xrange(0, width):
        for y in xrange(0, height):
            if pix[x,y] == old_color:
                im.putpixel((x, y), new_color)

    im.save(path+"__out.png")

It's a modification of https://stackoverflow.com/a/6483549/541208

Upvotes: 0

Martin Thoma
Martin Thoma

Reputation: 136177

I've just came up with this solution:

import Image
im = Image.open("MyImage.png")
width, height = im.size
colortuples = im.getcolors()
mycolor1 = min(colortuples)[1]
mycolor2 = max(colortuples)[1]
pix = im.load()
for x in range(0, width):
    for y in range(0, height):
        if pix[x,y] == mycolor1:
            im.putpixel((x, y), mycolor2)
im.save('MyImage.png')

Although putpixel isn't fast, it seems to be fast enough for me.

Upvotes: 4

hazzey
hazzey

Reputation: 1248

This is a modification of Joe Kington's answer above. The following is how to do this if your image contains an alpha channel as well.

import numpy as np
import Image

im = Image.open('fig1.png')
im = im.convert('RGBA')
data = np.array(im)

r1, g1, b1 = 0, 0, 0 # Original value
r2, g2, b2, a2 = 255, 255, 255, 255 # Value that we want to replace it with

red, green, blue, alpha = data[:,:,0], data[:,:,1], data[:,:,2], data[:,:,3]
mask = (red == r1) & (green == g1) & (blue == b1)
data[:,:,:4][mask] = [r2, g2, b2, a2]

im = Image.fromarray(data)
im.save('fig1_modified.png')

It took me a long time to figure out how to get it to work. I hope that it helps someone else.

Upvotes: 6

Related Questions