Python Подушка Gif Артефакты / Фон - PullRequest
1 голос
/ 27 марта 2020

Цель: каждый кадр в конце должен иметь полное sudowoodo. Все, что не подходит, должно быть прозрачным в gif (мне бы тоже было хорошо с белым). Моя конечная цель - перекрасить его, поэтому я должен различать guish фон и покемона.

Я использую запросы, чтобы получить gif с веб-сайта а затем подушка, чтобы получить кадры. Когда я просматриваю кадры, артефакты (в основном фоновые) мешают моему методу избавления. Я использую https://ezgif.com/split, чтобы проверить, как это должно выглядеть.

Я поместил рамку, метод утилизации и рамки вокруг экстентов утилизации для своих коллажей, чтобы понять, как он должен складываться (показано на изображение ниже). Внизу приведен пример кода, который покажет восстановленные кадры.

Так как мне правильно получить чистые кадры с помощью подушки?


Изображения

Примечание:

  • Для рамки кадра индекс 4 получает белую линию в теле, а индекс кадра 27 имеет зеленый фон. И несколько кадров не хватает зеленого цвета в сферах / ветвях.
  • Чтобы ezgif.com увидел опубликованную мной фотографию, нужно поставить «Игнорировать оптимизации», но мне нужна конечная фотография, которая отображается на веб-сайте «Перерисовать каждый кадр с деталями из предыдущих кадров». '.

Используемый рисунок: https://play.pokemonshowdown.com/sprites/xyani/sudowoodo.gif

Результаты подушки:
Pillow Extracted Frames
Результаты Эзгифа:
Websites extraction


Код

Python Версии
Python == 3,6 .4
Подушка == 7.0.0
запросы == 2.23.0

from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
import requests

#Depends on the dispose_method and disposal_extent will process accordingly
def method_dispose(i, frames, previous_frame):
    # 0 PIL = Overlay and pass
    # 1 PIL = Overlay and return previous
    # 2 PIL = Erase Overlay
    new_frame = previous_frame.copy()
    current_frame = frames.convert('RGBA')
    new_frame.alpha_composite(current_frame, dest=frames.dispose_extent[0:2], source=frames.dispose_extent)
    if frames.disposal_method is 0:
        return new_frame, Image.new('RGBA', box=frames.size)
    elif frames.disposal_method is 1:
        return new_frame, new_frame.copy()
    elif frames.disposal_method is 2:
        draw = ImageDraw.Draw(previous_frame)
        draw.rectangle(frames.dispose_extent, fill=(255, 255, 255, 0)) #fill white transparent
        return new_frame, previous_frame.copy()

# Goes through the frames and pastes them next to each other then shows
def simpleCollage(frames, num_images_width : int = 5, num_images_height : int = 10):
    width, height = frames.size
    compilation = Image.new('RGBA', size=(width * num_images_width, height * num_images_height))
    fnt = ImageFont.load_default().font
    for i in range(frames.n_frames):
        frames.seek(i)
        the_frame = frames.convert('RGBA')
        draw = ImageDraw.Draw(the_frame)
        draw.rectangle(frames.dispose_extent, outline=(255,173,0,255))
        draw.text((0,0), f"F{i}-M{frames.disposal_method}", font=fnt, fill=(255, 0, 0))
        compilation.paste(the_frame, box=(width * int(i % num_images_width), height * int(i / num_images_width)))
        if i == (num_images_width * num_images_height):
            break;
    compilation.show()

response = requests.get("https://play.pokemonshowdown.com/sprites/xyani/sudowoodo.gif")
frames = Image.open(BytesIO(response.content))
simpleCollage(frames)

width, height = frames.size
all_frames = []
pass_frame = Image.new('RGBA', size=frames.size)
for i in range(frames.n_frames):
    frames.seek(i)
    disp_frame, pass_frame = method_dispose(i, frames, pass_frame)
    all_frames.append(disp_frame)

all_frames[0].save(fp="test.gif", format='GIF', save_all=True, append_images=all_frames[1:], optimize=False, duration=frames.info['duration'], loop=0)
simpleCollage(Image.open("test.gif"))

Некоторые источники, которые я использовал для метода утилизации:

Ответы [ 2 ]

1 голос
/ 30 марта 2020

Полученное плохое изображение является результатом повторного .convert(). Для решения этой проблемы .seek(0) необходимо поставить после .convert(). Таким образом, полученный код должен выглядеть так:

for i in range(frames.n_frames):
    frames.seek(i)
    disp_frame, pass_frame = method_dispose(i, frames, pass_frame)
    all_frames.append(disp_frame)
    frames.seek(0) # <-- Added
0 голосов
/ 27 марта 2020

Не полностью проверенный, полностью проработанный ответ, но работа в процессе, которую я хотел сохранить и поделиться, как и я go, и это может быть полезно всем, кто смотрит на это.

Вы можете проверить размер, удаление, задержку и т. Д. Кадров в GIF, используя ImageMagick , например:

identify -format "%f[%s] canvas=%Wx%H size=%wx%h offset=%X%Y %D %Tcentisecs\n" treething.gif 

Пример вывода

treething.gif[0] canvas=58x66 size=58x66 offset=+0+0 Background 3centisecs
treething.gif[1] canvas=58x66 size=58x66 offset=+0+0 None 3centisecs
treething.gif[2] canvas=58x66 size=49x63 offset=+7+1 None 3centisecs
treething.gif[3] canvas=58x66 size=55x47 offset=+2+1 Background 3centisecs
treething.gif[4] canvas=58x66 size=56x64 offset=+2+1 Background 3centisecs
treething.gif[5] canvas=58x66 size=56x64 offset=+2+1 Background 3centisecs
treething.gif[6] canvas=58x66 size=56x64 offset=+2+1 Background 3centisecs
treething.gif[7] canvas=58x66 size=56x64 offset=+2+1 Background 3centisecs
treething.gif[8] canvas=58x66 size=56x64 offset=+2+1 None 3centisecs
treething.gif[9] canvas=58x66 size=54x65 offset=+3+1 Background 3centisecs
treething.gif[10] canvas=58x66 size=54x65 offset=+3+1 Background 3centisecs
treething.gif[11] canvas=58x66 size=54x65 offset=+3+1 None 3centisecs
treething.gif[12] canvas=58x66 size=45x58 offset=+7+6 Background 3centisecs
treething.gif[13] canvas=58x66 size=51x58 offset=+7+6 Background 3centisecs
treething.gif[14] canvas=58x66 size=55x64 offset=+2+0 Background 3centisecs
treething.gif[15] canvas=58x66 size=55x64 offset=+2+0 Background 3centisecs
treething.gif[16] canvas=58x66 size=55x64 offset=+2+0 Background 3centisecs
treething.gif[17] canvas=58x66 size=55x64 offset=+2+0 None 3centisecs
treething.gif[18] canvas=58x66 size=41x53 offset=+16+4 Background 3centisecs
treething.gif[19] canvas=58x66 size=56x60 offset=+1+4 None 3centisecs
treething.gif[20] canvas=58x66 size=19x61 offset=+9+3 None 3centisecs
treething.gif[21] canvas=58x66 size=43x54 offset=+8+10 None 3centisecs
treething.gif[22] canvas=58x66 size=43x47 offset=+8+10 None 3centisecs
treething.gif[23] canvas=58x66 size=50x61 offset=+1+3 Background 3centisecs
treething.gif[24] canvas=58x66 size=51x61 offset=+1+3 None 3centisecs
treething.gif[25] canvas=58x66 size=43x50 offset=+7+4 None 3centisecs
treething.gif[26] canvas=58x66 size=47x65 offset=+10+1 Background 3centisecs
treething.gif[27] canvas=58x66 size=50x65 offset=+7+1 None 3centisecs
treething.gif[28] canvas=58x66 size=47x64 offset=+3+0 Background 3centisecs
treething.gif[29] canvas=58x66 size=56x64 offset=+2+0 Background 3centisecs
treething.gif[30] canvas=58x66 size=58x64 offset=+0+0 Background 3centisecs
treething.gif[31] canvas=58x66 size=58x64 offset=+0+0 Background 3centisecs
treething.gif[32] canvas=58x66 size=58x64 offset=+0+0 None 3centisecs
treething.gif[33] canvas=58x66 size=37x59 offset=+15+2 Background 3centisecs
treething.gif[34] canvas=58x66 size=48x63 offset=+7+1 Background 3centisecs
treething.gif[35] canvas=58x66 size=48x63 offset=+7+1 Background 3centisecs
treething.gif[36] canvas=58x66 size=50x63 offset=+7+1 Background 3centisecs
treething.gif[37] canvas=58x66 size=50x63 offset=+7+1 Background 3centisecs
treething.gif[38] canvas=58x66 size=50x63 offset=+7+1 None 3centisecs
treething.gif[39] canvas=58x66 size=52x65 offset=+1+1 Background 3centisecs
treething.gif[40] canvas=58x66 size=57x65 offset=+1+1 Background 3centisecs
treething.gif[41] canvas=58x66 size=57x65 offset=+1+1 None 3centisecs
treething.gif[42] canvas=58x66 size=53x63 offset=+1+2 Background 3centisecs
treething.gif[43] canvas=58x66 size=54x63 offset=+1+2 Background 3centisecs
treething.gif[44] canvas=58x66 size=54x65 offset=+1+0 Background 3centisecs
treething.gif[45] canvas=58x66 size=55x65 offset=+1+0 Background 3centisecs
treething.gif[46] canvas=58x66 size=56x65 offset=+1+0 None 3centisecs
treething.gif[47] canvas=58x66 size=44x54 offset=+14+10 Background 3centisecs
treething.gif[48] canvas=58x66 size=44x63 offset=+14+2 Background 3centisecs
treething.gif[49] canvas=58x66 size=44x63 offset=+14+2 Background 3centisecs
treething.gif[50] canvas=58x66 size=44x63 offset=+14+2 Background 3centisecs
treething.gif[51] canvas=58x66 size=51x63 offset=+7+2 Background 3centisecs
treething.gif[52] canvas=58x66 size=51x63 offset=+7+2 None 3centisecs
treething.gif[53] canvas=58x66 size=40x31 offset=+14+3 Background 3centisecs
treething.gif[54] canvas=58x66 size=52x55 offset=+4+2 Background 3centisecs
treething.gif[55] canvas=58x66 size=52x55 offset=+4+2 None 3centisecs
treething.gif[56] canvas=58x66 size=49x51 offset=+1+6 None 3centisecs
treething.gif[57] canvas=58x66 size=56x63 offset=+2+2 Background 3centisecs
treething.gif[58] canvas=58x66 size=56x65 offset=+2+0 None 3centisecs
treething.gif[59] canvas=58x66 size=48x64 offset=+7+1 None 3centisecs

Вы также можете вставить следующую строку в вашу программу после draw.text((0,0)...), чтобы получить аналогичный вывод:

print(i,frames.dispose_extent, frames.disposal_method)

Теперь все, что мне нужно сделать, это сравнить два ...

Я все еще пытаюсь выяснить, что пошло не так - моё подозрение:

  • вам нужно добавить маску к строке compilation.paste(the_frame,...) или
  • , которая the_frame = frames.convert('RGBA') делает вам неудобство, потому что GIF-файлы на самом деле палитрированы, и что-то не так с преобразованием.

Вы также можете видеть слитые кадры из ImageMagick на красном фоне:

magick tree.gif miff:- | magick montage -background red -geometry +5+5 -tile 12x miff:- montage.png

enter image description here

...