2009-10-24 14 views
14

我试图从我的图像中删除某种颜色,但它没有像我希望的那样工作。我试图做同样的事情在这里看到Using PIL to make all white pixels transparent?然而,图像质量是有点损失,所以它留下了什么被删除的地方奇怪的彩色像素的小幽灵。如果所有三个值都低于100,我尝试做像像素更改一样的东西,但由于图像质量差,周围的像素甚至不是黑色。PIL最好的方法来取代颜色?

有没有人知道用Python中的PIL更好的方法来替换颜色及其周围的任何东西?这可能是我可以想到的唯一可靠的消除方式,但是我无法想到完成这种操作的方法。

图片有白色背景和黑色的文字。我们只是说我想从图像中完全删除文本而不会遗留任何工件。

非常感谢别人的帮助!谢谢

回答

5

您需要将图像表示为2维数组。这意味着要么制作像素列表的列表,要么用一些聪明的数学方法将1维数组视为2d数组。然后,对于每个有针对性的像素,您需要查找所有周围的像素。你可以用python的发电机从而做到这一点:

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 

所以,你会使用这样的:

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 
22

执行此操作的最佳方法是使用Gimp中使用的“用于alpha的颜色”算法替换颜色。它会适用于你的情况。我使用PIL为一个开源的python照片处理器phatch重新实现了这个算法。你可以找到完整的实现here。这是一个纯粹的PIL实现,它没有其他依赖。您可以复制功能代码并使用它。下面是使用GIMP之类的样本:

alt textalt text

可以使用黑色作为颜色应用在图像上color_to_alpha功能。然后将图像粘贴到不同的背景颜色上进行替换。

顺便说一句,这个实现使用了PIL中的ImageMath模块。它比使用getdata访问像素更有效率。

编辑:这里是全码:

from PIL import Image, ImageMath 

def difference1(source, color): 
    """When source is bigger than color""" 
    return (source - color)/(255.0 - color) 

def difference2(source, color): 
    """When color is bigger than source""" 
    return (color - source)/color 


def color_to_alpha(image, color=None): 
    image = image.convert('RGBA') 
    width, height = image.size 

    color = map(float, color) 
    img_bands = [band.convert("F") for band in image.split()] 

    # Find the maximum difference rate between source and color. I had to use two 
    # difference functions because ImageMath.eval only evaluates the expression 
    # once. 
    alpha = ImageMath.eval(
     """float(
      max(
       max(
        max(
         difference1(red_band, cred_band), 
         difference1(green_band, cgreen_band) 
        ), 
        difference1(blue_band, cblue_band) 
       ), 
       max(
        max(
         difference2(red_band, cred_band), 
         difference2(green_band, cgreen_band) 
        ), 
        difference2(blue_band, cblue_band) 
       ) 
      ) 
     )""", 
     difference1=difference1, 
     difference2=difference2, 
     red_band = img_bands[0], 
     green_band = img_bands[1], 
     blue_band = img_bands[2], 
     cred_band = color[0], 
     cgreen_band = color[1], 
     cblue_band = color[2] 
    ) 

    # Calculate the new image colors after the removal of the selected color 
    new_bands = [ 
     ImageMath.eval(
      "convert((image - color)/alpha + color, 'L')", 
      image = img_bands[i], 
      color = color[i], 
      alpha = alpha 
     ) 
     for i in xrange(3) 
    ] 

    # Add the new alpha band 
    new_bands.append(ImageMath.eval(
     "convert(alpha_band * alpha, 'L')", 
     alpha = alpha, 
     alpha_band = img_bands[3] 
    )) 

    return Image.merge('RGBA', new_bands) 

image = color_to_alpha(image, (0, 0, 0, 255)) 
background = Image.new('RGB', image.size, (255, 255, 255)) 
background.paste(image.convert('RGB'), mask=image) 
+0

我试图让这个工作,但它说,没有模块命名为核心之类的东西,那只是一团糟。我可能是一个白痴,但我无法让它工作。无论如何,我确定你的答案会帮助其他人。 – Cookies 2009-10-24 16:41:25

+0

你不应该尝试运行整个文件。只需复制color_to_alpha函数本身。无论如何,我很高兴你找到了适合你的解决方案。如果你需要更高效的解决方案,你知道在哪里看;) – 2009-10-24 18:10:06

+0

我做了,它首先说全局名称'OPTIONS'没有定义,所以我复制了那部分,然后它说_t没有定义,但它是我没有的模块。这就是我的意思,我试图让它工作,但不能,下面建议的方法对我来说工作是可以的,但如果你的功能可以真的把图像中的所有背景像素都拿出来,那会很棒。还有一些左派混淆了tesseract。 – Cookies 2009-10-24 22:10:25

11

使用numpy的和PIL:

这将图像加载到形状(W,H,3),的numpy的阵列,其中W是 宽度和H是高度。阵列的第三根轴表示3色 通道,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') 
data = np.array(img) 
data[(data == orig_color).all(axis = -1)] = replacement_color 
img2 = Image.fromarray(data, mode='RGB') 
img2.show() 

由于orig_color是长度为3的元组,以及具有data形状 (W,H,3),NumPy的 broadcasts orig_color到形状(W,H,3)的阵列,以执行比较data == orig_color。结果形成(W,H,3)形状的布尔数组。

(data == orig_color).all(axis = -1)是形状(W,H)的一个布尔阵列 为True无论在data RGB颜色是original_color

8
#!/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) 
0

这是我的代码部分,结果想: source

target

import os 
import struct 
from PIL import Image 
def changePNGColor(sourceFile, fromRgb, toRgb, deltaRank = 10): 
    fromRgb = fromRgb.replace('#', '') 
    toRgb = toRgb.replace('#', '') 

    fromColor = struct.unpack('BBB', bytes.fromhex(fromRgb)) 
    toColor = struct.unpack('BBB', bytes.fromhex(toRgb)) 

    img = Image.open(sourceFile) 
    img = img.convert("RGBA") 
    pixdata = img.load() 

    for x in range(0, img.size[0]): 
     for y in range(0, img.size[1]): 
      rdelta = pixdata[x, y][0] - fromColor[0] 
      gdelta = pixdata[x, y][0] - fromColor[0] 
      bdelta = pixdata[x, y][0] - fromColor[0] 
      if abs(rdelta) <= deltaRank and abs(gdelta) <= deltaRank and abs(bdelta) <= deltaRank: 
       pixdata[x, y] = (toColor[0] + rdelta, toColor[1] + gdelta, toColor[2] + bdelta, pixdata[x, y][3]) 

    img.save(os.path.dirname(sourceFile) + os.sep + "changeColor" + os.path.splitext(sourceFile)[1]) 

if __name__ == '__main__': 
    changePNGColor("./ok_1.png", "#000000", "#ff0000")