翻转图像/镜像

问题描述 投票:0回答:3

我需要编写一个函数来获取图像并返回镜像(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")
python image-processing
3个回答
19
投票

使用 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 替换为您想要着色的像素位置的公式即可。


3
投票

您混淆了基于 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

,则您必须阅读有关转换输入类型的信息。

    


0
投票
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)

	
© www.soinside.com 2019 - 2024. All rights reserved.