Volteo de imagen / imagen de espejo

Necesito escribir una función que obtenga una imagen y devuelva una imagen espejo (la coordenada Y nunca cambia), sin usar ningún módulo espejo o flip de PIL.
Tengo que escribirlo yo mismo. Estoy recibiendo un mensaje de error:

IndexError: image index out of range 

¿que me estoy perdiendo aqui?

gracias.

 from os.path import exists import tkMessageBox, tkFileDialog from PIL import Image, ImageTk, ImageFilter def flip(im): '''Flips a picutre horizontally, and returns a new image that is a mirror view of the original''' org=Image.open(im) new=Image.new("RGB",org.size) for x in range(org.size[0]): a=org.size[0] for y in range(org.size[1]): pixel=org.getpixel((x,y)) new.putpixel((a,y),pixel) a-=1 new.save("new.bmp","bmp") 

Estás mezclando la indexación basada en 0 y la basada en 1. x varía de 0 a org.size[0]-1 . Pero a rango va desde org.size[0] a 1 , porque comienzas con a=org.size[0] y lo usas, sin restar primero.

Lo más probable es que el error venga de algún lugar dentro de esta línea:

 new.putpixel((a,y),pixel) 

… en su primera llamada, cuando intenta escribir píxeles (280, 0) en una imagen que solo se ejecuta desde (0-279, 0-279).

Entonces, en lugar de esto:

 for x in range(org.size[0]): a=org.size[0] for y in range(org.size[1]): pixel=org.getpixel((x,y)) new.putpixel((a,y),pixel) a-=1 

Hacer esto:

 for x in range(org.size[0]): a=org.size[0]-1 for y in range(org.size[1]): pixel=org.getpixel((x,y)) new.putpixel((a,y),pixel) a-=1 

Pero una vez que solucione esto, se encontrará con otro problema. Establece a en org.size[0] cada vez a través del bucle externo, en lugar de solo la primera vez. Y luego decrementas a cada vez a través del bucle interno, en lugar del bucle externo. Entonces, vas a terminar copiando cada línea de la imagen original en la diagonal que va desde (279,0) a (0,279).

Entonces, necesitas hacer esto:

 a=org.size[0]-1 for x in range(org.size[0]): for y in range(org.size[1]): pixel=org.getpixel((x,y)) new.putpixel((a,y),pixel) a-=1 

Este tipo de cosas es exactamente la razón por la que debe intentar evitar la modificación manual de índices como este. Nunca lo entiendes bien en tu primer bash. En su tercer bash, obtiene algo que se ve bien, pero se bloquea tan pronto como prueba la primera imagen que no estaba en su suite de prueba. Es mejor calcular los valores en lugar de contarlos. Por ejemplo:

 for x in range(org.size[0]): flipped_x = org.size[0] - x - 1 for y in range(org.size[1]): pixel=org.getpixel((x,y)) new.putpixel((flipped_x,y),pixel) 

Mientras estamos en ello, si puede requerir / depender de PIL 1.1.6 o posterior, usar la matriz devuelta por Image.load() es significativamente más simple, mucho más eficiente y, a menudo, más fácil de depurar:

 orgpixels, newpixels = org.load(), new.load() for x in range(org.size[0]): flipped_x = org.size[0] - x - 1 for y in range(org.size[1]): pixel=orgpixels[x, y] newpixels[flipped_x, y] = pixel 

Si no puede confiar en 1.1.6, puede usar getdata para obtener una secuencia iterable de píxeles, usarla para generar una nueva list u otra secuencia (lo que significa que puede usar una lista de comprensión, un map , incluso para alimentarlos en un numpy a través de, por ejemplo, np.array(org.getdata()).reshape(org.size) ), y luego use putdata para crear la nueva imagen del resultado.

Por supuesto, getdata y putdata tratan con una secuencia 1D, mientras que usted desea tratarla como una secuencia 2D. Afortunadamente, la función de itertools en los documentos de itertools , que puede copiar y pegar, o simplemente pip install more-itertool es exactamente lo que desea:

 orgrows = more_itertools.grouper(org.size[0], org.getdata()) newrows = [list(reversed(row)) for row in orgrows] new.putdata(newrows) 

Una cosa a tener en cuenta es que Image.open(im) puede no necesariamente devolverte una imagen en modo RGB. Si solo copia píxeles de, por ejemplo, una imagen XYZ o P a un RGB, terminará con basura descolorida o solo el canal rojo, respectivamente. Es posible que desee print org.mode y posiblemente print org.pixel((0, 0)) para asegurarse de que realmente tenga 3 canales (y que se vean como RGB) `.

La forma más fácil de hacerlo es convertir org antes de hacer cualquier otra cosa:

 org=Image.open(im).convert('RGB') 

Por supuesto, algunos formatos no tienen conversiones directas o requieren una matriz explícita o una paleta de colores. Si obtiene un ValueError , tendrá que leer sobre la conversión de su tipo de entrada.

Use ImageOps.mirror (imagen) para voltear la imagen horizontalmente.

 import Image import ImageOps img = Image.open(FILENAME) mirror_img = ImageOps.mirror(img) 

Su código está muy cerca de trabajar. Tienes un error “off-by-one”.

 a=org.size[0] ... new.putpixel((a,y),pixel) 

Digamos que la org es de 100 píxeles de ancho. Luego, la primera vez a través del bucle está colocando un píxel en (100,y) . Pero los píxeles se indexan desde 0–99. Esta es la razón por la que (y dónde) obtiene un IndexError: image index out of range .


Además, tenga cuidado con los lugares en los que está inicializando y disminuyendo a . De hecho, sugeriría no usar a en absoluto.

Más bien, use

 w,h = org.size for x in range(w): for y in range(h): pixel = org.getpixel((x, y)) new.putpixel(EXPRESSION, pixel) 

y simplemente reemplace EXPRESSION con alguna fórmula para la ubicación del píxel que desea colorear.