Domanda

Sto provando a rimuovere un determinato colore dalla mia immagine, ma non funziona come speravo. Ho provato a fare la stessa cosa vista qui Uso di PIL per rendere tutto bianco pixel trasparenti? tuttavia la qualità dell'immagine è un po 'imperfetta, quindi lascia un po' di fantasmi di pixel di colore strano attorno a dove è stato rimosso. Ho provato a fare qualcosa come cambiare pixel se tutti e tre i valori sono inferiori a 100 ma poiché l'immagine era di scarsa qualità i pixel circostanti non erano nemmeno neri.

Qualcuno conosce un modo migliore con PIL in Python per sostituire un colore e tutto ciò che lo circonda? Questo è probabilmente l'unico modo sicuro in cui riesco a pensare di rimuovere completamente gli oggetti, ma non riesco a pensare a un modo per farlo.

L'immagine ha uno sfondo bianco e il testo è nero. Diciamo solo che voglio rimuovere il testo interamente dall'immagine senza lasciare alcun artefatto.

Gradirei davvero l'aiuto di qualcuno! Grazie

È stato utile?

Soluzione

Dovrai rappresentare l'immagine come un array bidimensionale. Ciò significa o creare un elenco di elenchi di pixel o visualizzare l'array monodimensionale come un 2d con una matematica intelligente. Quindi, per ogni pixel targetizzato, dovrai trovare tutti i pixel circostanti. Puoi farlo con un generatore Python così:

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

Quindi, lo useresti in questo modo:

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

Altri suggerimenti

Il modo migliore per farlo è usare " color in alpha " algoritmo utilizzato in Gimp per sostituire un colore. Funzionerà perfettamente nel tuo caso. Ho reimplementato questo algoritmo usando PIL per un processore fotografico open source Python phatch . Puoi trovare l'implementazione completa qui . Questa è una pura implementazione PIL e non ha altre dipendenze. È possibile copiare il codice funzione e utilizzarlo. Ecco un esempio usando Gimp:

alt text a  alt text

Puoi applicare la funzione color_to_alpha sull'immagine usando il nero come colore. Quindi incolla l'immagine su un colore di sfondo diverso per eseguire la sostituzione.

A proposito, questa implementazione usa il modulo ImageMath in PIL. È molto più efficiente dell'accesso ai pixel usando getdata.

MODIFICA: ecco il codice completo:

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)

Uso di numpy e PIL:

Questo carica l'immagine in una matrice intorpidita di forma (W,H,3), dove W è il larghezza e H è l'altezza. Il terzo asse dell'array rappresenta il 3 colori canali, 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()

Poiché orig_color è una tupla di lunghezza 3 e data ha forma data == orig_color, NumPy trasmissioni (data == orig_color).all(axis = -1) a una matrice di forme (W,H) per eseguire il confronto original_color. Il risultato è una matrice booleana di forma <=>.

<=> è un array booleano di forma <=> che è True ovunque il colore RGB in <=> sia <=>.

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

Se i pixel non sono facilmente identificabili, ad esempio dici (r < 100 e g < 100 e b < 100) anche non corrispondono correttamente alla regione nera, significa hai molto rumore.

Il modo migliore sarebbe quello di identificare una regione e riempirla con il colore desiderato, è possibile identificare la regione manualmente o potrebbe essere rilevando i bordi, ad es. http://bitecode.co.uk/2008/07/edge rilevamento delle-in-python /

o un approccio più sofisticato sarebbe usare una libreria come opencv ( http://opencv.willowgarage.com/ wiki / ) per identificare gli oggetti.

Questo fa parte del mio codice, il risultato vorrebbe: 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")
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top