使用 PIL 的 ImageDraw 模块

发布于 2024-10-15 04:52:45 字数 1749 浏览 2 评论 0原文

我正在尝试使用 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

I'm trying to do individual pixel manipulation using PIL's ImageDraw Module. The code bellow is supposed to create Tkinter canvas widget. Then open an image, change one pixel's color to red, then embed the image in the canvas widget. However, it doesn't seem to be working.

My Code:

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()

I get the following error upon running my code:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

德意的啸 2024-10-22 04:52:45

您的问题是您正在将 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 的工作原理。请查看此处示例。基本上:

  • 如果你想在 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 时将图像置于画布的中心

Your problem is you're reassigning im to multiple things.

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

When you call ImageTk.PhotoImage(im), the function expects a PIL image object, but you've already assigned im to the result of the point() function, which actually returns None. This is the cause of your problem.

I think you're misunderstanding how ImageDraw works. Have a look here for an example. Basically:

  • You need an instance of ImageDraw if you want to draw something complicated on your PIL Image
  • You still need to keep your PIL image in some variable
  • ImageDraw paints directly on the image you've given it during construction time
  • You can throw away the ImageDraw object at any point. It doesn't contain any important information because everything is written directly to the image.

Here's the fixed __init__ method:

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)

You'll notice I've fixed a couple of things:

  • Set the canvas size to the size of the image. Obviously, you need to load the image before you can find the image size, so I've moved things around a bit.
  • Assign the ImageDraw instance to a separate variable
  • Draw a green rectangle instead of a dot, cause this will stand out more. Note you don't need to grab the return value of draw.rectangle -- it actually returns None, as most other drawing functions do.
  • Delete the draw variable after we're done drawing
  • Center the image in the canvas when calling create_image
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文