
MJ作为AI圈很抗打的AI生图工具,在其强大的功能里,人物一致性的保持堪称一大亮点。我们在制作插画或角色故事时,人物一致性至关重要。此操作不仅仅靠单一的后缀参数调整来实现,要想更大程度上挖掘MJ进阶用法,需要打出一套组合拳并理解背后严谨的数学原理和机器学习。
我们在第一篇博客中讲过,垫图、风格迁移......都可以高度还原理想图片。
不了解MJ基本操作的朋友们可以先阅读这篇博客:《AIGC | Midjourney使用指南,直接拿捏~》
但是要想充分利用MJ这一工具需要调用多个功能:
第一步: 使用/describe,对目标图片进行描述

第二步:将描述结果进行翻译,选择更为全面的描述,同时也可以综合四条结果自己整合出更全面的提示词。

第三步:复制目标图片链接在提示词前进行垫图,垫图后输入空格后再写入提示词 ,写入提示词后,空格 加入后缀参数,每个后缀参数间要插入空格。
注:--iw(范围为0-2)数值越大,对垫图链接的参考越大。--sref空格+链接+空格+--sw空格(0-1000)数值越大,对链接图片的风格参考性更大。--cref空格+链接+空格+--cw空格(0-100)数值为0时,只是对图片脸部进行参考,数值为100时,是对全图细节元素进行参考。
--sref --sw & --cref --cw 使用贴士
--sref与--sw不一定要同时使用,但--sw 不能单独使用,故只能出现:--sref空格+链接或--sref空格+链接+空格+--sw空格(0-1000)这两种形式。
--cref与--cw必须同时使用,故只能出现:-cref空格+链接+空格+--cw空格(0-100)否则会报错。

此外,我们在一张图中也可以融合多张图的元素,比如人脸参考图A,风格参考图B,大致垫图为图C,也就是说,这三张图不一定要是一张图。
垫图+--iw +--cref --cw 0+--seed,对提示词进行修改,从而呈现不同画面。




提示词:https://s.mj.run/RiqmbDqC2HA , A little girl plays the guitar in the garden --seed 2023957784 --cref https://s.mj.run/RiqmbDqC2HA --cw 0 --iw 2 --niji 6
在垫图中我们可以多次垫不同的图,确保有更大的发挥性,垫图的先后次序有关权重,我们也可以在链接后输入::+数值来调整权重。
我们在提示词中加入特定指令也可实现,人物一致性操作。
如:不同动作:Different actions
连续动作:Continuous action
多视角动作:Multi-view action
不同表情:Different expressions
正在做什么:What is being done
连续拍摄:Continuous shooting
序列拍摄:Sequence shooting
详情请看: 《AIGC | Midjourney使用指南,直接拿捏~》
通过提供视觉参考,垫图帮助 AI 抓取并应用关键元素,如风格、纹理等,与文本提示相结合来指导创作。主要有 “克隆” 和 “牵引” 两种用途,“克隆” 是尽可能复刻风格,“牵引” 是引导创作方向而非完全复制。

核心是利用深度学习中的卷积神经网络(CNN)等技术,将内容图像的内容与风格图像的风格进行融合。
代码实现: 以 Python 和 TensorFlow 为例,使用 VGG19 模型实现风格迁移。
import tensorflow as tf
from tensorflow import keras
from keras.applications.vgg19 import VGG19
from keras.preprocessing.image import load_img, img_to_array
import numpy as np
# 定义内容层和风格层
content_layers = ['block3_conv1']
style_layers = ['block1_conv1', 'block2_conv1', 'block3_conv1', 'block4_conv1', 'block5_conv1']
# 加载预训练的VGG19模型
base_model = VGG19(weights='imagenet', include_top=False)
# 构建内容模型
content_model = keras.Model(inputs=base_model.input, outputs=[base_model.get_layer(layer).output for layer in content_layers])
# 构建风格模型
style_model = keras.Model(inputs=base_model.input, outputs=[base_model.get_layer(layer).output for layer in style_layers])
# 加载并预处理图像
def preprocess_img(img_path, target_size=(224, 224)):
img = load_img(img_path, target_size=target_size)
img = img_to_array(img)
img = np.expand_dims(img, axis=0)
img = keras.applications.vgg19.preprocess_input(img)
return img
# 计算Gram矩阵
def gram_matrix(feature_map):
shape = tf.shape(feature_map)
height, width, channels = shape[1], shape[2], shape[3]
feature_map = tf.reshape(feature_map, [height * width, channels])
gram = tf.matmul(tf.transpose(feature_map), feature_map)
return gram
# 计算内容损失
def content_loss(generated_content, content_target):
return tf.reduce_mean(tf.square(generated_content - content_target))
# 计算风格损失
def style_loss(generated_style, style_target):
style_loss = 0.0
for gen, target in zip(generated_style, style_target):
gen_gram = gram_matrix(gen)
target_gram = gram_matrix(target)
style_loss += tf.reduce_mean(tf.square(gen_gram - target_gram))
return style_loss
# 图像风格迁移
def style_transfer(content_img_path, style_img_path, num_iterations=1000, content_weight=1.0, style_weight=100.0):
content_img = preprocess_img(content_img_path)
style_img = preprocess_img(style_img_path)
# 初始化生成图像为内容图像
generated_img = tf.Variable(content_img, dtype=tf.float32)
optimizer = tf.optimizers.Adam(learning_rate=5, beta_1=0.99, epsilon=1e-1)
for i in range(num_iterations):
with tf.GradientTape() as tape:
generated_content = content_model(generated_img)
generated_style = style_model(generated_img)
content_loss_value = content_weight * content_loss(generated_content, content_model(content_img))
style_loss_value = style_weight * style_loss(generated_style, style_model(style_img))
total_loss = content_loss_value + style_loss_value
gradients = tape.gradient(total_loss, generated_img)
optimizer.apply_gradients([(gradients, generated_img)])
return generated_img
content_img_path = 'content.jpg'
style_img_path = 'style.jpg'
generated_img = style_transfer(content_img_path, style_img_path)
# 保存生成的图像
keras.preprocessing.image.save_img('output.jpg', generated_img.numpy()[0])
代码实现:
import tensorflow as tf
# 定义生成器和判别器网络结构
def generator(inputs):
# 生成器网络架构
return generated_image
def discriminator(image):
# 判别器网络架构
return discrimination_result
# 定义损失函数
cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)
# 定义生成器损失
def generator_loss(fake_output):
return cross_entropy(tf.ones_like(fake_output), fake_output)
# 定义判别器损失
def discriminator_loss(real_output, fake_output):
real_loss = cross_entropy(tf.ones_like(real_output), real_output)
fake_loss = cross_entropy(tf.zeros_like(fake_output), fake_output)
return real_loss + fake_loss
# 定义优化器
generator_optimizer = tf.keras.optimizers.Adam(learning_rate=0.0002, beta_1=0.5)
discriminator_optimizer = tf.keras.optimizers.Adam(learning_rate=0.0002, beta_1=0.5)
# 训练循环
for epoch in range(num_epochs):
for batch in data_loader:
real_images = batch
# 生成随机噪声作为生成器输入
noise = tf.random.normal([batch_size, noise_dim])
with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
# 生成假图像
fake_images = generator(noise)
# 判别器对真实图像和假图像的判别结果
real_output = discriminator(real_images)
fake_output = discriminator(fake_images)
# 计算生成器和判别器损失
gen_loss = generator_loss(fake_output)
disc_loss = discriminator_loss(real_output, fake_output)
# 计算生成器和判别器的梯度
gen_gradients = gen_tape.gradient(gen_loss, generator.trainable_variables)
disc_gradients = disc_tape.gradient(disc_loss, discriminator.trainable_variables)
# 更新生成器和判别器的参数
generator_optimizer.apply_gradients(zip(gen_gradients, generator.trainable_variables))
discriminator_optimizer.apply_gradients(zip(disc_gradients, discriminator.trainable_variables))
本文代码实现来自:豆包
数学原理参考文献:
不作溢美之词,不作浮夸文章,此文与功名进取毫不相干也!
与大家共勉~感谢您的阅读!您的三联是我更新最大的动力!