【问题标题】:PIL putpixel does nothingPIL putpixel 什么都不做
【发布时间】:2018-11-11 17:54:06
【问题描述】:

在高中,我们从 Python 开始,我们被要求使用 Pillow 模块编写一个小型图像处理器。目标是打开一个文件,然后选择一个过滤器。

我尝试编程的第一个滤镜是改变色温。 但是还有一个带有 tkinter 的极简界面,它显示了一些按钮,并且可以正常工作。

这是打开文件的函数

def Ouvrir():
    fichier = askopenfilename(title="Ouvrir une image",filetypes=[('jpg files','.jpg'),('all files','.*')])
    global img
    img =Image.open(fichier)
    l, h = img.size
    img.show()   #visualisation de l'image

    global img2
    img2 = img #img2 est une copie de img

它创建一个从文件加载的全局img 图像对象。然后lh加载图片的宽高。

为输出图像创建另一个全局对象图像img2,它是img的副本。

那么这里就是处理图像的函数

def filtreTC(): #Filtre permettant de changer la température de couleur
    coef = sliderTC.get() / 100 #On récupère le coefficient à partir de l'échelle. Le coefficient compris entre -1 et 1: -1 = froid (image bleu-vert), 0 = neutre, 1 = chaud (image orangée)
    fenTC.destroy() #On ferme la fenêtre
    if(coef <= 0): #Calcul des coefficients rouges, verte et bleus
        coefR = 1 + coef
        coefV = 1 + (coef / 2)
        coefB = 1
    else:
        coefR = 1
        coefV = 1 - (coef / 2)
        coefB = 1 - coef
    for y in range(0, h, 1):
        for x in range(0, l, 1):
            r, v, b = img.getpixel((x, y))
            r = int(float(r * coefR))
            v = int(float(v * coefV))
            b = int(float(b * coefB))
            img2.putpixel((x, y), (r, v, b))
    img2.show()

这是一个循环,它扫描整个图像并从img 中获取一个像素,将其 rgb 值乘以其相应的系数,然后将该像素放入img2

问题是它不起作用。它没有给出任何错误,但是当它显示img2 时,它与img1 相同,就像putpixel 函数没有做任何事情一样。

我检查了很多东西,所以我知道问题既不是 rgb 值也不是 x/y 坐标。

  • 我尝试将img2 = img 替换为img2 = Image.new("RGB", (l, h)),但得到的是黑色图像。
  • 然后我尝试用img2.putpixel((100, 100), (127, 127, 127)) 替换img2.putpixel((x, y), (r, v, b)),这样我应该在左上角附近得到一个灰色像素。但我仍然得到一张黑色图像。

然后我尝试删除

global img2
img2 = img

来自打开文件并放置的函数

img2 = Image.new("RGB", (l, h))

就在fenTC.destroy() 之后,我得到了这个:

Exception in Tkinter callback
Traceback (most recent call last):
  File "e:\xxxx\programmes\anaconda\lib\tkinter\__init__.py", line 1702, in __call__
    return self.func(*args)
  File "H:\ISN\Programmes\TP-image\projet.py", line 62, in filtreTC
    img2.show()
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\Image.py", line 2016, in show
    _show(self, title=title, command=command)
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\Image.py", line 2876, in _show
    _showxv(image, **options)
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\Image.py", line 2881, in _showxv
    ImageShow.show(image, title, **options)
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\ImageShow.py", line 51, in show
    if viewer.show(image, title=title, **options):
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\ImageShow.py", line 75, in show
    return self.show_image(image, **options)
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\ImageShow.py", line 95, in show_image
    return self.show_file(self.save_image(image), **options)
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\ImageShow.py", line 91, in save_image
    return image._dump(format=self.get_format(image), **self.options)
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\Image.py", line 639, in _dump
    self.save(filename, format, **options)
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\Image.py", line 1969, in save
    save_handler(self, fp, filename)
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\BmpImagePlugin.py", line 319, in _save
    (rawmode, stride, -1))])
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\ImageFile.py", line 512, in _save
    e.setimage(im.im, b)
SystemError: tile cannot extend outside image

基本上很多东西我都不知道是什么意思,除了:

SystemError: tile cannot extend outside image

我检查了 x 和 y 坐标,它们从未超出边界,所以我不明白这是什么错误。

我花了几个小时试图找出问题所在,并尝试了很多不同的方法,但都没有奏效。所以我认为最好寻求帮助

【问题讨论】:

  • 避免在函数中使用全局变量。这让我们很难或不可能真正知道发生了什么。而是包含minimal reproducible example。使用 all 重现您的问题所需的代码。如果您收到“图块无法扩展到图像外部”的错误消息,则表明您对图像形状做出了一些错误的假设。

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


【解决方案1】:

您的问题是您没有创建副本img2 = img 创建对同一对象的另一个引用,而不是一个新的、单独的图像。

要创建实际副本,请使用image.copy() method

img2 = img.copy()

接下来,我不会使用循环和 getpixel() / putpixel() 组合。您正在为不止一次出现的 RGB 值做双重工作。如果您使用image.point() 方法,那么您可以对图像中每个每个波段中的唯一值 使用您的公式,并将所有像素的循环留给库(更快)。它还为您制作图像副本!

你需要创建一个表;对于 R、G 和 B 值从 0 到 255 的值,计算可能的结果,并将这 3 * 256 个结果放在一个长列表中:

coefG = [i * (1 - (coef / 2)) for i in range(256)]
if coef <= 0:
    coefR = [i * (1 + coef) for i in range(256)]
    coefB = list(range(256))
else:
    coefR = list(range(256))
    coefB = [i * (1 - coef) for i in range(256)]
img2 = img1.point(coefR + coefG + coefB)

生成的表格用于图像中的每个唯一颜色值。

您还可以将 RGB 图像拆分为单独的波段,将不同的系数公式作为函数应用于每个单独的波段,然后将这些波段重新组合成一个新图像:

r, g, b = img.split()
g = g.point(lambda i: i * (1 - (coef / 2)))
if coef <= 0:
    r = r.point(lambda i: i * (1 + coef))
else:
    b = b.point(lambda i: i * (1 - coef))
img = Image.merge('RGB', (r, g, b))

在创建图像过滤器时,您确实希望将输入图像作为 函数参数 传递,而不是使用全局变量。也传入系数:

def filtreTC(source_image, coef):
    coefG = [i * (1 - (coef / 2)) for i in range(256)]
    if coef <= 0:
        coefR = [i * (1 + coef) for i in range(256)]
        coefB = list(range(256))
    else:
        coefR = list(range(256))
        coefB = [i * (1 - coef) for i in range(256)]
    return source_image.point(coefR + coefG + coefB)

然后,如果需要,您可以将调用结果存储在全局中,但该函数现在可以独立存在,并且可以在任何具有 RGB PIL 图像对象的地方重复使用。您可以使用滑块值调用该函数:

coef = sliderTC.get() / 100
fenTC.destroy()
img2 = filtreTC(img, coef)

在您的个人资料图片上使用上述内容

系数为 0.75,给我们:

而 -0.75 的结果是:

【讨论】:

  • 谢谢。我知道使用 getpixel/putpixel 显然不是正确的方法。老师告诉我们,PIL库确实有图像处理的方法。但他告诉我们使用 getpixel/putpixel 以便我们了解图像处理的工作原理。如果我使用您的 filtreTC 函数,它会完美运行。然后我修改了我的filtreTC 函数,使它接受一个源图像和一个参数,再次没有错误,但我得到一个黑色图像,就像 putpixel 函数没有做任何事情一样。但令人惊讶的是 Image.point 有效,我不明白为什么。
  • @IntegratedElectronics:当我尝试使用img2 = img.copy() 时,您的循环代码对我来说工作得很好,值得。将副本放在函数的顶部,在 img.size 维度上运行循环,然后返回更改后的副本。
猜你喜欢
  • 2019-03-08
  • 2016-12-24
  • 2017-04-18
  • 2011-08-03
  • 2014-05-11
  • 2014-09-10
  • 1970-01-01
  • 2023-03-29
  • 2013-09-28
相关资源
最近更新 更多