我需要编写一个函数来获取图像并返回镜像(Y坐标永不改变),而不使用任何镜像或翻转 来自PIL的模块 我必须自己写。 我收到错误信息:
IndexError: image index out of range
我在这里错过了什么?
谢谢。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")
答案 0 :(得分:15)
使用ImageOps.mirror(image)水平翻转图像。
import Image
import ImageOps
img = Image.open(FILENAME)
mirror_img = ImageOps.mirror(img)
您的代码非常接近工作。你有一个“一个一个”的错误。
a=org.size[0]
...
new.putpixel((a,y),pixel)
假设org
宽100像素。然后第一次通过循环,你在(100,y)
放置一个像素。但像素的索引编号为0--99。这就是为什么(以及在哪里)你得到一个
IndexError: image index out of range
例外。
另外,请注意初始化和递减a
的循环中的位置。事实上,我建议不要使用a
。
相反,请使用
w,h = org.size
for x in range(w):
for y in range(h):
pixel = org.getpixel((x, y))
new.putpixel(EXPRESSION, pixel)
只需用一些公式替换EXPRESSION,以获得想要着色的像素的位置。
答案 1 :(得分:3)
您正在混合基于0和基于索引的索引。 x
的范围是0
到org.size[0]-1
。但a
的范围从org.size[0]
到1
,因为您从a=org.size[0]
开始并使用它,而不先减去。{/ p>
错误很可能来自这一行内的某个地方:
new.putpixel((a,y),pixel)
...在您第一次调用时,当您尝试在仅从(0-279,0-279)运行的图像中写入像素(280,0)时。
所以,而不是:
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
这样做:
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
但是一旦解决了这个问题,你就会遇到另一个问题。您每次通过外部循环将a
设置为org.size[0]
,而不是仅仅是第一次。然后每次通过内循环而不是外循环递减a
。因此,您最终会将原始图像中的每一行复制到从(279,0)到(0,279)的对角线。
所以,你需要这样做:
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
这就是为什么你应该尝试避免像这样手动修改索引的原因。你第一次尝试时从来没有做对。在第三次尝试时,您会看到看起来的内容,但只要您尝试第一张不在测试套件中的图片就会崩溃。最好是计算值而不是计算它们。例如:
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)
虽然我们正在使用它,但是如果您可以要求/依赖于PIL 1.1.6或更高版本,那么使用Image.load()
返回的数组会更加简单,效率更高,并且通常更容易调试:< / p>
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
如果您不能依赖1.1.6,可以使用getdata
获取可迭代的像素序列,使用它生成新的list
或其他序列(这意味着您可以使用列表理解map
,甚至通过例如np.array(org.getdata()).reshape(org.size)
)将它们输入numpy
,然后使用putdata
从结果中创建新图像。
当然getdata
和putdata
处理一维序列,而您希望将其视为二维序列。幸运的是,itertools
文档中的grouper
功能 - 您可以复制和粘贴,或只是pip install more-itertool
- 通常正是您想要的:
orgrows = more_itertools.grouper(org.size[0], org.getdata())
newrows = [list(reversed(row)) for row in orgrows]
new.putdata(newrows)
需要注意的一点是,Image.open(im)
可能不一定会以RGB模式返回您的图像。如果您只是将XYZ或P图像中的像素复制到RGB,则最终会分别出现变色垃圾或红色通道。您可能希望print org.mode
,可能还需要print org.pixel((0, 0))
以确保它实际上有3个通道(它们看起来像RGB)。
最简单的方法是在执行任何其他操作之前转换org
:
org=Image.open(im).convert('RGB')
当然,某些格式要么没有直接转换,要么需要显式矩阵或调色板。如果您获得ValueError
,则必须阅读转换输入类型的信息。