views:

575

answers:

5

I am trying to remove a certain color from my image however it's not working as well as I'd hoped. I tried to do the same thing as seen here http://stackoverflow.com/questions/765736/using-pil-to-make-all-white-pixels-transparent however the image quality is a bit lossy so it leaves a little ghost of odd colored pixels around where what was removed. I tried doing something like change pixel if all three values are below 100 but because the image was poor quality the surrounding pixels weren't even black.

Does anyone know of a better way with PIL in Python to replace a color and anything surrounding it? This is probably the only sure fire way I can think of to remove the objects completely however I can't think of a way to do this.

The picture has a white background and text that is black. Let's just say I want to remove the text entirely from the image without leaving any artifacts behind.

Would really appreciate someone's help! Thanks

+1  A: 

You'll need to represent the image as a 2-dimensional array. This means either making a list of lists of pixels, or viewing the 1-dimensional array as a 2d one with some clever math. Then, for each pixel that is targeted, you'll need to find all surrounding pixels. You could do this with a python generator thus:

def targets(x,y):
    yield (x,y) # Center
    yield (x+1,y) # Left
    yield (x-1,y) # Right
    yield (x,y+1) # Above
    yield (x,y-1) # Below
    yield (x+1,y+1) # Above and to the right
    yield (x+1,y-1) # Below and to the right
    yield (x-1,y+1) # Above and to the left
    yield (x-1,y-1) # Below and to the left

So, you would use it like this:

for x in range(width):
    for y in range(height):
        px = pixels[x][y]
        if px[0] == 255 and px[1] == 255 and px[2] == 255:
            for i,j in targets(x,y):
                newpixels[i][j] = replacementColor
Benson
Excellent, this did the trick. Thanks a lot!
Cookies
No problem, glad I could help. :-)
Benson
+1  A: 

If the pixels are not easily identifiable e.g you say (r < 100 and g < 100 and b < 100) also doesn't match correctly the black region, it means you have lots of noise.

Best way would be to identify a region and fill it with color you want, you can identify the region manually or may be by edge detection e.g. http://bitecode.co.uk/2008/07/edge-detection-in-python/

or more sophisticated approach would be to use library like opencv (http://opencv.willowgarage.com/wiki/) to identify objects.

Anurag Uniyal
+3  A: 
Nadia Alramli
I tried to get this to work but it said no module named core and things like that, it was just a mess. I'm probably an idiot but I just couldn't get it to work. Thanks anyway I'm sure your answer will help someone else though.
Cookies
You should not try to run the whole file. Just copy the color_to_alpha function itself. Anyway, I'm glad you found a solution that works for you. If you need a more efficient solution, you know where to look ;)
Nadia Alramli
I did, and it first said global name 'OPTIONS' is not defined, so I copied that part out and then it said _t is not defined, but it was a module I didn't have. That's what I meant by mess, I tried to get it to work but couldn't, the method suggested below that worked for me is okay but if your function could really take out all the background pixels in the image that'd be great. There are still some left that confuse tesseract.
Cookies
I updated the solution with the full answer. You can change the colors in the last 3 lines to match the ones you want.
Nadia Alramli
Thanks, it works except it still leaves behind a ghost of pixels unlike the solution below. Basically I have a solid dark colored text, it is black/blue like a gradient because of the poor quality. I want to keep the solid objects and remove all the pixels around it that are sort of like a shadow.Like this:http://img36.imageshack.us/img36/6963/expuq.jpgI am going to play around with it a bit and see if I can get something to work.. Thanks again!
Cookies
I wish I was able to help. Go with the solution that works best for your case :)
Nadia Alramli
A: 

Using numpy and PIL:

This loads the image into a numpy array of shape (W,H,3), where W is the width and H is the height. The third axis of the array represents the 3 color channels, R,G,B.

import Image
import numpy as np

orig_color=(255,255,255)
replacement_color=(0,0,0)
img = Image.open(filename).convert('RGB')
arr = np.array(np.asarray(img))
masks=[]
for i in range(3):
    band=arr[:,:,i]
    masks.append(band==orig_color[i])
mask=np.logical_and.reduce(masks)
for i in range(3):
    arr[mask,i]=replacement_color[i]
img = Image.fromarray(arr,mode='RGB')
img.save('out.png')
unutbu
A: 
#!/usr/bin/python
from PIL import Image
import sys

img = Image.open(sys.argv[1])
img = img.convert("RGBA")

pixdata = img.load()

# Clean the background noise, if color != white, then set to black.
# change with your color
for y in xrange(img.size[1]):
    for x in xrange(img.size[0]):
        if pixdata[x, y] == (255, 255, 255, 255):
            pixdata[x, y] = (0, 0, 0, 255)
Gunslinger_