Tous les articles par gerotex

Natures mortes

Quelques générations de natures mortes les plus simplistes possibles en utilisant des styles connus.

A painting of a bouquet of white roses on a black and white marble table, in the style of Alfred Stevens
Steps: 36, Sampler: Euler a, CFG scale: 7, Seed: 2486835856, Size: 768x512, Model hash: 7460a6fa

Parfois il ne faut pas trop brider le style naturel du peintre qui donne de meilleurs résultats:

A painting  of flowers by Jan Davidsz de Heem
Steps: 24, Sampler: Euler a, CFG scale: 7, Seed: 4188331574, Size: 832x576, Model hash: 7460a6fa

A painting of an interior room by Jan Davidsz de Heem
Steps: 32, Sampler: Euler a, CFG scale: 7, Seed: 577309228, Size: 832x640, Model hash: 7460a6fa
A painting of  grapes  by Jan Davidsz de Heem
Steps: 32, Sampler: Euler a, CFG scale: 7, Seed: 2834515573, Size: 832x640, Model hash: 7460a6fa

Impact du sampler (technique)

Clairement, Euler_a et DPM2 par exemple donnent des « textures » différentes. Euler_a donne un aspect plus doux/vaporeux, DPM2 fait un peu plus vieilli ou rugueux. « DDIM » est un peu entre les deux.

A painting of grapes, apples, pears, basket by Jan Davidsz de Heem
Steps: 32, Sampler: Euler a, CFG scale: 7, Seed: 2200000539, Size: 832x640, Model hash: 7460a6fa

A painting of grapes, apples, pears, basket by Jan Davidsz de Heem
Steps: 32, Sampler: DPM2, CFG scale: 7, Seed: 2200000539, Size: 832x640, Model hash: 7460a6fa

img2img

Pour un meilleur contrôle de la composition, un img2img depuis un brouillon sous paint est probablement le plus efficace. Il faudra quand même affiner plusieurs fois le brouillon et les paramètres de denoise pour obtenir exactement l’effet recherché

A painting by Jan Davidsz de Heem
Steps: 22, Sampler: Heun, CFG scale: 7.5, Seed: 1440074437, Size: 704x576, Model hash: 7460a6fa, Denoising strength: 0.68, Mask blur: 4

Du classique sans originalité

Une exploration de reproductions de styles historiques.

« A painting by < artiste name > » sans autre guidage. Post-processing de correction de visages uniquement si nécessaire; sélection manuelle des meilleurs résultats (cependant la majorité est acceptable). Choix de la résolution en fonction du format le plus adapté pour chaque peintre.

  • Il apparaît vite que sans plus de précision, le réseau va se contenter de donner toujours des déclinaisons d’un seul exemple de sujet ou une composition, au lieu de piocher aléatoirement dans l’ensemble des thèmes disponibles de chaque artiste. Il faudra donc enrichir le prompt manuellement pour explorer le reste du répertoire.
  • tel-quel, ça donne donc plus un « style » de peinture (en terme de palettes et textures) qu’un répertoire de sujets.
  • S’inspirant d’un peintre professionnel ou pas, StableDiffusion reste approximatif sur les proportions et le nombre de bras d’un humain.
  • NB: il est possible que le sampler « Euler_a » soit plus adapté pour les styles « peinture » mais pas testé ici (et euler_a a tendance à changer trop de chose par rapport aux autres pour pouvoir comparer simplement)

Alfons Mucha

Le réseau connaît les différentes orthographes Alphonse/Alphons/Alfons Mucha , mais chacune semble donner des styles un peu différents.

Thomas Gainsborough

Deux variantes de prompts demandé, « painting » (qui ne sort que des paysages presque tous pareil) et « portrait« . Ça ne semble sortir que des auto-portraits cependant.

Edouard Manet

Les thèmes générés sont quand même plus répétitifs que les oeuvres d’origine (sans autre guidage de prompt)

Claude Monet

Une sur-représentation de L’étang aux nymphéas et autres sujets approchants.

Peter Rubens

Pas vraiment de variation entre « Peter Rubens », « Peter Paul Rubens » ou « Pierre Rubens »

Sur la composition récurrente qui sort à chaque fois, les amas de chair et les visages imparfaits donnent vite des visions d’horreurs…

De nouveau, test aussi sur « Portrait » explicitement mais qui sort toujours la même personne.

Alfred Stevens

Jan Davidsz de Heem

On voit bien tout de suite l’effet « nature morte » par contre en y regardant de plus près, difficile de savoir s’il s’agit de fleurs, de légumes ou de spatules en bois. Pour avoir un sujet cohérent il faudra raffiner le prompt pour guider la composition.

Johannes Vermeer

Une sur-représentation (voire une reproduction complète) de La Jeune Fille à la perle vient se greffer sur certains visages, ainsi que sa palette or & bleu. On remarque les variations du motif de carrelage au sol, similaire aux variations qu’on trouve dans les tableaux d’origine.

Pour les formats allongés, l’algorithme tend à créer des paires de personnage, à contrer en cochant « Highres Fix » dans l’interface.

Morphing et chimères

Trigger-warning: bestioles en forme d’araignées à la fin de l’article

Dans cette startup, on se donne à 150% !

La syntaxe (mot-clef:valeur) permet de pondérer l’intensité d’un mot dans le prompt. Avec une personne connue, l’effet principal est de donner un contrôle de ressemblance entre « humain moyen » à 50% et « caricature des traits spécifiques » au delà de 100% (en fait, au delà de 90%, car la sur-représentation de certaines célébrités dans l’entraînement du réseau les exagère déjà par défaut)

Portrait photo of  (Elon Musk:1.4)
Steps: 40, Sampler: DDIM, CFG scale: 7, Seed: 3355823348, Size: 512x512, Model hash: 7460a6fa

Alter-ego international

Un grand classique. Les traits ethniques vus par StableDiffusion appliqués à n’importe qui: Et si Elon Musk était Sud-Africain ?

Cocktail de célébrités

On commence par générer deux personnes avec les mêmes paramètres:

D’abord Thor, avec 90% de Chris Hemsworth

a photo of (chris hemsworth:0.9)
Steps: 42, Sampler: DPM2, CFG scale: 7, Seed: 1517168840, Size: 512x512, Model hash: 7460a6fa

Et Spiderman:

a photo of  Tom Holland
Steps: 42, Sampler: DPM2, CFG scale: 7, Seed: 1517168840, Size: 512x512, Model hash: 7460a6fa

Mixage par << « machin » as « truc »>>

Première technique de mixage, par construction grammaticale du prompt: « machin » as « truc » pour avoir une sorte de 50%, plus ou moins selon les coefficients

a photo of   (chris hemsworth:0.9) as Tom Holland

Bizarrement ça ne change pas grand chose, d’ailleurs je ne vais pas poster l’image.

À l’inverse si on échange les termes, il se passe quelquechose.

a photo of  Tom Holland as (chris hemsworth:0.9)

On peut tenter de varier les coefficients pour avoir des résultats un peu chaotiques:

a photo of   (chris hemsworth:0.7) as (Tom Holland:1.2)

Prompt-editing

La syntaxe de prompt [toto:tata:0.5] génère les toto sur les premières itérations, puis change la cible de génération à « tata » pour la fin (si je comprend bien). Une sorte de txt2img suivi d’un img2img automatisé, probablement.

a photo of [(chris hemsworth:0.9):Tom Holland:0.5]
a photo of [(chris hemsworth:0.9):Tom Holland:0.25]

Aussi changer l’ordre de qui est en premier est important:

a photo of [Tom Holland:(chris hemsworth:0.9):0.5]

Prompt-alternating

La syntaxe [toto|tata] , au lieu de répartir de la changement de prompt entre la 1ère et la 2ème moitié des itérations, l’alterne à chaque étape de génération. Du coup c’est aussi du 50% obligatoire sans autre coefficient possible. Cependant, en pratique ça n’a eu aucun effet pour le morphing de visages chez moi. Peut-être que les sampling-steps ou choix de diffuseur a un impact ?

a photo of [Tom Holland|(chris hemsworth:0.9)]

prompt vector interpollation

Théoriquement il y a moyen d’interpoller mathématiquement entre les représentations vectorielles des sujets demandés. Mais ça n’est pas encore implémentée dans l’interface actuellement disponible.

txt2img -> img2img

En renvoyant l’image de départ vers img2img et en changeant le prompt, et en réglant comme il faut le Denoising strength pour l’intensité de transformation, on peut avoir un résultat. Attention, la « seed » de l’img2img devrait être différente de celle du txt2img initial sinon il y a un effet de saturation qui dégrade l’image.

On peut aussi partir d’une vraie photo, probablement.

a photo of Tom Holland
Steps: 23, Sampler: DPM2, CFG scale: 7, Seed: 1016314451, Size: 512x512, Model hash: 7460a6fa, Denoising strength: 0.27, Mask blur: 4

Mi ours, Mi scorpion, et re-mi ours derrière

https://www.youtube.com/watch?v=Vwz9tX1cl5A

Au lieu d’un bête morphing entre deux humains, tentons de demander de hybrides improbables:

Le mi-ours était malheureusement impossible à générer directement à partir d’un prompt, et l’inpaiting ressemblait à un mauvais photoshop.

À la place:

A [zebra:wolf:0.3], National Geographics
Steps: 24, Sampler: DPM2 Karras, CFG scale: 7, Seed: 3167607957, Size: 768x512, Model hash: 7460a6fa

A [wolf:zebra:0.3], National Geographics
Steps: 24, Sampler: DPM2 Karras, CFG scale: 7, Seed: 3167607955, Size: 768x512, Model hash: 7460a6fa
A pig tiger
Steps: 24, Sampler: DPM2 Karras, CFG scale: 7, Seed: 3167607954, Size: 768x512, Model hash: 7460a6fa
A dolphin camel in the desert, by National Geographics
Steps: 24, Sampler: DPM2 Karras, CFG scale: 7, Seed: 3514664270, Size: 768x512, Model hash: 7460a6fa

girafphants

Spider-cat

Cryptozoologie

D’autres bestioles improbables, volontairement ou issues des tentatives infructueuses des paragraphes précédents ( « c’est pas ce que j’avais demandé, mais je garde quand même« )

« Alors c’est comme un centaure, mais Mi-cheval devant, Mi-cheval au milieu, et re-Mi-cheval derrière: »

Inpainting: aller trop loin

Image initiale: Mr. Rogers et son pull rouge (une vraie photo)

Sélection à la grosse louche du masque à appliquer:

Prompt d’inpainting: « A red wedding dress« . L’algo s’applique en gardant le contexte du reste de l’image non masquée, et décide donc que Monsieur Rogers porte plutôt des costumes d’homme que des robes:

Pour forcer le prompt, il faut donc rajouter le terme « woman » dans le prompt d’inpainting:

« A woman in a red wedding dress« .

Par curiosité on peut étendre le masque au visage pour voir comment l’algorithme a opéré la transition (Option « Restore Faces » de Automatic1111 activée)

Cette semelle de basket n’a plus aucun sens, les trucs au dessus ressemblent à des fleur donc repartons d’ici pour la transformer en vase, avec un nouveau masque:

« A woman in a red wedding dress, holds a white porcelain flower vase« 

Il est temps de finir le reste de l’image en transformant la plante verte, le rideau vert et les quelques meubles en bois, en quelque chose de plus intéressant. Masquage grossier:

« A woman sits on a dead tree log in a tropical forest »

les grands applats du mur de l’image d’origine ne fournissent pas assez de matière, il faut monter le curseur de « denoising strength » à 0.76 pour créer plus de chose à partir de rien:

L’anatomie des jambes est totalement à l’ouest. Les tentatives de regénérations des jambes ne donnent jamais rien avec cette position initiale, on va en faire autre chose avec ce bleu. Disons, « A blue giant bird« 

Ça ne ressemble plus vraiment à un endroit où porter une « robe de mariage », on remasque le haut du corps pour en faire « an middle-aged warrior woman with dark red leather clothes« 

Surprise ! Cette perruche et ce vase en porcelaine n’étaient qu’un habile camouflage pour une arme à dispersion énergétique !

« a sci-fi energy gun, with neon blue laser light, smoke« 

« a red general in a cyberpunk city by night »

Ah, il est bien loin le Mr Rogers amical et pacifique des débuts…

Transition complète animée

Encore plus ?…

Après avoir ciblé zone par zone, il peut être intéressant de passer la dernière image obtenue dans un img2img intégral (qui peut rattraper des jonctions de zones qui commençaient à manquer de cohérence) avec un denoise-strength pas trop fort (0.5)

« a red general in a cyberpunk city by night, holds a energy weapon with blue laser »

Pour comparaison, voici ce que donne le même prompt/paramètres, mais sur la photo de départ:

STOP !

« A bride in a red wedding dress holds a blue flower bouquet in front of a night club »

Making-Of

Pour faire cet article avec environ 15 images publiées, entre 100 et 200 essais intermédiaires ont été nécessaires pour sélectionner les plus convenables.

Inpainting pour défilé de mode (Automatic1111 UI)

Edit 2022-11: Quelques liens externes dans la même veine:

Robe

À partir d’une photo de base:

Laetitia Casta en robe à fleurs, Cannes 2021

Masquer la robe et changer le style (assez peu de variété lors des générations à cause de la texture d’origine trop « plate »)

Pour finir on peut faire un img2img intégral:

Veste

Ou bien prenons une veste typiquement portée par des loups-garous avec plus de plis et de volumes:

Cette fois l’inpainting a plus de matière pour travailler. Cependant, impossible en général de varier les couleurs.

This is not Loup…us.

Photoréaliste mais pas vraiment

Quelques résultats qui se rapprochent de la photo, mais à y regarder de plus près pas vraiment… (recherche simplement par raffinement du prompt et recherche de bonne seed avec Stable-Diffusion de base sans autre outils)

Cavalier dans la nature

txt2img.py --prompt "Photograph of a serious rider on his horse, in pine forest, crossing a stream, blue sky, rocky mountains on the horizon, National Geographic, Canon EOS 5D, 4k, detailed"  --ckpt sd-v1-4.ckpt --n_samples 1 --n_iter 1 --precision full --W 704 --H 512 --ddim_steps 40  --scale 6.7 
# recherche de seed entre 100000 et 100026
# Variation de prompte entre "stream", "snow", "spring flowers"

Chiens à la plage et ailleurs

Photoréaliste au niveau des textures ne veut pas dire réaliste biologiquement, selon les paramètres (scale 4.7 -> 6.7 -> 7.7, prompts variés autour de « Photograph of a fluffy labrador dog running and jumping on the beach, sand texture, floppy ears, catching a red ball, sunny sky, National Geographic, Canon EOS 5D, 4k, depth of field, detailed« , seed {1,2}00003 et suivants)

« On me dit que je ressemble à Alain de loin »

« à Alain Delon ? »

« non non, de loin »

(l’IA a confondu à moitié avec Patrick Dewaere non ?)

« studio Harcourt », « Polaroid », « Canon EOS 5D ».

Tour du monde des Bibliothéquaires

« Portrait of a {French,Italian,German…} librarian woman, Canon EOS 5D » seed 100003

French, Italian, German, Spanish, British, Turkish, Russian, Japanese, Thai, Egyptian, Congolese, Chilean

Les yeux sont toujours ratés quel que soit le nombre d’itération, on va dire que c’est le lunettes (sauf les russes qui ont une meilleure vue apparemment).

Bizarrement, certaines nationalités changent brutalement de cadrage entre 50 et 150 itérations, dans ce cas j’ai mis les deux versions. Voire ne sont jamais cadré « en situation ».

Animation du Latent-Space dans le code

Par défaut, les images de txt2img sont générés en itérant par dessus un bruit aléatoire (issu de la graine –seed passé en paramètre) dans l’espace « Latent ». Ces données ne sont pas manipulables et utilisable par défaut, à part choisir une graine aléatoire identique. img2img part d’une image source fournie par l’utilisateur mais la dérive aussi du bruit de l’espace latent sans contrôle.

Décalage

Avec un patch simple dans le code, il est possible de faire une première manipulation de cet espace latent, en contrôlant un décalage en X ou Y supplémentaire après la génération aléatoire.

À noter que la dimension de l’espace latent est 8 fois plus petit que l’image finale (optimisation de vitesse spécifique à Stable-Diffusion) et donc ces décalages ne sont pas très fluides et se font par saut de 8 pixels.

On remarque alors que l’image générée n’est pas simplement décalée sans changement: le réseau de neurone continue de réintepréter la génération selon ce qu’il a appris, par exemple un paysage de montagne sera souvent cadré avec 1/3 de ciel et 2/3 de montagnes; si elles sont trop décalées en haut ou en bas, alors elles seront métamorphosées en nuage ou en arbres:

les m

Un déplacement horizontal est un peu plus « naturel » mais va quand même faire beaucoup de métamorphoses:

Intensité

Un patch équivalent permet de multiplier le tensor de l’espace latent par une valeur entre -1 et +1; les valeurs négatives donnent un resultat totalement différent (similaire à un changement de seed ) , les valeurs proches de zéro donnent un vague brouillard uniforme, et entre 0.8 et 1.0 on assiste à une transition à partir de rien et un affinage des détails:

Interpolation

Une interpolation du tenseur de l’espace latent correspondant à deux seeds différentes permet de passer continûment d’une image à l’autre avec un prompt identique.

Un test d’interpolation naïve linéaire ne donne pas de résultat (90% de la plage visitée est un brouillard vide), il faut utiliser une « interpolation sphérique », voir la fonction « slrep » de https://github.com/nateraw/stable-diffusion-videos/commit/a1244dc452f1bc2dd78890840b13e273913127d7

Bien que plus fluide que les décalages en X/Y, il reste toujours des sauts brusques lors de la création finale des « features » d’image, et l’interpolation ne donne pas un morphing uniforme: il y a de longues périodes de changements subtils puis de très courtes plages rassemblant de nombreuses métamorphoses.

Cette vidéos est assemblée à partir de différentes sections d’interpolation à taux variable (pour ne pas passer 10h à calculer 500 images où rien ne change):

Code

Un script simple pour faire un tour complet en X :


for k in $(seq 0 64); do 
python scripts/txt2img.py  --prompt 'A fantasy landscape, snow mountains on the horizon, ancient forest, bright day, concept-art'  --seed 52  --skip_grid   --ckpt sd-v1-4.ckpt  --n_samples 1 --n_iter 1 --precision full --W 512 --H 512  --ddim_steps 50  --scale 7 --shift_latent_x $k;
 done

Le patch de code :

--- a/scripts/txt2img.py
+++ b/scripts/txt2img.py
@@ -216,6 +216,17 @@ def main():
         help="the seed (for reproducible sampling)",
     )
     parser.add_argument(
+        "--shift_latent_y",
+        type=int,
+        help="Scroll up the random latent space by N*8 pixels"
+    )
+    parser.add_argument(
+        "--shift_latent_x",
+        type=int,
+        help="Scroll left the random latent space by N*8 pixels"
+    )
+
+    parser.add_argument(
         "--precision",
         type=str,
         help="evaluate at this precision",
@@ -273,6 +284,19 @@ def main():
     if opt.fixed_code:
         start_code = torch.randn([opt.n_samples, opt.C, opt.H // opt.f, opt.W // opt.f], device=device)
 
+    if opt.shift_latent_y:
+        if start_code is None:
+            start_code = torch.randn([opt.n_samples, opt.C, opt.H // opt.f, opt.W // opt.f], device=device)
+        print(f"Shifting tensor by {opt.shift_latent_y} blocs up")
+        start_code = torch.roll(start_code, opt.shift_latent_y, 2)
+
+    if opt.shift_latent_x:
+        if start_code is None:
+            start_code = torch.randn([opt.n_samples, opt.C, opt.H // opt.f, opt.W // opt.f], device=device)
+        print(f"Shifting tensor by {opt.shift_latent_x} blocs left")
+        start_code = torch.roll(start_code, opt.shift_latent_x, 3)
+
+
     precision_scope = autocast if opt.precision=="autocast" else nullcontext
     with torch.no_grad():
         with precision_scope("cuda"):