19

画像から特定の色を削除しようとしていますが、期待どおりに機能していません。ここで見たのと同じことをしようとしましたPILを使用してすべての白いピクセルを透明にしますか? ただし、画質が少し失われるため、削除された場所の周りに奇妙な色のピクセルのゴーストが少し残ります. 3 つの値がすべて 100 未満の場合にピクセルを変更するようなことを試みましたが、画像の品質が低かったため、周囲のピクセルは黒でもありませんでした。

Python で PIL を使用して、色とその周囲のものを置き換えるより良い方法を知っている人はいますか? これはおそらく、オブジェクトを完全に削除するために私が考えることができる唯一の確実な方法ですが、これを行う方法は考えられません.

画像の背景は白で、テキストは黒です。アーティファクトを残さずに、画像からテキストを完全に削除したいとしましょう。

誰かの助けを本当に感謝します!ありがとう

4

6 に答える 6

27

それを行う最良の方法は、 Gimpで使用されている「colortoalpha」アルゴリズムを使用して色を置き換えることです。それはあなたの場合には完璧に機能します。オープンソースのPythonフォトプロセッサphatchにPILを使用して、このアルゴリズムを再実装しました。完全な実装はここにあります。これは純粋な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)
于 2009-10-24T12:36:50.210 に答える
19

numpy と PIL の使用:

これにより、画像が shape の numpy 配列にロードされます。(W,H,3)ここWで、 は幅で、Hは高さです。配列の 3 番目の軸は、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 のタプルであり、 shape をdata持っているため、NumPy は shapeの(W,H,3)配列 にブロードキャスト して比較を実行します。shape のブール配列の結果。orig_color(W,H,3)data == orig_color(W,H,3)

(data == orig_color).all(axis = -1)(W,H)の RGB カラーがどこにあっても Trueである形状のブール配列dataですoriginal_color

于 2010-07-03T00:55:01.000 に答える
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)
于 2010-10-03T15:24:43.333 に答える
5

画像を 2 次元配列として表す必要があります。これは、ピクセルのリストのリストを作成するか、1 次元配列を巧妙な数学で 2 次元配列として表示することを意味します。次に、対象となるピクセルごとに、周囲のすべてのピクセルを見つける必要があります。したがって、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
于 2009-10-24T03:51:21.390 に答える
4

ピクセルが簡単に識別できない場合 (r < 100 および g < 100 および b < 100) も黒の領域と正しく一致しない場合、ノイズが多いことを意味します。

最善の方法は、領域を特定して必要な色で塗りつぶすことです。領域を手動で特定するか、エッジ検出によって特定することもできます。/

またはより洗練されたアプローチは、opencv ( http://opencv.willowgarage.com/wiki/ ) のようなライブラリを使用してオブジェクトを識別することです。

于 2009-10-24T05:02:24.627 に答える