简体   繁体   中英

Python pillow make gif from pixels

在此处输入图片说明

I have the image and a list of blue pixels. I want to iterate over the blue pixels, change them to red color and make gif from that. So it must be a line that consequently changing color from blue to red, but something going wrong

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 it is just a red line, without any animation

There are lots of ways to make the blue pixels red - and using a for loop is way down the list in terms of performance, readability, maintainability.


Here's one using a "Colour Matrix" to swap the red and blue channels:

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)

在此处输入图片说明

This is around 40x faster than for loops. It takes 1.07ms on my machine versus 40ms using for loops.


Here's one using Numpy to find blue pixels and make them red:

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)

This is around 8x faster at 5ms.


Here's one using Numpy to reverse the RGB ordering to 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)

This is around 9x faster at 4.4ms.


Here's one where we use PIL to split the image into its constituent RGB channels and then merge them back in the reverse order:

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

This is around 100x faster at 371 microseconds.

So the problem is you failed to make it animated?

In your loop, you keep updating the same Image and put that same Image into the list, which means at the end, all entries in the list is pointing to the same Image , which is all red. In the for loop, instead of images.append(im) , do images.append(im.copy()) .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM