2015-05-29 15 views
7

Sto lavorando a un progetto in cui voglio scattare una foto di una griglia colorata come input (realizzata con mattoncini Lego in questo esempio) e restituire un'immagine modificata molto più piccola.Immagine pixel con cuscino

Ecco un ingresso esempio:

Input

seguito è un'immagine molto piccola 8x8 che sarebbe il risultato:

Output

Qui è un molto versione più grande del risultato previsto::

Big Output

Ecco il mio codice finora: Funziona solo con le immagini in bianco e nero.

from PIL import Image 
import re 

black = [(110,110,110),(0,0,0)] #The highest value and the lowest RGB value for the color black 

img = Image.open("input.jpg") #The input image 
size = (8,8) #The dimensions of the output image 

out = img.resize(size,resample=Image.LANCZOS) #Resize the image 

for y in range(size[0]): #loop through every pixel 
    for x in range(size[1]): 

     if out.getpixel((x,y)) <= black[0] and out.getpixel((x,y)) >= black[1]: #check to see if the pixel is within the accepted black values 

      out.putpixel((x,y), (0,0,0)) #Give the current pixel true color 
     else: 
      #otherwise make the pixel black 
      out.putpixel((x,y), (255,255,255)) #Give the current pixel true color 

"""Save the pixelated image""" 
out.save("output.jpg") 

E l'uscita restituito dal mio codice:

Actual Output

Il mio programma funziona bene per le immagini in bianco e nero, ma ho bisogno di aiuto cambiare per funzionare con diversi colori (rosso, arancione, giallo, verde chiaro, verde scuro, blu chiaro, blu scuro, viola, bianco e nero).

Grazie in anticipo!

+0

La miniatura non fa ciò che vuoi? –

risposta

7

Stai facendo alcune cose sbagliate.

Prima di tutto, è necessario utilizzare PNG, non JPG per l'output. JPG introduce così tanti artefatti, che le immagini di piccole dimensioni come il tuo output vengono completamente degenerate.

Quindi, è necessario ridurre la tavolozza. È molto più semplice lavorare con input senza rumore.

Prima di tutto, l'inizializzazione noioso:

from PIL import Image 
import operator 
from collections import defaultdict 
import re 

input_path = 'input.jpg' 
output_path = 'output.png' 
size = (4,4) 

Poi ci dichiariamo la tavolozza - questo dovrebbe contenere i colori di tutte le possibili mattoncini LEGO. Ho provato i valori al di sotto dalla vostra immagine, ma è possibile utilizzare in bianco e nero, come si fa nel codice, o tutti i colori che volete fintanto che sono simili ai colori l'immagine di origine in:

palette = [ 
    (45, 50, 50), #black 
    (240, 68, 64), #red 
    (211, 223, 223), #white 
    (160, 161, 67), #green 
    (233, 129, 76), #orange 
] 
while len(palette) < 256: 
    palette.append((0, 0, 0)) 

Il codice qui sotto dichiarerà tavolozza per PIL, dal momento che ha bisogno di PIL matrice piana piuttosto che array di tuple:

flat_palette = reduce(lambda a, b: a+b, palette) 
assert len(flat_palette) == 768 

Ora possiamo dichiarare un'immagine che conterrà la tavolozza. Lo useremo per ridurre i colori dell'immagine originale in un secondo momento.

palette_img = Image.new('P', (1, 1), 0) 
palette_img.putpalette(flat_palette) 

Qui apriamo l'immagine e la quantizziamo. Lo scaliamo fino a dimensioni otto volte più grandi del necessario, poiché in seguito andremo a campionare l'output medio.

multiplier = 8 
img = Image.open(input_path) 
img = img.resize((size[0] * multiplier, size[1] * multiplier), Image.BICUBIC) 
img = img.quantize(palette=palette_img) #reduce the palette 

Dopo questo, la nostra immagine assomiglia a questo:

quantized image

Abbiamo bisogno di riconvertirlo in RGB in modo da poter assaggiare pixel ora:

img = img.convert('RGB') 

Ora noi costruiremo la nostra immagine finale. Per fare ciò, vedremo quanti pixel di ciascuna tavolozza colorano ogni quadrato nell'immagine più grande. Quindi sceglieremo il colore che si verifica più spesso.

out = Image.new('RGB', size) 
for x in range(size[0]): 
    for y in range(size[1]): 
     #sample at get average color in the corresponding square 
     histogram = defaultdict(int) 
     for x2 in range(x * multiplier, (x + 1) * multiplier): 
      for y2 in range(y * multiplier, (y + 1) * multiplier): 
       histogram[img.getpixel((x2,y2))] += 1 
     color = max(histogram.iteritems(), key=operator.itemgetter(1))[0] 
     out.putpixel((x, y), color) 

, infine, salvare l'output:

out.save(output_path) 

Il risultato:

small image

in scala da 1600%:

big image

+0

Ciao, ho appena avuto l'abitudine di usare il codice e mi ha lanciato alcuni errori che sembrano correlati alla versione di Python. Sto usando Python 3.4.2. In quale versione è stato scritto questo codice? –

+0

Python 3.4.3, ma io uso Pillow piuttosto che PIL (è una forchetta più attiva). Potrebbero esserci modifiche API minime. –

+1

Grazie per le informazioni. Sono felice di dire che ho lavorato tutto ora. –

3

Solo per divertimento, ho affrontato questo con ImageMagick - che è anche chiamabile da Python ...

Prima di tutto, creo una piccola tavolozza personalizzata per abbinare i tuoi colori - il tuo bianco non è molto bianco e il tuo verde è diverso dall'idea di Green di ImageMagick, quindi ho usato l'hex per loro anziché i nomi dei colori.

convert xc:black xc:red xc:"rgb(200,200,200)" xc:"rgb(168,228,23)" xc:orange +append palette.png 

Se mi scala quella tavolozza up, sembra che questo:

enter image description here

Poi ho ridimensionare l'immagine verso il basso per 4x4 e mappa il risultato alla tavolozza personalizzata e scalare il backup in modo si può vedere in questo modo:

convert lego.jpg -resize 4x4! +dither -remap palette.png -scale 1600 result.png 

ed ecco il risultato

enter image description here

Il bianco è spento per corrispondere allo "bianco" nel vostro originale.

Problemi correlati