【问题标题】:Python pillow make gif from pixelsPython枕头从像素制作gif
【发布时间】:2020-02-28 12:28:31
【问题描述】:

我有图像和蓝色像素列表。我想遍历蓝色像素,将它们更改为红色并从中制作 gif。所以它必须是一条线,因此颜色从蓝色变为红色,但是出了点问题

im = Image.open(r"test2.png")
pixels = im.load()
images = []
blues = get_sorted_blues()  # See func below

for x, y in blues:
     ...:     pixels[x, y] = (255, 0, 0)
     ...:     images.append(im)

images[0].save('result.gif',
     ...:                save_all=True,
     ...:                append_images=images[1:],
     ...:                duration=100,
     ...:                loop=0)

def get_sorted_blues():
    ...:     blues = []
    ...:     for x in range(im.width):
    ...:         for y in range(im.height):
    ...:             if pixels[x, y] == (0, 0, 255):
    ...:                 blues.append([x, y])
    ...:     return sorted(blues)

result.gif 它只是一条红线,没有任何动画

【问题讨论】:

  • 请分享您的起始图片,以便我们更好地为您提供帮助。此外,您应该避免使用 Python 图像处理的 for 循环——它们是 sl-o-o-o-ow。使用诸如 OpenCV 或 Numpy 之类的矢量化工具进行处理。
  • 所以问题是你没有让它动画?不熟悉枕头,但在你的循环中,你不断更新同一个图像并将同一个图像放入列表中,这意味着最后,列表中的所有条目都指向同一个图像,它都是红色的。在for循环中,代替images.append(im),改为images.append(im.copy())
  • 是的,这是一个答案。需要使用 im.copy()。我觉得很愚蠢,一个愚蠢的错误。
  • @ДавидШико 很高兴知道。我将我的评论作为答案,以便您接受。

标签: python python-imaging-library gif


【解决方案1】:

有很多方法可以使蓝色像素变为红色 - 使用 for 循环在性能、可读性和可维护性方面排名靠后。


这是一个使用 “颜色矩阵” 交换红色和蓝色通道的方法:

from PIL import Image

# Open image
im = Image.open('lines.png')

# Define color matrix to swap the red and blue channels
# This says:
# New red   = 0*old red + 0*old green + 1*old blue + 0offset
# New green = 0*old red + 1*old green + 0*old blue + 0offset
# New blue  = 1*old red + 0*old green + 0*old blue + 0offset
Matrix = ( 0, 0, 1, 0, 
           0, 1, 0, 0, 
           1, 0, 0, 0)    

# Apply matrix
result = im.convert("RGB", Matrix)

这比 for 循环快 40 倍左右。在我的机器上需要 1.07 毫秒,而使用 for 循环需要 40 毫秒。


这是一个使用 Numpy 查找蓝色像素并将其变为红色的示例:

import numpy as np
from PIL import image

# Open image and make Numpy version
im = Image.open('lines.png')
na = np.array(im)

# Make all blue pixels red
na[ np.all(na[:,:]==[0,0,255], axis=2) ] = [255,0,0] 

# Convert back to PIL Image
result = Image.fromarray(na)

这在 5 毫秒时快了大约 8 倍。


这是一个使用 Numpy 将 RGB 排序反转为 BGR:

import numpy as np
from PIL import image

# Open image and make Numpy version
im = Image.open('lines.png')
na = np.array(im)

# Reverse channel ordering i.e. RGB -> BGR
BGR = na[...,::-1] 

# Convert back to PIL Image
result = Image.fromarray(BGR)

这在 4.4 毫秒时快了大约 9 倍。


这是我们使用 PIL 将图像拆分为其组成的 RGB 通道,然后以相反的顺序将它们合并回来:

from PIL import Image

# Open image
im = Image.open('lines.png')

# Split into R, G, B channels
R, G, B = im.split()

# Recombine in B, G, R order
result = Image.merge('RGB',(B,G,R))

这在 371 微秒时快了大约 100 倍。

【讨论】:

  • 这是一个很好的答案,但我的问题是如何从某些像素创建带有枕头的 gif。性能不用担心,它不是生产代码。但这很有趣,你能解释一下几点吗 1.它是如何工作的im.convert(我只看到对称矩阵:)) 2.为什么我应该从'RGB'转换为'BGR'?
  • 对不起,我不明白。如果你把所有的蓝色像素都变成红色并用它制作一个 GIF,你会得到一个单帧的 GIF——它不会被动画化。
  • 试一下我在问题里贴的代码,把images.append(im) to images.append(im.copy())换成images.append(im) to images.append(im.copy())就会给你生成gif,显示从蓝色到红色的转换过程
【解决方案2】:

所以问题是你没能把它做成动画?

在您的循环中,您不断更新相同的Image 并将相同的Image 放入列表中,这意味着最后,列表中的所有条目都指向相同的Image,它都是红色的.在 for 循环中,不要使用 images.append(im),而是使用 images.append(im.copy())

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-10
    • 1970-01-01
    • 2017-06-02
    • 1970-01-01
    • 2013-06-17
    • 1970-01-01
    • 2021-10-25
    • 2015-07-17
    相关资源
    最近更新 更多