audito/sampler.py
Luca Conte d8e76a0420 v2
2024-06-17 13:15:26 +02:00

613 rindas
22 KiB
Python

from enum import Enum
import os
import numpy as np
import librosa
import math
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt
import random
import shutil
import subprocess
import tempfile
import textwrap
import click
import tensorflow as tf
from PIL import Image, ImageEnhance
from noisemaker.composer import EFFECT_PRESETS, GENERATOR_PRESETS, reload_presets
from noisemaker.constants import ColorSpace, ValueDistribution
from noisemaker.presets import PRESETS
import noisemaker.ai as ai
import noisemaker.dreamer as dreamer
import noisemaker.cli as cli
import noisemaker.generators as generators
import noisemaker.effects as effects
import noisemaker.util as util
import noisemaker.value as value
MAX_SEED_VALUE = 2 ** 32 - 1
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
reload_presets(PRESETS)
@click.group(context_settings=cli.CLICK_CONTEXT_SETTINGS)
def main():
pass
def anlyzeSound(audio_input_file):
# Assuming that into "generated" directoruy U've already create "project_name" subfolder
#audio_input_file = '/home/lalo/data/studio_grafica/deforum/stars_clip_r2.wav'
#audio_input_file = '/home/lalo/data/studio_suono/ardourprojects/space/export/star_r1_sessione_20240310_msub07.wav'
#audio_input_file = '/home/lalo/data/studio_suono/spx/231104_001_m01.wav'
#audio_input_file = '/home/lalo/data/studio_grafica/deforum/eucrasy_r1_sample.wav'
#audio_input_file = '/home/lalo/data/studio_grafica/deforum/eucrasy_r1.wav'
#audio_input_file = '/home/lalo/data/studio_grafica/deforum/eucrasy_short_r1.wav'
#audio_input_file = '/home/lalo/data/studio_suono/231014_002_mastered_r2_clip.WAV'
#audio_input_file = 'C:/Users/LucaConte/Music/lc_music/wilson_r1_mm.wav'
# Store the sampling rate as `sr`
fps = 24
flength = 22050//fps
#audio frame size is 22050/30=735
wave, sr = librosa.load(audio_input_file)
rms = librosa.feature.rms(y=wave, frame_length=flength, hop_length=flength)
#rms = librosa.feature.rms(y=wave, frame_length=735, hop_length=735)
cent = librosa.feature.spectral_centroid(y=wave, sr=sr,n_fft=flength, hop_length=flength)
zcr = librosa.feature.zero_crossing_rate(y=wave, frame_length=flength, hop_length=flength)
duration = int(math.ceil(librosa.get_duration(y=wave, sr=sr)))
#frames = duration * fps
#:w
# sr.len /22050 = duration
# rms.len * 30 = duration
# rms[i] mi da la potenza media del frame iesimo
#generateSoundVariations("bubble-machine", 3793866858, rms,5000,7500)
#generateSoundVariations("sands-of-time", 2226183906, rms,-1,2500)
#generateSoundVariations("sands-of-time", 2226183906, rms,2500,5000)
#generateSoundVariations("sands-of-time", 2226183906, rms,5000,7500)
#generateSoundVariations("sands-of-time", 2226183906, rms,7500,10000)
#generateSoundVariations("sands-of-time", 2226183906, rms,10000,10333)
#generateSamples()
#postprocessBrightness("/tmp/",cent, 8316,10000)
return rms, cent, zcr
def width_option(default=1024, **attrs):
attrs.setdefault("help", "Output width, in pixels")
return int_option("--width", default=default, **attrs)
#gli estremi frame start e frame stop sono esclusi
# python sampler.py genframes --width 666 --height 666 --preset bubble-machine --framestart 1 --framestop 55
@main.command()
@click.option('--width', required=True, type=int, default=1024)
@click.option('--height', required=True, type=int, default=1024)
@click.option('--seed', required=False, type=int, default=None)
@click.option('--out-dir', required=True, type=str, default=tempfile.gettempdir())
@click.option('--framestart', required=False, type=int, default=1)
@click.option('--framestop', required=False, type=int, default=-1)
@click.option('--audiofile', required=True, type=str, default='./dummy.wav')
@click.option('--preset', type=click.Choice(["random"] + sorted(GENERATOR_PRESETS)))
@click.pass_context
def genframes(ctx,width, height,preset, seed, framestart, framestop, audiofile, out_dir):
rms, centroids, zcr = anlyzeSound(audiofile)
if not seed:
seed = random.randint(1, MAX_SEED_VALUE)
print(f"(total frames: {len(rms[0])}) (framestart: {framestart}) (framestop: {framestop})")
time_dividend =500
s = interp1d([min(rms[0]), max(rms[0])], [0, 0.9])
trms=rms[0]
mean = np.mean(trms)
if framestop<0:
framestop = len(rms[0])
for frame in range(framestart, framestop):
try:
speed=abs(mean - float(format(trms[frame], '.3f')))
#print(f"(speed: {speed}) (trms: {trms[frame]}) )")
time = (float)((frame % time_dividend)/time_dividend)
filename = out_dir+ '/' + preset + "_" + str(seed)+ "_" + str(frame).zfill(10) +".png"
print(f"(speed: {speed}) (time: {time}) (filename: {filename})")
generate(1080,1080,time,speed,seed,filename,False,False,False,False,False,False,"",False,False,preset)
#generate(1024,1024,ftime,1,seed,"/tmp/" + str(frame).zfill(10) +".png",False,False,False,False,False,False,"",False,False,preset_name)
#generate(1024,1024,0.0,ftime,seed,"/tmp/" + str(frame).zfill(10) +"_" + preset_name + ".png",False,False,False,False,False,False,"",False,False,preset_name)
except Exception as e:
print(f"Exception {e} on Preset: {preset}")
continue
@main.command()
@click.pass_context
def testpillow(ctx):
image = Image.open('/tmp/the-inward-spiral_3917354306_0_0.23284526795328386.png')
brightness_factor = 3.5 # Increase brightness by 50%
enhancer = ImageEnhance.Brightness(image)
brightened_image = enhancer.enhance(brightness_factor)
contrast_factor = 4.2 # Increase contrast by 20%
enhancer = ImageEnhance.Contrast(image)
contrasted_image = enhancer.enhance(contrast_factor)
brightened_image.save("/tmp/alt/brightened_image.png")
contrasted_image.save("/tmp/alt/contrasted_image.png")
def postprocessBrightness(srcdir,centroids,framemin=0,framemax=9999999999):
c = interp1d([centroids.min(), centroids.max()], [1, 4.5])
items = os.listdir(srcdir)
sorted_items = sorted(items)
for f in sorted_items:
if f.endswith(".png"):
frame = int(f.split("_")[-1].split(".")[0])@click.command(context_settings=dict(
ignore_unknown_options=True,
))
if frame >= framemin and frame < framemax:
image = Image.open(srcdir+f)
enhancer = ImageEnhance.Brightness(image)
brightened_image = enhancer.enhance(c(centroids[0][frame]))
print(f'File: {f}')
brightened_image.save(srcdir+"b_"+f)
def testCombinedVariations(preset_name):
seed = random.randint(1, MAX_SEED_VALUE)
times = 0
for speed in range(0,999,1):
try:
if(times == 0):
times = random.randint(1, 30)
time = round(random.uniform(0, 1), 1)
fspeed = (float)(speed/100)
filename = "/tmp/"+ preset_name + "_" + str(seed)+ "_" + str(speed).zfill(10) +".png"
print(f"(speed: {speed}) (time: {time}) (times: {times}) (filename: {filename})")
times -= 1
#generate(600,600,time,fspeed,seed,filename,False,False,False,False,False,False,"",False,False,preset_name)
except Exception as e:
print(f"Exception on Preset: {preset_name}")
continue
def generateSpeedVariations(preset_name):
seed = random.randint(1, MAX_SEED_VALUE)
for speed in range(0,999,1):
try:
generate(600,600,0.1,speed,seed,"/tmp/"+ preset_name + "_" + str(seed)+ "_" + str(speed).zfill(10) +".png",False,False,False,False,False,False,"",False,False,preset_name)
except Exception as e:
print(f"Exception on Preset: {preset_name}")
continue
@main.command()
@click.option('--iterations', required=False, type=int, default=100)
@click.option('--preset', type=click.Choice(["random"] + sorted(GENERATOR_PRESETS)))
@click.pass_context
def gentimevariations(ctx,preset,iterations):
seed = random.randint(1, MAX_SEED_VALUE)
speed = random.random()
for time in range(0, iterations, 1):
try:
ftime = (float)(time/iterations)
print(str(ftime))
filename = tempfile.gettempdir() + "/" + preset+ "_" + str(seed) + "_" + str(time) + "_" + str(speed) + ".png"
generate(600,600,ftime,speed,seed, filename,False,False,False,False,False,False,"",False,False,preset)
except Exception as e:
print(f"Exception on Preset: {preset}")
continue
@main.command()
@click.pass_context
def gensamples(ctx):
for preset_name, preset_data in PRESETS().items():
try:
seed = random.randint(1, MAX_SEED_VALUE)
time = random.random()
speed = random.random()
filename = tempfile.gettempdir() + "/" + preset_name + "_" + str(seed) + "_" + str(time)+ "_" + str(speed) + ".png"
print(f"Going to generate: {filename}")
generate(1024, 1024, time, speed, seed, filename ,
False, False, False, False, False, False, "", False, False, preset_name)
except Exception as e:
print(f"Exception on Preset: {preset_name}")
continue
@main.command()
@click.option('--iterations', required=False, type=int, default=10)
@click.option('--preset', type=click.Choice(["random"] + sorted(GENERATOR_PRESETS)))
@click.pass_context
def genseedsvariations(ctx,preset,iterations):
for i in range(iterations):
try:
seed = random.randint(1, MAX_SEED_VALUE)
time = random.random()
speed = random.random()
filename = tempfile.gettempdir() + "/" + preset + "_" + str(seed) + "_" + str(time) + "_" + str(
speed) + ".png"
print(f"Going to generate: {filename}")
generate(1024, 1024, time, speed, seed, filename,
False, False, False, False, False, False, "", False, False, preset)
except Exception as e:
print(f"Exception on Preset: {preset}")
continue
def generate(width, height, time, speed, seed, filename, with_alpha, with_supersample, with_fxaa, with_ai, with_upscale,
with_alt_text, stability_model, debug_print, debug_out, preset_name):
if not seed:
seed = random.randint(1, MAX_SEED_VALUE)
value.set_seed(seed)
reload_presets(PRESETS)
if preset_name == "random":
preset_name = list(GENERATOR_PRESETS)[random.randint(0, len(GENERATOR_PRESETS) - 1)]
preset = GENERATOR_PRESETS[preset_name]
if debug_print or debug_out:
debug_text = _debug_print(seed, preset, with_alpha, with_supersample, with_fxaa, with_ai, with_upscale, stability_model)
if debug_print:
for line in debug_text:
print(line)
if debug_out is not None:
with open(debug_out, 'w') as fh:
for line in debug_text:
fh.write(line + "\n")
try:
preset.render(seed, shape=[height, width, None], time=time, speed=speed, filename=filename,
with_alpha=with_alpha, with_supersample=with_supersample, with_fxaa=with_fxaa,
with_ai=with_ai, with_upscale=with_upscale, stability_model=stability_model)
except Exception as e:
util.logger.error(f"preset.render() failed: {e}\nSeed: {seed}\nArgs: {preset.__dict__}")
raise
if preset.ai_success:
print(f"{preset_name} vs. {preset.ai_settings['model']} (seed: {seed})")
else:
print(f"{preset_name} (seed: {seed})")
if with_alt_text:
print(ai.describe(preset.name.replace('-', ' '), preset.ai_settings.get("prompt"), filename))
def _debug_print(seed, preset, with_alpha, with_supersample, with_fxaa, with_ai, with_upscale, stability_model):
first_column = ["Layers:"]
if preset.flattened_layers:
first_column.append(" - Lineage (by newest):")
if not preset.flattened_layers:
first_column.append(" - None")
for parent in reversed(preset.flattened_layers):
first_column.append(f" - {parent}")
first_column.append("")
first_column.append(" - Effects (by newest):")
if not preset.final_effects and not with_ai and not preset.post_effects:
first_column.append(" - None")
first_column.append("")
if preset.final_effects:
first_column.append(" - Final Pass:")
for effect in reversed(preset.final_effects):
if callable(effect):
first_column.append(f" - {effect.func.__name__.replace('_', ' ')}")
else:
first_column.append(f" - {effect.name.replace('_', ' ').replace('-', ' ')}")
first_column.append("")
if with_ai:
first_column.append(f" - AI Settings:")
for (k, v) in sorted(preset.ai_settings.items()):
if stability_model and k == 'model':
v = stability_model
for i, line in enumerate(textwrap.wrap(f"{k.replace('_', ' ')}: {v}", 42)):
if i == 0:
first_column.append(f" - {line}")
else:
first_column.append(f" {line}")
first_column.append("")
if preset.post_effects or with_ai:
first_column.append(" - Post Pass:")
if with_ai:
first_column.append(" - stable diffusion")
for effect in reversed(preset.post_effects):
if callable(effect):
first_column.append(f" - {effect.func.__name__.replace('_', ' ')}")
else:
first_column.append(f" - {effect.name.replace('_', ' ').replace('-', ' ')}")
first_column.append("")
if preset.octave_effects:
first_column.append(" - Per-Octave Pass:")
for effect in reversed(preset.octave_effects):
if callable(effect):
first_column.append(f" - {effect.func.__name__.replace('_', ' ')}")
else:
first_column.append(f" - {effect.name.replace('_', ' ').replace('-', ' ')}")
first_column.append("")
first_column.append("Canvas:")
first_column.append(f" - seed: {seed}")
first_column.append(f" - with alpha: {with_alpha}")
first_column.append(f" - with supersample: {with_supersample}")
first_column.append(f" - with fxaa: {with_fxaa}")
first_column.append(f" - with upscale: {with_upscale}")
first_column.append("")
second_column = ["Settings:"]
for (k, v) in sorted(preset.settings.items()):
if isinstance(v, Enum):
second_column.append(f" - {k.replace('_', ' ')}: {v.name.replace('_', ' ')}")
elif isinstance(v, float):
second_column.append(f" - {k.replace('_', ' ')}: {round(v, 3)}")
else:
second_column.append(f" - {k.replace('_', ' ')}: {v}")
second_column.append("")
out = []
for i in range(max(len(first_column), len(second_column))):
if i < len(first_column):
first = first_column[i]
else:
first = ""
if i < len(second_column):
second = second_column[i]
else:
second = ""
out.append(f"{first:50} {second}")
return out
def apply(ctx, seed, filename, no_resize, with_fxaa, time, speed, preset_name, input_filename):
if not seed:
seed = random.randint(1, MAX_SEED_VALUE)
value.set_seed(seed)
reload_presets(PRESETS)
input_shape = util.shape_from_file(input_filename)
input_shape[2] = min(input_shape[2], 3)
tensor = tf.image.convert_image_dtype(util.load(input_filename, channels=input_shape[2]), dtype=tf.float32)
if preset_name == "random":
preset_name = list(EFFECT_PRESETS)[random.randint(0, len(EFFECT_PRESETS) - 1)]
print(f"{preset_name} (seed: {seed})")
preset = EFFECT_PRESETS[preset_name]
if no_resize:
shape = input_shape
else:
shape = [1024, 1024, input_shape[2]]
tensor = effects.square_crop_and_resize(tensor, input_shape, shape[0])
try:
preset.render(seed=seed, tensor=tensor, shape=shape, with_fxaa=with_fxaa, time=time, speed=speed, filename=filename)
except Exception as e:
util.logger.error(f"preset.render() failed: {e}\nSeed: {seed}\nArgs: {preset.__dict__}")
raise
def animate(ctx, width, height, seed, effect_preset, filename, save_frames, frame_count, watermark, preview_filename, with_alt_text, with_supersample, with_fxaa, preset_name):
if seed is None:
seed = random.randint(1, MAX_SEED_VALUE)
value.set_seed(seed)
reload_presets(PRESETS)
if preset_name == 'random':
preset_name = list(GENERATOR_PRESETS)[random.randint(0, len(GENERATOR_PRESETS) - 1)]
if effect_preset == 'random':
effect_preset = list(EFFECT_PRESETS)[random.randint(0, len(EFFECT_PRESETS) - 1)]
if effect_preset:
print(f"{preset_name} vs. {effect_preset} (seed: {seed})")
else:
print(f"{preset_name} (seed: {seed})")
preset = GENERATOR_PRESETS[preset_name]
caption = None
with tempfile.TemporaryDirectory() as tmp:
for i in range(frame_count):
frame_filename = f'{tmp}/{i:04d}.png'
common_params = ['--seed', str(seed),
'--time', f'{i/frame_count:0.4f}',
'--filename', frame_filename]
extra_params = []
if with_alt_text and i == 0:
extra_params = ['--with-alt-text']
if with_supersample:
extra_params += ['--with-supersample']
if with_fxaa:
extra_params += ['--with-fxaa']
output = subprocess.check_output(['noisemaker', 'generate', preset_name,
'--speed', str(_use_reasonable_speed(preset, frame_count)),
'--height', str(height),
'--width', str(width)] + common_params + extra_params,
universal_newlines=True).strip().split("\n")
if with_alt_text and i == 0:
if len(output) == 6: # Useless extra crap that Tensorflow on Apple Silicon spews to stdout
print(output[2])
else:
print(output[1])
if effect_preset:
extra_params = []
if with_fxaa:
extra_params += ['--with-fxaa']
util.check_call(['noisemaker', 'apply', effect_preset, frame_filename,
'--no-resize',
'--speed', str(_use_reasonable_speed(EFFECT_PRESETS[effect_preset], frame_count))]
+ common_params + extra_params)
if save_frames:
shutil.copy(frame_filename, save_frames)
if watermark:
util.watermark(watermark, frame_filename)
if preview_filename and i == 0:
shutil.copy(frame_filename, preview_filename)
if filename.endswith(".mp4"):
util.check_call(["ffmpeg",
"-framerate", "30",
"-i", f"{tmp}/%04d.png",
"-s", "1024x1024",
"-c:v", "libx264",
"-preset", "veryslow",
"-crf", "15",
"-pix_fmt", "yuv420p",
"-b:v", "8000k",
"-bufsize", "16000k",
filename])
else:
util.magick(f'{tmp}/*png', filename)
@main.command(help="Blend a directory of .png or .jpg images")
@cli.input_dir_option(required=True)
@cli.filename_option(default="collage.png")
@click.option("--control-filename", help="Control image filename (optional)")
@cli.time_option()
@click.option('--speed', help="Animation speed", type=float, default=0.25)
@cli.seed_option()
@click.pass_context
def mashup(ctx, input_dir, filename, control_filename, time, speed, seed):
filenames = []
for root, _, files in os.walk(input_dir):
for f in files:
if f.endswith(('.png', '.jpg')):
filenames.append(os.path.join(root, f))
collage_count = min(random.randint(4, 6), len(filenames))
collage_images = []
for i in range(collage_count + 1):
index = random.randint(0, len(filenames) - 1)
input_filename = os.path.join(input_dir, filenames[index])
collage_input = tf.image.convert_image_dtype(util.load(input_filename, channels=3), dtype=tf.float32)
collage_images.append(collage_input)
if control_filename:
control_shape = util.shape_from_file(control_filename)
control = tf.image.convert_image_dtype(util.load(control_filename, channels=control_shape[2]), dtype=tf.float32)
else:
control = collage_images.pop()
shape = tf.shape(control) # All images need to be the same size!
control = value.value_map(control, shape, keepdims=True)
value.set_seed(seed)
base = generators.basic(freq=random.randint(2, 5), shape=shape, lattice_drift=random.randint(0, 1), hue_range=random.random(),
time=time, speed=speed)
value_shape = value.value_shape(shape)
control = value.convolve(kernel=effects.ValueMask.conv2d_blur, tensor=control, shape=value_shape)
tensor = effects.blend_layers(control, shape, random.random() * .5, *collage_images)
tensor = value.blend(tensor, base, .125 + random.random() * .125)
tensor = effects.bloom(tensor, shape, alpha=.25 + random.random() * .125)
tensor = effects.shadow(tensor, shape, alpha=.25 + random.random() * .125, reference=control)
tensor = tf.image.adjust_brightness(tensor, .1)
tensor = tf.image.adjust_contrast(tensor, 1.5)
util.save(tensor, filename)
print('mashup')
def _use_reasonable_speed(preset, frame_count):
"""Return a reasonable speed parameter for the given animation length."""
return preset.settings.get("speed", 0.25) * (frame_count / 50.0)
def dream(width, height, filename):
name, prompt, description = dreamer.dream(width, height, filename=filename)
print(name)
print(prompt)
print(description)
if __name__ == "__main__":
main()
#testPillow()
#postprocessBrightness('/tmp/')