NFT
May 11, 2022
СОЗДАЕМ ИЗОБРАЖЕНИЯ ДЛЯ NFT С ПОМОЩЬЮ PYTHON (2 ЧАСТЬ)
В прошлой статье мы создали генератор условных NFT на языке python, в целом можно было бы закончить, но хотелось бы немного улучшить наш результат и сделать наши NFT анимированными.
Добавим новые переменные для настройки нашего генератора:
from PIL import Image import os import random import numpy as np import math #sizes in in_w, in_h = (500,500) #sizes out out_w, out_h = (500,500) #sizes block b_w, b_h = (500,50) #gif settings gif = 1 gif_duration = 500 gif_optimisation = True collage_w, collage_h = (4,2) #how many images uses in procces generate use_src_images = 10 src_images = list() path_images = list() images = list() def getFixBoxSize(a, b): for i in range(0, b+1)[::-1]: if a % i == 0: return i
Немного пояснений про добавленные переменные:
# Кол-во кадров в нашей будущей gif
gif = 10
# Пауза между переходами
gif_duration = 500
# Оптимизация gif от библиотеки pillow
gif_optimisation = True
# Мозаика из gif (колонки, строки)
collage_w, collage_h = (4,2)
И изменим наш основной код на следующий вид:
if gif > 1: finally_image_list = list() for c in range(0, gif): # Get imagesimg tmp_images = os.listdir('./img') # Shuffle images in the list tmp_images = sorted(tmp_images, key=lambda A: random.random()) # Save fixed count images if len(tmp_images) >= use_src_images: path_images = [tmp_images[x] for x in range(0, use_src_images)] # Load images to buffer for img in path_images: images.append(Image.open(f"./img/{img}").resize((in_w, in_h))) combimosaic = Image.new("RGB", (out_w * collage_w, out_h * collage_h), tuple(np.random.choice(range(256), size=3))) if collage_w > 0 and collage_h > 0: for c_row in range(0, collage_h): for c_col in range(0, collage_w): mosaic = Image.new("RGB", (in_w, in_h), tuple(np.random.choice(range(256), size=3))) print(f"Source Images: " + ", ".join(path_images)) print("Method generation: VERTICAL") print(f"In size image: {in_w}x{in_h}") print(f"Out size image: {out_w}x{out_h}") print(f"SET Block size: {b_w}x{b_h}") b_w = getFixBoxSize(in_w, b_w) b_h = getFixBoxSize(in_h, b_h) print(f"FIX Block size: {b_w}x{b_h}") # calculate how many parts need cols, rows = (math.ceil(in_w / b_w),math.ceil(in_h / b_h)) print(f"ROWS: {rows}") print(f"COLS: {cols}") block_lines = [sorted([x2 for x2 in range(0,cols)], key=lambda A: random.random()) for x in range(0,rows)] print(" M A T R I X") print('\n'.join(str(x) for x in block_lines)) for row in range(0, rows): for col in range(0, cols): rand = random.randrange(0, len(images)) num = block_lines[row].pop(0) quad = (b_w * num, b_h * row, b_w * num + b_w, b_h * row + b_h) quadimg = images[rand].crop(quad) mosaic.paste(quadimg, (b_w * num, b_h * row, b_w * num + b_w, b_h * row + b_h), quadimg) fragment = mosaic.resize((out_w, out_h)) fragmentimg = fragment.crop((0,0,out_w,out_h)) combimosaic.paste(fragmentimg, (out_w * c_col, out_h * c_row, out_w * c_col + out_w, out_h * c_row + out_h)) finally_image_list.append(combimosaic) else: mosaic = Image.new("RGB", (in_w, in_h), tuple(np.random.choice(range(256), size=3))) print(f"Source Images: " + ", ".join(path_images)) print("Method generation: VERTICAL") print(f"In size image: {in_w}x{in_h}") print(f"Out size image: {out_w}x{out_h}") print(f"SET Block size: {b_w}x{b_h}") b_w = getFixBoxSize(in_w, b_w) b_h = getFixBoxSize(in_h, b_h) print(f"FIX Block size: {b_w}x{b_h}") # calculate how many parts need cols, rows = (math.ceil(in_w / b_w),math.ceil(in_h / b_h)) print(f"ROWS: {rows}") print(f"COLS: {cols}") block_lines = [sorted([x2 for x2 in range(0,cols)], key=lambda A: random.random()) for x in range(0,rows)] print(" M A T R I X") print('\n'.join(str(x) for x in block_lines)) for row in range(0, rows): for col in range(0, cols): rand = random.randrange(0, len(images)) num = block_lines[row].pop(0) quad = (b_w * num, b_h * row, b_w * num + b_w, b_h * row + b_h) quadimg = images[rand].crop(quad) mosaic.paste(quadimg, (b_w * num, b_h * row, b_w * num + b_w, b_h * row + b_h), quadimg) mosaic = mosaic.resize((out_w, out_h)) finally_image_list.append(mosaic) gif = Image.new("RGB", (out_w * collage_w, out_h * collage_h), tuple(np.random.choice(range(256), size=3))) temp = [x for x in finally_image_list] temp[0].save('out.gif', save_all=True, append_images= temp[1:],optimize=gif_optimisation, duration=gif_duration, loop=0) else: # Get images tmp_images = os.listdir('./img') # Shuffle images in the list tmp_images = sorted(tmp_images, key=lambda A: random.random()) # Save fixed count images if len(tmp_images) >= use_src_images: path_images = [tmp_images[x] for x in range(0, use_src_images)] # Load images to buffer for img in path_images: images.append(Image.open(f"./img/{img}").resize((in_w, in_h))) combimosaic = Image.new("RGB", (out_w * collage_w, out_h * collage_h), tuple(np.random.choice(range(256), size=3))) if collage_w > 0 and collage_h > 0: for c_row in range(0, collage_h): for c_col in range(0, collage_w): mosaic = Image.new("RGB", (in_w, in_h), tuple(np.random.choice(range(256), size=3))) print(f"Source Images: " + ", ".join(path_images)) print("Method generation: VERTICAL") print(f"In size image: {in_w}x{in_h}") print(f"Out size image: {out_w}x{out_h}") print(f"SET Block size: {b_w}x{b_h}") b_w = getFixBoxSize(in_w, b_w) b_h = getFixBoxSize(in_h, b_h) print(f"FIX Block size: {b_w}x{b_h}") # calculate how many parts need cols, rows = (math.ceil(in_w / b_w),math.ceil(in_h / b_h)) print(f"ROWS: {rows}") print(f"COLS: {cols}") block_lines = [sorted([x2 for x2 in range(0,cols)], key=lambda A: random.random()) for x in range(0,rows)] print(" M A T R I X") print('\n'.join(str(x) for x in block_lines)) for row in range(0, rows): for col in range(0, cols): rand = random.randrange(0, len(images)) num = block_lines[row].pop(0) quad = (b_w * num, b_h * row, b_w * num + b_w, b_h * row + b_h) quadimg = images[rand].crop(quad) mosaic.paste(quadimg, (b_w * num, b_h * row, b_w * num + b_w, b_h * row + b_h), quadimg) fragment = mosaic.resize((out_w, out_h)) fragmentimg = fragment.crop((0,0,out_w,out_h)) combimosaic.paste(fragmentimg, (out_w * c_col, out_h * c_row, out_w * c_col + out_w, out_h * c_row + out_h)) combimosaic.show() else: mosaic = Image.new("RGB", (in_w, in_h), tuple(np.random.choice(range(256), size=3))) print(f"Source Images: " + ", ".join(path_images)) print("Method generation: VERTICAL") print(f"In size image: {in_w}x{in_h}") print(f"Out size image: {out_w}x{out_h}") print(f"SET Block size: {b_w}x{b_h}") b_w = getFixBoxSize(in_w, b_w) b_h = getFixBoxSize(in_h, b_h) print(f"FIX Block size: {b_w}x{b_h}") # calculate how many parts need cols, rows = (math.ceil(in_w / b_w),math.ceil(in_h / b_h)) print(f"ROWS: {rows}") print(f"COLS: {cols}") block_lines = [sorted([x2 for x2 in range(0,cols)], key=lambda A: random.random()) for x in range(0,rows)] print(" M A T R I X") print('\n'.join(str(x) for x in block_lines)) for row in range(0, rows): for col in range(0, cols): rand = random.randrange(0, len(images)) num = block_lines[row].pop(0) quad = (b_w * num, b_h * row, b_w * num + b_w, b_h * row + b_h) quadimg = images[rand].crop(quad) mosaic.paste(quadimg, (b_w * num, b_h * row, b_w * num + b_w, b_h * row + b_h), quadimg) mosaic = mosaic.resize((out_w, out_h)) mosaic.show() mosaic.save('out.png')
Теперь мы можем делать анимированные изображения лиц, статичные изображения лиц, а так же мозаики тех и других, при этом играясь с переменными размеров блоков.