18

Sto utilizzando lo Python Imaging Library per colorare un'immagine in bianco e nero con una tabella di ricerca che definisce le relazioni dei colori. La tabella di ricerca è semplicemente una lista di 256 elementi di tuple RGB:Utilizzo del metodo Image.point() in PIL per manipolare i dati dei pixel

>>> len(colors) 
256 
>>> colors[0] 
(255, 237, 237) 
>>> colors[127] 
(50, 196, 33) 
>>> 

La mia prima versione ha usato le getpixel() e putpixel() metodi:

for x in range(w): 
     for y in range(h): 
      pix = img.getpixel((x,y)) 
      img.putpixel((x,y), colors[pix[0]]) 

Questo era terribilmente lento. Un rapporto profile indicava i metodi putpixel e getpixel come responsabili. Una piccola indagine (leggi i documenti) e trovo "Nota che questo metodo è relativamente lento." re: putpixel. (effettiva esecuzione: 53s in putpixel e 50s getpixel per un'immagine di 1024x1024)

Sulla base suggerimento nella documentazione, ho usato im.load() e accesso pixel diretto invece:

pixels = img.load() 
    for x in range(w): 
     for y in range(h): 
      pix = pixels[x, y] 
      pixels[x, y] = colors[pix[0]]     

Processing accelerato da un ordine di grandezza, ma è ancora lento: circa 3,5 s per elaborare un'immagine 1024x1024.

Uno studio più approfondito dei documenti Pil sembra indicare Image.point() è esattamente destinati a questo scopo:

im.point(table) => immagine

im.point(function) => immagine

restituisce una copia dell'immagine in cui ogni pixel è stato mappato attraverso la tabella data. La tabella dovrebbe contenere 256 valori per banda nell'immagine. Se invece viene usata una funzione, dovrebbe prendere un singolo argomento. La funzione viene chiamata una volta per ogni possibile valore di pixel e la tabella risultante viene applicata a tutte le bande dell'immagine.

Ho passato un po 'di tempo a hackerare con l'interfaccia, ma non riesco a farlo bene. Perdona la mia ignoranza, ma i documenti di PIL sono bruschi e non ho molta esperienza nell'elaborazione delle immagini. Ho cercato un po 'su google e ho trovato alcuni esempi, ma nulla ha reso l'uso "click" per me. Quindi, finalmente, le mie domande:

  • Image.point() è lo strumento giusto per questo lavoro?
  • Quale formato/struttura ha Image.point() la tabella?
  • Qualcuno può mettere a punto un'implementazione di esempio? Ogni iterazione che ho provato fino ad ora si è conclusa con un'immagine nera dritta.

risposta

15

Is Image.point() lo strumento giusto per questo lavoro?

Sì, Image.point() è perfetto per questo lavoro

quale formato/struttura fa Image.point() si aspettano che il tavolo?

Si dovrebbe appiattire la lista così invece di [(12, 140, 10), (10, 100, 200), ...] uso:

[12, 140, 10, 10, 100, 200, ...] 

Ecco un rapido esempio ho appena provato:

im = im.point(range(256, 0, -1) * 3) 

alt text alt text

E dal modo, se hai bisogno di più controllo sui colori e senti che Image.point non fa per te puoi anche usare Image.getdata e Image.putdata per cambiare i colori più rapidamente rispetto a entrambi gli standard load e putpixel. È più lento di Image.point però.

Image.getdata fornisce l'elenco di tutti i pixel, li modifica e li riscrive utilizzando Image.putdata. È così semplice Ma prova a farlo usando prima Image.point.


EDIT

ho commesso un errore nella prima spiegazione, mi spiego correttamente ora:

La tabella di colore in realtà è come questo

[0, 1, 2, 3, 4, 5, ...255, 0, 1, 2, 3, ....255, 0, 1, 2, 3, ...255] 

Ogni banda gamma accanto all'altro. Per cambiare il colore (0, 0, 0) a (10, 100, 10) si ha bisogno di diventare in questo modo:

[10, 1, 2, 3, 4, 5, ...255, 100, 1, 2, 3, ....255, 10, 1, 2, 3, ...255] 

per trasformare la vostra lista di colore nel formato giusto provare questo:

table = sum(zip(*colors),()) 

Penso che il mio primo esempio dovrebbe dimostrare il formato per voi.

+0

appiattire la lista? ok, ma come funziona? Voglio pixel con valore 0 -> (12, 140, 10) e pixel con valore 255 -> (254, 237, 220). –

+4

sai, penso che questo potrebbe essere L'unico posto su Internet in cui è descritto il formato previsto di tale tabella. // Ho appena ottenuto img.point() lavorando con la tabella di ricerca, grazie alla tua descrizione. I risultati non sono esattamente quello che mi aspettavo, ma ho abbastanza per incappare in giro e capirlo. Grazie mille! –

+0

@ J.J., Il formato non è molto evidente. Ho fatto un errore nella mia prima spiegazione e l'ho risolto ora. Spero di aver capito bene questa volta. Dormirò quindi non potrò rispondere alle domande. –

3

Penso che potrebbe essere più tipico point su una base di banda-by-band in questo modo (sollevato direttamente dal PIL tutorial):

# split the image into individual bands 
source = im.split() 

R, G, B = 0, 1, 2 

# select regions where red is less than 100 
mask = source[R].point(lambda i: i < 100 and 255) 

# process the green band 
out = source[G].point(lambda i: i * 0.7) 

# paste the processed band back, but only where red was < 100 
source[G].paste(out, None, mask) 

# build a new multiband image 
im = Image.merge(im.mode, source) 
+0

il formato tabella ha più senso con una singola banda, questo è sicuro. Potrei dover utilizzare questo percorso per gestire il canale alfa con un caso speciale ... –

+0

è veloce e veloce grazie. – Conex

Problemi correlati