Question

J'essaie de supprimer une certaine couleur de mon image, mais cela ne fonctionne pas aussi bien que je l'espérais. J'ai essayé de faire la même chose que celle décrite ici utiliser la LIP pour rendre tout blanc pixels transparents? Cependant, la qualité de l'image est un peu dégradée et laisse donc un petit fantôme de pixels de couleur impairs autour desquels les éléments ont été supprimés. J'ai essayé quelque chose comme changer de pixel si les trois valeurs sont inférieures à 100, mais parce que l'image était de mauvaise qualité, les pixels environnants n'étaient même pas noirs.

Quelqu'un connaît-il une meilleure façon, avec PIL en Python, de remplacer une couleur et tout ce qui l'entoure? C’est probablement le seul moyen infaillible auquel je puisse penser pour enlever complètement les objets, mais je ne vois pas comment le faire.

La photo a un arrière-plan blanc et un texte en noir. Disons simplement que je veux supprimer entièrement le texte de l'image sans laisser d'artefacts.

J'apprécierais vraiment l'aide de quelqu'un! Merci

Était-ce utile?

La solution

Vous devrez représenter l'image sous forme de tableau à 2 dimensions. Cela signifie soit en faisant une liste de listes de pixels, soit en affichant le tableau à 1 dimension comme un tableau en 2D avec quelques astuces mathématiques. Ensuite, pour chaque pixel ciblé, vous devez rechercher tous les pixels environnants. Vous pouvez le faire avec un générateur de python ainsi:

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

Donc, vous l'utiliseriez comme ceci:

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

Autres conseils

La meilleure façon de le faire est d’utiliser la " couleur en alpha " algorithme utilisé pour Gimp remplacer une couleur. Cela fonctionnera parfaitement dans votre cas. J'ai réimplémenté cet algorithme en utilisant PIL pour un processeur de photo python open source phatch . Vous pouvez trouver la mise en œuvre complète ici . Ceci est une implémentation PIL pure et il n’a pas d’autres dépendances. Vous pouvez copier le code de fonction et l'utiliser. Voici un exemple utilisant Gimp:

alt text à  alt text

Vous pouvez appliquer la fonction color_to_alpha à l'image en utilisant le noir comme couleur. Collez ensuite l'image sur une couleur d'arrière-plan différente pour effectuer le remplacement.

À propos, cette implémentation utilise le module ImageMath dans PIL. C'est beaucoup plus efficace que d'accéder aux pixels avec getdata.

EDIT: voici le code complet:

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)

Utilisation de Numpy et de PIL:

Ceci charge l'image dans un tableau numpy de forme (W,H,3), où W est le width et H est la hauteur. Le troisième axe du tableau représente la couleur 3 canaux, 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()

Étant donné que orig_color est un tuple de longueur 3, et data a forme data == orig_color, NumPy diffusions (data == orig_color).all(axis = -1) à un tableau de forme (W,H) pour effectuer la comparaison original_color. Le résultat dans un tableau booléen de forme <=>.

<=> est un tableau booléen de forme <=> qui est vrai partout où la couleur RVB dans <=> est <=>.

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

Si les pixels ne sont pas facilement identifiables, par exemple, vous dites (r < 100 et g < 100 et b < 100) ne correspond pas non plus correctement à la région noire, cela signifie vous avez beaucoup de bruit.

Le meilleur moyen serait d’identifier une région et de la remplir avec la couleur de votre choix. Vous pouvez identifier la région manuellement ou par détection des contours, par exemple. http://bitecode.co.uk/2008/07/edge -detection-in-python /

ou une approche plus sophistiquée consisterait à utiliser une bibliothèque comme opencv ( http://opencv.willowgarage.com/ wiki / ) pour identifier les objets.

Cela fait partie de mon code, le résultat voudrait: source

cible

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")
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top