【问题标题】:Using PIL's ImageDraw Module使用 PIL 的 ImageDraw 模块
【发布时间】:2011-01-31 04:44:23
【问题描述】:

我正在尝试使用 PIL 的 ImageDraw 模块进行单个像素操作。下面的代码应该创建 Tkinter 画布小部件。然后打开一个图像,将一个像素的颜色更改为红色,然后将图像嵌入到画布小部件中。但是,它似乎不起作用。

我的代码:

import Tkinter
from PIL import ImageTk, Image, ImageDraw


class image_manip(Tkinter.Tk):

    def __init__(self):
        Tkinter.Tk.__init__(self)

        self.configure(bg='red')

        self.ImbImage = Tkinter.Canvas(self, highlightthickness=0, bd=0, bg='blue')
        self.ImbImage.pack()

        im = Image.open(r'C:\Python26\Suite\test.png')

        print im.format, im.size, im.mode

        im = ImageDraw.Draw(im)

        im = im.point((0, 0), fill="red")

        self.i = ImageTk.PhotoImage(im)
        self.ImbImage.create_image(139, 59, image=self.i)




def run():
    image_manip().mainloop()
if __name__ == "__main__":
    run()

运行代码时出现以下错误:

Exception AttributeError: "PhotoImage instance has no attribute '_PhotoImage__photo'" in <bound method PhotoImage.__del__ of <PIL.ImageTk.PhotoImage instance at 0x05DF7698>> ignored
Traceback (most recent call last):
  File "<string>", line 245, in run_nodebug
  File "C:\Python26\Suite\test_image.py", line 30, in <module>
    run()
  File "C:\Python26\Suite\test_image.py", line 28, in run
    image_manip().mainloop()
  File "C:\Python26\Suite\test_image.py", line 20, in __init__
    self.i = ImageTk.PhotoImage(im)
  File "C:\Python26\lib\site-packages\PIL\ImageTk.py", line 109, in __init__
    mode = Image.getmodebase(mode)
  File "C:\Python26\lib\site-packages\PIL\Image.py", line 245, in getmodebase
    return ImageMode.getmode(mode).basemode
  File "C:\Python26\lib\site-packages\PIL\ImageMode.py", line 50, in getmode
    return _modes[mode]
KeyError: None

【问题讨论】:

    标签: python image-processing image-manipulation tkinter python-imaging-library


    【解决方案1】:

    您的问题是您将im 重新分配给多个事物。

    im = Image.open(r'C:\Python26\Suite\test.png')
    im = ImageDraw.Draw(im)
    im = im.point((0, 0), fill="red")
    

    当您调用ImageTk.PhotoImage(im) 时,该函数需要一个PIL 图像对象,但您已经将im 分配给point() 函数的结果,该函数实际上返回None。这就是你的问题的原因。

    我认为您误解了 ImageDraw 的工作原理。以here 为例。基本上:

    • 如果你想在你的 PIL 图像上绘制一些复杂的东西,你需要一个 ImageDraw 的实例
    • 您仍然需要将 PIL 图像保存在某个变量中
    • ImageDraw 直接在您在施工期间提供的图像上绘画
    • 您可以随时丢弃ImageDraw 对象。它不包含任何重要信息,因为所有内容都直接写入图像。

    这里是固定的__init__ 方法:

    def __init__(self):
        Tkinter.Tk.__init__(self)
        self.configure(bg='red')
        im = Image.open(r'C:\Python26\Suite\test.png')
        width, height = im.size
        self.ImbImage = Tkinter.Canvas(self, highlightthickness=0, bd=0, bg='red', width=width, height=height)
        self.ImbImage.pack()
        print im.format, im.size, im.mode
    
        draw = ImageDraw.Draw(im)
        draw.rectangle([0, 0, 40, 40 ],  fill="green")
        del draw
    
        self.i = ImageTk.PhotoImage(im)
        self.ImbImage.create_image(width/2, height/2, image=self.i)
    

    你会注意到我已经修复了一些问题:

    • 将画布大小设置为图像大小。显然,您需要先加载图像,然后才能找到图像大小,所以我稍微移动了一下。
    • ImageDraw 实例分配给单独的变量
    • 画一个绿色矩形而不是一个点,因为这样会更显眼。请注意,您不需要获取draw.rectangle 的返回值——它实际上返回None,就像大多数其他绘图函数一样。
    • 绘制完成后删除draw变量
    • 调用create_image时将图像在画布中居中

    【讨论】:

    • 请注意,您必须将 ImageTk.PhotoImage(im) 分配给 persistent(非垃圾收集)变量。 Tkinter 中有一个错误,如果您将图像分配给局部变量并在 create_image 中使用它,图像将被垃圾收集。见infohost.nmt.edu/tcc/help/pubs/pil/image-tk.html
    猜你喜欢
    • 2011-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-20
    • 2018-04-03
    • 1970-01-01
    相关资源
    最近更新 更多