翻转图像/镜像

时间:2013-01-06 13:35:41

标签: python image-processing

我需要编写一个函数来获取图像并返回镜像(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")

2 个答案:

答案 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的范围是0org.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从结果中创建新图像。

当然getdataputdata处理一维序列,而您希望将其视为二维序列。幸运的是,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,则必须阅读转换输入类型的信息。