Imagen pixelada con almohada

Estoy trabajando en un proyecto donde quiero tomar una foto de una cuadrícula de color como entrada (hecha con ladrillos Lego en este ejemplo) y devolver una imagen modificada mucho más pequeña.

Aquí hay un ejemplo de entrada:

Entrada

A continuación se muestra una imagen muy pequeña de 8×8 que sería el resultado:

Salida

    Aquí hay una versión mucho más grande del resultado esperado :

    Gran salida

    Aquí está mi código hasta ahora: solo funciona con imágenes en blanco y negro.

    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[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") 

    Y la salida devuelta por mi código:

    Salida real

    Mi progtwig funciona bien para imágenes en blanco y negro, pero necesito ayuda para cambiarlo para que funcione con varios colores (rojo, naranja, amarillo, verde claro, verde oscuro, azul claro, azul oscuro, púrpura, blanco y negro).

    ¡Gracias por adelantado!

    Estás haciendo algunas cosas mal.

    En primer lugar, debe usar PNG, no JPG para su salida. JPG presenta tantos artefactos, que las imágenes pequeñas como su salida se degeneran completamente.

    Entonces, debes reducir tu paleta. Es mucho más fácil trabajar con entradas que no contienen ruido.

    En primer lugar, inicialización aburrida:

     from PIL import Image import operator from collections import defaultdict import re input_path = 'input.jpg' output_path = 'output.png' size = (4,4) 

    Luego declaramos la paleta, que debe contener los colores de todos los ladrillos LEGO posibles. Tomé muestras de los valores a continuación de su imagen, pero puede usar blanco y negro como lo hace en su código, o cualquier color que desee, siempre que sean similares a los colores en la imagen de origen:

     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)) 

    El siguiente código declarará la paleta para PIL, ya que PIL necesita una matriz plana en lugar de una matriz de tuplas:

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

    Ahora podemos declarar una imagen que contendrá la paleta. Lo usaremos para reducir los colores de la imagen original más adelante.

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

    Aquí abrimos la imagen y la cuantizamos. Lo escalamos a un tamaño ocho veces mayor que el necesario, ya que vamos a muestrear la producción promedio más adelante.

     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 

    Después de esto, nuestra imagen se ve así:

    imagen cuantificada

    Necesitamos convertirlo de nuevo a RGB para que podamos muestrear píxeles ahora:

     img = img.convert('RGB') 

    Ahora vamos a construir nuestra imagen final. Para hacer esto, muestreamos cuántos píxeles de cada paleta de color contiene cada cuadrado en la imagen más grande. Luego elegiremos el color que aparezca con mayor frecuencia.

     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) 

    Finalmente, guardamos la salida:

     out.save(output_path) 

    El resultado:

    imagen pequeña

    Mejora en un 1600%:

    imagen grande

    Solo por diversión, abordé esto con ImageMagick, que también se puede llamar desde Python …

    En primer lugar, creo una pequeña paleta personalizada para que coincida con sus colores: su blanco no es muy blanco y su verde es diferente de la idea de verde de ImageMagick, así que utilicé hexágonos en lugar de nombres de colores.

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

    Si escala esa paleta, se ve así:

    introduzca la descripción de la imagen aquí

    Luego, redimensiono su imagen a 4×4, asigno el resultado a la paleta personalizada y lo escala de nuevo para que pueda verlo así:

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

    y aqui esta el resultado

    introduzca la descripción de la imagen aquí

    El blanco está apagado para que coincida con el “blanco” en su original.