我正试图从我的图像中删除某种颜色,但它的效果并不像我希望的那么好。我尝试做同样的事情Using PIL to make all white pixels transparent?然而图像质量有点有损,所以它会在被移除的地方留下一些奇怪的彩色像素。如果所有三个值都低于100,我尝试做像更改像素这样的事情但由于图像质量很差,周围的像素甚至都不是黑色。
有没有人知道用Python中的PIL更好的方法来替换它周围的颜色和任何东西?这可能是我能想到的完全移除物体的唯一可靠方法,但是我想不出办法来做到这一点。
图片为白色背景,文字为黑色。我们只想说我想从图像中完全删除文本而不留下任何文物。
非常感谢别人的帮助!谢谢
答案 0 :(得分:22)
最好的方法是使用Gimp中使用的“颜色到alpha”算法来替换颜色。它将完美适用于您的情况。我使用PIL为开源python照片处理器phatch重新实现了这个算法。您可以找到完整的实施here。这是一个纯粹的PIL实现,它没有其他依赖性。您可以复制功能代码并使用它。以下是使用Gimp的示例:
至
您可以使用黑色作为颜色在图像上应用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)
答案 1 :(得分:12)
使用numpy和PIL:
这会将图像加载到形状为(W,H,3)
的numpy数组中,其中W
为。{1}}
宽度和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)
形状orig_color
,NumPy
broadcasts
(W,H,3)
到形状data ==
orig_color
的数组,以执行比较(W,H,3)
。结果形状为(data == orig_color).all(axis = -1)
的布尔数组。
(W,H)
是一个形状data
的布尔数组
如果original_color
中的RGB颜色为{{1}},则为真。
答案 2 :(得分: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)
答案 3 :(得分:5)
您需要将图像表示为二维数组。这意味着要么制作像素列表列表,要么将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
答案 4 :(得分:4)
如果像素不容易识别,例如你说(r <100且g <100且b <100)也不能正确匹配黑色区域,则意味着你有很多噪音。
最好的方法是识别一个区域并用你想要的颜色填充它,你可以手动识别区域,也可以通过边缘检测来识别。 http://bitecode.co.uk/2008/07/edge-detection-in-python/
或更复杂的方法是使用类似opencv(http://opencv.willowgarage.com/wiki/)的库来识别对象。
答案 5 :(得分:0)
这是我的代码的一部分,结果如下: source
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")