varias recorrer procesamiento por para mostrar matriz manipular manipulacion librerias imagenes imagen descomponer convertir con como binario python image-processing python-imaging-library

python - recorrer - manipulacion de imagenes con numpy



¿Cómo convierto cualquier imagen en una imagen paletizada de 4 colores usando la Biblioteca de imágenes de Python? (4)

John, encontré ese primer enlace también, pero no me ayudó directamente con el problema. Sin embargo, me hizo mirar más profundamente en la cuantización.

Ayer se me ocurrió esto antes de acostarme:

import sys import PIL import Image PALETTE = [ 0, 0, 0, # black, 00 0, 255, 0, # green, 01 255, 0, 0, # red, 10 255, 255, 0, # yellow, 11 ] + [0, ] * 252 * 3 # a palette image to use for quant pimage = Image.new("P", (1, 1), 0) pimage.putpalette(PALETTE) # open the source image image = Image.open(sys.argv[1]) image = image.convert("RGB") # quantize it using our palette image imagep = image.quantize(palette=pimage) # save imagep.save(''/tmp/cga.png'')

TZ.TZIOY, tu solución parece funcionar según los mismos principios. Felicitaciones, debería haber dejado de trabajar en eso y esperé tu respuesta. El mío es un poco más simple, aunque definitivamente no más lógico que el tuyo. PIL es engorroso de usar. El tuyo explica qué está sucediendo para hacerlo.

Tengo un dispositivo que admite gráficos de 4 colores (muy parecido a CGA en los viejos tiempos).

Quería usar PIL para leer la imagen y convertirla usando mi paleta de 4 colores (de rojo, verde, amarillo, negro), pero no puedo entender si es siquiera posible. Encontré algunas publicaciones de listas de correo que parecen sugerir que otras personas han intentado hacerlo y han fallado.

¡Un simple ejemplo de pitón sería muy apreciado!

Puntos de bonificación si agrega algo que luego convierte la imagen en una cadena de bytes donde cada byte representa 4 píxeles de datos (con cada dos bits representando un color de 0 a 3)


Primero: su paleta de cuatro colores (negro, verde, rojo, amarillo) no tiene componente azul. Por lo tanto, debe aceptar que su imagen de salida apenas se aproximará a la imagen de entrada, a menos que no haya un componente azul para comenzar.

Prueba este código:

import Image def estimate_color(c, bit, c_error): c_new= c - c_error if c_new > 127: c_bit= bit c_error= 255 - c_new else: c_bit= 0 c_error= -c_new return c_bit, c_error def image2cga(im): "Produce a sequence of CGA pixels from image im" im_width= im.size[0] for index, (r, g, b) in enumerate(im.getdata()): if index % im_width == 0: # start of a line r_error= g_error= 0 r_bit, r_error= estimate_color(r, 1, r_error) g_bit, g_error= estimate_color(g, 2, g_error) yield r_bit|g_bit def cvt2cga(imgfn): "Convert an RGB image to (K, R, G, Y) CGA image" inp_im= Image.open(imgfn) # assume it''s RGB out_im= Image.new("P", inp_im.size, None) out_im.putpalette( ( 0, 0, 0, 255, 0, 0, 0, 255, 0, 255, 255, 0, ) ) out_im.putdata(list(image2cga(inp_im))) return out_im if __name__ == "__main__": import sys, os for imgfn in sys.argv[1:]: im= cvt2cga(imgfn) dirname, filename= os.path.split(imgfn) name, ext= os.path.splitext(filename) newpathname= os.path.join(dirname, "cga-%s.png" % name) im.save(newpathname)

Esto crea una imagen de paleta PNG con solo las primeras cuatro entradas de paleta configuradas a sus colores. Esta imagen de muestra:

http://tzotzioy.googlepages.com/new_pic_baby2.jpg

se convierte

http://tzotzioy.googlepages.com/cga-new_pic_baby2.png

Es trivial tomar la salida de image2cga (produce una secuencia de 0-3 valores) y empacar cada cuatro valores en un byte.

Si necesita ayuda sobre lo que hace el código, pregunte y lo explicaré.

EDIT1: No reinventar la rueda

Por supuesto, resulta que estaba demasiado entusiasta y, como Thomas descubrió, el método Image.quantize puede tomar una imagen de paleta como argumento y hacer la cuantificación con mejores resultados que mi método ad-hoc anterior:

def cga_quantize(image): pal_image= Image.new("P", (1,1)) pal_image.putpalette( (0,0,0, 0,255,0, 255,0,0, 255,255,0) + (0,0,0)*252) return image.convert("RGB").quantize(palette=pal_image)

EDIT1, cont: empaqueta los píxeles en bytes

Para "valor agregado", aquí sigue el código para producir la cadena empaquetada (4 píxeles por byte):

import itertools as it # setup: create a map with tuples [(0,0,0,0)‥(3,3,3,3)] as keys # and values [chr(0)‥chr(255)], because PIL does not yet support # 4 colour palette images TUPLE2CHAR= {} # Assume (b7, b6) are pixel0, (b5, b4) are pixel1… # Call it "big endian" KEY_BUILDER= [ (0, 64, 128, 192), # pixel0 value used as index (0, 16, 32, 48), # pixel1 (0, 4, 8, 12), # pixel2 (0, 1, 2, 3), # pixel3 ] # For "little endian", uncomment the following line ## KEY_BUILDER.reverse() # python2.6 has itertools.product, but for compatibility purposes # let''s do it verbosely: for ix0, px0 in enumerate(KEY_BUILDER[0]): for ix1, px1 in enumerate(KEY_BUILDER[1]): for ix2, px2 in enumerate(KEY_BUILDER[2]): for ix3, px3 in enumerate(KEY_BUILDER[3]): TUPLE2CHAR[ix0,ix1,ix2,ix3]= chr(px0+px1+px2+px3) # Another helper function, copied almost verbatim from itertools docs def grouper(n, iterable, padvalue=None): "grouper(3, ''abcdefg'', ''x'') --> (''a'',''b'',''c''), (''d'',''e'',''f''), (''g'',''x'',''x'')" return it.izip(*[it.chain(iterable, it.repeat(padvalue, n-1))]*n) # now the functions def seq2str(seq): """Takes a sequence of [0..3] values and packs them into bytes using two bits per value""" return ''''.join( TUPLE2CHAR[four_pixel] for four_pixel in grouper(4, seq, 0)) # and the image related function # Note that the following function is correct, # but is not useful for Windows 16 colour bitmaps, # which start at the *bottom* row… def image2str(img): return seq2str(img.getdata())



import sys import PIL from PIL import Image def quantizetopalette(silf, palette, dither=False): """Convert an RGB or L mode image to use a given P image''s palette.""" silf.load() # use palette from reference image palette.load() if palette.mode != "P": raise ValueError("bad mode for palette image") if silf.mode != "RGB" and silf.mode != "L": raise ValueError( "only RGB or L mode images can be quantized to a palette" ) im = silf.im.convert("P", 1 if dither else 0, palette.im) # the 0 above means turn OFF dithering return silf._makeself(im) if __name__ == "__main__": import sys, os for imgfn in sys.argv[1:]: palettedata = [ 0, 0, 0, 0, 255, 0, 255, 0, 0, 255, 255, 0,] palimage = Image.new(''P'', (16, 16)) palimage.putpalette(palettedata + [0, ] * 252 * 3) oldimage = Image.open(sys.argv[1]) newimage = quantizetopalette(oldimage, palimage, dither=False) dirname, filename= os.path.split(imgfn) name, ext= os.path.splitext(filename) newpathname= os.path.join(dirname, "cga-%s.png" % name) newimage.save(newpathname)

Para aquellos que no querían Dithering para obtener colores sólidos. Modded: Convierta la imagen a una paleta específica usando PIL sin difuminado con las dos soluciones en este hilo. Aunque este hilo es antiguo, algunos de nosotros queremos esa información. Kudios