我需要编写一个函数来获取图像并返回镜像(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")
使用 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 替换为您想要着色的像素位置的公式即可。
您混淆了基于 0 的索引和基于 1 的索引。
x
范围从 0
到 org.size[0]-1
。但 a
的范围是从 org.size[0]
到 1
,因为您从 a=org.size[0]
开始并使用它,而无需先进行减法。
错误很可能来自此行内的某个地方:
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()
返回的数组要简单得多,效率更高,并且通常更容易调试:
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
,甚至可以通过以下方式将它们输入 numpy
:
np.array(org.getdata()).reshape(org.size)
),然后使用 putdata
从结果创建新图像。 当然
getdata
和
putdata
处理 1D 序列,而您想将其视为 2D 序列。幸运的是,grouper
文档中的itertools
函数(您可以复制和粘贴,或者只是
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
,则您必须阅读有关转换输入类型的信息。
image.transpose
:
from PIL import Image
img = Image.open(FILENAME)
x_flipped_img = image.transpose(Image.FLIP_TOP_BOTTOM) # along the x-axis (top to bottom)
y_flipped_img = image.transpose(Image.FLIP_LEFT_RIGHT) # along the y-axis (left to right)