文章目录
- 💯前言
- 💯Midjourney后置指令--seed
- 测试1
- 测试2
- 如何获取未指定种子图片的随机种子
- 注意点
- 💯Midjourney后置指令--tile
- 测试
- 💯Midjourney后置指令--q(or--quality)
- 测试
- 注意点
- 💯Midjourney后置指令--chaos
- 测试
- 注意点
- 💯Midjourney后置指令--w (or --weired)
- 测试
- 注意点
- 对比总结--chaos、--stylize、--weired区别
- 💯Midjourney后置指令--no
- 测试
- 注意点
- 💯小结
💯前言
我们在之前的文章【AI绘画】Midjourney后置指令–ar、–iw 、 --s 、–r、–stop详解中讲解了--ar、--iw 、 --s 、--r、--stop
后置指令,今天我们将介绍剩下几项Midjourney中常用的后置指令,包括–seed、–tile、–q、–chaos、–w、--no
,这些指令可以帮助我们更好地控制图像的生成过程和结果。通过合理使用这些指令,我们可以在Midjourney创作中获得更多灵活性和创意表达的空间。
- Midjourney官方使用手册
💯Midjourney后置指令–seed
- 作用:使用相同的种子,会让相同参数下多次生成的图片几乎一致。
- 简单原理:seed决定初始图象。如果我们使用相同的图片参数和种子值,我们会得到类似的初始图像
Midjourney--seed官方使用文档
测试1
测试提示词:
A cat sitting by the window looking out at the street
- 在使用Midjourney生成图片时,许多人会注意到,尽管设定的参数相同,每次生成的图像却有所不同。比如,当我们使用相同的提示词,如“一只猫坐在窗边看着外面的街道”,生成的图片却在细节上有所差异。这种机制其实非常有利,因为全世界的用户都在生成图像,如果每次生成的结果完全相同,就可能引发抄袭或版权问题。但由于这种随机性存在,这样的风险被有效避免了。
提示词加上sunset:
A cat sitting by the window looking out at the street,sunset
- 然而,这种随机性也带来了一些挑战,尤其是当我们想要精确调整图像时。举个例子,如果我想在现有的提示词中加入’黄昏’(sunset),图片会立即产生变化。然而,我很难知道这些新增词汇究竟对画面产生了什么具体影响,因为每次生成的基础画面本身就不同。
测试2
提示词加上种子0906:
A cat sitting by the window looking out at the street --ar 16:9 --seed 0906
- 因此,当我们真正想了解某个提示词对图像的影响时,需要先将图像的基础固定住。在固定的基础上调整提示词和参数,才能准确对比不同词汇的效果。为此,我们可以使用一个重要的参数——种子参数(seed)。--seed 的中文翻译是“种子”。它的作用是,当我们使用相同的种子时,在相同参数的情况下,多次生成的图片会基本保持一致。这样可以方便我们在进行参数调整或修改提示词时,更加精确地对比结果的变化。
在种子不变情况下,新增提示词:
A cat sitting by the window looking out at the street --ar 16:9 --seed 0906
- 在新生成的图片中,通过保持相同的种子(–seed)并添加提示词“sunset”,我们可以明显看到生成的图片在原有图像基础上增加了“落日”的元素。从图片中可以看出,小猫的朝向、背景中的叶子位置等关键特征保持一致,这体现了使用相同种子时的可控性和一致性。而“sunset”的加入,则带来了新的视觉元素,使图片呈现出落日的场景,同时保持了与原图的相似性。这正是种子参数的作用所在——在固定的画面基础上进行小范围的调整,从而实现对变化的精准控制。
如何获取未指定种子图片的随机种子
- 有时我们可能遇到这样的情况:在没有指定种子参数的情况下生成了一张图像,结果生成的图片非常满意,我们希望在此基础上修改提示词,进行进一步调整。但是问题来了,由于生成图片时没有预先指定种子,图像是随机生成的。那我们该如何获取这张图片的种子值呢?
- 鼠标悬停至出图的四宫格
- 选择第一个按钮添加反应
- 输入并选择envelope
- 点击下方的小信封
- 查看midjourney发送的私信
- 找到图片的随机种子
- 测试系统给出的随机种子,生成的图片与原图非常相似
注意点
-
如果不做设置,每次生成图片的种子是完全不同的
-
取值范围
0 —— 2 32 − 1 0 —— 2^{32} - 1 0——232−1
0 —— 4294967295 0 —— 4294967295 0——4294967295
-
种子值仅影响生成图片的初始状态
💯Midjourney后置指令–tile
作用:使用该参数后,生成的图像上下、左右可连接,可创建无缝图案。可用于壁纸、布料和纹理。
Midjourney--tile官方使用文档
测试
intricate geometric pattern with floral elements, vibrant colors --tile
- 生成一个复杂的几何图案,带有花卉元素:
- 放入PS中发现图片可以完美的拼在一起。
💯Midjourney后置指令–q(or–quality)
表象:决定了图片生成质量
原理:决定生成一张图片花了多少时间
Midjourney--quality官方使用文档
测试
--q 0.5:
a detailed portrait of a futuristic robot with glowing eyes, intricate metallic textures --q 0.5
- 在这个质量设置下,图像的生成速度较快,但细节较为简单。图像的光影效果和复杂的金属纹理没有很好地表现出来,图像整体看起来较为模糊,细节部分不够丰富,适合用于快速预览或者不需要过多细节的场景。
--q 1:
a detailed portrait of a futuristic robot with glowing eyes, intricate metallic textures --q 1
- 在默认质量1下,图像的细节表现已经有了明显的提升。机器人的金属纹理更加复杂,发光的眼睛也更加清晰。虽然生成速度适中,但画面的质感、光影效果和整体细节已经较为饱满,适合大多数场景使用。
--q 2:
a detailed portrait of a futuristic robot with glowing eyes, intricate metallic textures --q 2
- 在最高质量2的设置下,图像的每一个细节都被放大,金属质感更加细腻,光影的处理也非常细致。发光眼睛的效果尤其突出,整体图像的精致度达到最高,非常适合对细节要求极高的创作场景。然而,使用这个设置时,生成图像的时间会明显变长。
注意点
-
该参数默认值为1
-
当前版本,只能把该参数设置为0.5 ,1, 2
-
当设置为更大的数值时,会自动把数值降为2
-
该参数的设置不影响分辨率的大小。之所以能够在调大数值之后,图片质量提高,是因为他在这张图片上花更多的时间去进行生成。
-
该值不一定越大越好。在特定情况下,如抽象画生成时,低于1的值也会有很好的效果。
💯Midjourney后置指令–chaos
作用:混乱模式。该参数决定midjourney一次生成的四张图片在
内容、色彩、风格
的不同程度
Midjourney--chaos官方使用文档
Chaos
在英文中意为“混乱”。它在 Midjourney 中的作用是控制生成图像时的变化幅度。在之前当我们使用相同的提示词生成四张图像时,通常这些图像的风格会比较一致。然而,通过调整 chaos 值,我们可以影响图像之间的差异程度。
测试
可爱的2D卡通角色提示词:
a cute 2D cartoon character in a vibrant fantasy world, simple shapes and bright colors --chaos 80
- 设置了混乱值 80 后,可以明显看到四张图像之间在风格和构图上出现了较大的差异。虽然提示词相同,但每张图像呈现出的视觉效果截然不同。这种差异不仅体现在角色的设计上,也反映在背景、颜色和整体氛围上。高混乱值带来了更多的随机性,使得每张图片在同一基础上产生了独特的变化,充分展示了 --chaos 参数的作用。
注意点
-
该参数默认值为0
-
取值范围0——100
💯Midjourney后置指令–w (or --weired)
作用:怪异模式。该参数生成的图像引入了古怪和另类的特性,会产生独特的、意想不到的效果。
Midjourney--weired官方使用文档
- --weird(怪异值)是一个非常有趣的参数。它能够为图片加入一些古怪、另类的特征,生成具有独特、不寻常的效果。使用这个参数时,图像可能会呈现出意想不到的、甚至有时带有恐怖或令人不安的元素。这为创作带来了更多的创意空间,适合用于探索超现实主义、奇异风格或想要突破常规的艺术作品。
测试
宁静的乡村小屋:
a beautiful cottage in a peaceful countryside, surrounded by trees and flowers --ar 16:9
- 在未使用 --weird 参数的情况下,生成的图像展现了一个典型的、和谐的乡村场景,画面中的小屋被绿树和鲜花环绕,整体氛围非常宁静与自然。每张图片的色彩鲜艳,建筑和自然环境之间的搭配和谐,给人一种舒适、田园诗般的美感。
–weird 2800 :
a beautiful cottage in a peaceful countryside, surrounded by trees and flowers --ar 16:9 --weird 2800
- 在加入 --weird 2800 参数后,虽然场景依旧是乡村小屋,但整体画风开始变得古怪和略带诡异。图像中的小屋似乎被奇怪的植物或阴森的环境包围,光影效果也更具神秘感,场景变得更加阴郁且不寻常。这些微妙的怪异特征使得整个场景看起来有些超现实或不合常理,带有一种令人不安的氛围。
注意点
- –weird默认值为0
- –weird取值范围:0-3000
- –weird与种子值不完全兼容,最好不要同时使用
- 绝大多数订单情况下,我们都用不到这个值,除非我们做恐怖、悬疑类图片。
对比总结–chaos、–stylize、–weired区别
- --chaos混乱模式更注重不同图片初始网格的区别
- --stylize风格化更注重midjourney默认美术风格的应用程度
- --weired怪异模式更注重生成图片的不寻常程度
原图:
a mystical forest with glowing plants and ancient ruins, ethereal atmosphere, detailed trees and vines --ar 16:9
原始提示词
生成的图像展示了一个神秘的森林场景,背景中有发光的植物和古老的废墟,整体氛围安静而神秘。四张图片的风格较为一致,表现出柔和的光线和浓密的树木,环境中的细节处理得非常自然,展现出平和而略带神秘的氛围。
--chaos 50:
a mystical forest with glowing plants and ancient ruins, ethereal atmosphere, detailed trees and vines --chaos 50 --ar 16:9
- 在加入
--chaos 50
参数后,四张图像的差异性变得更为明显。图像的色彩开始大幅度变化,背景中的废墟造型、光线、植被以及整体氛围都有显著不同。例如,有的图像充满亮绿色和黄色的光线,有的图像则使用暗色调和神秘氛围。这一设定增强了画面在构图和风格上的差异性,体现了混乱值对图像随机性的影响。
--stylize 1000:
a mystical forest with glowing plants and ancient ruins, ethereal atmosphere, detailed trees and vines --stylize 1000 --ar 16:9
- 加入
--stylize 1000
后,图像的美术风格显得更加突出。整体画面显得更加梦幻、艺术化,光线与阴影的处理更加精致。每个图像中,森林的树木、废墟的光影处理呈现出极高的艺术感,细节显得更加富有表现力,仿佛置身于一个童话般的幻想世界。这种风格化使图像显得更加富有情感和美学价值。
--weird 1500:
a mystical forest with glowing plants and ancient ruins, ethereal atmosphere, detailed trees and vines --weird 1500 --ar 16:9
- 使用
--weird 1500
参数生成的图像出现了更具怪异和超现实感的变化。场景中的植被和废墟显得更加奇特,颜色搭配和构图充满了不寻常的元素。例如,某些图像中的光线和树木的处理显得更加诡异,有些图片表现出非自然的色彩和形状,场景带有强烈的异样感。整个画面充满了奇幻和超现实的视觉冲击,体现了怪异值对生成图像带来的戏剧性影响。
💯Midjourney后置指令–no
作用:反向提示词,告诉Midjourney什么是我们不需要的。
Midjourney--no官方使用文档
格式:
--no item1, item2, item3, item4
- –no 是一个非常有趣的后置参数,它的作用是实现反向提示词。如果你对 Stable Diffusion 有了解,那你对反向提示词的概念应该不会陌生。反向提示词的作用就是告诉 MidJourney 什么是我们不需要的。在写提示词时,我们通常是告诉 MidJourney 生成我们需要的内容。但有时我们可能想排除一些元素,而这时就可以使用 --no 参数。通过这个参数,我们可以告诉 MidJourney 哪些元素我们不希望出现在图像中,从而更好地控制生成结果。
测试
原图:
a beautiful park with children playing, sunny day, colorful balloons --ar 16:9
- 在没有使用 --no 参数的情况下,生成的图像展现了一个充满生机和色彩的公园。阳光明媚,孩子们在公园里快乐地玩耍,天空中飘浮着许多五颜六色的气球。气球在图像中占据了重要位置,为整个画面增添了更多的活力和欢乐氛围。整体感觉非常愉悦且充满童趣。
--no:
a beautiful park with children playing, sunny day, colorful balloons --no balloons --ar 16:9
- 在加入 --no balloons 参数后,生成的图像依旧保持了明亮的公园和玩耍的孩子,但画面减少了气球的装饰,显得更加安静和平和,视觉上更加自然朴素。尽管阳光依旧明媚,场景整体上少了一些活泼和童趣,呈现出一种更接近自然的宁静氛围。
这里由于原本提示词中有气球,所以no balloons难以消除所有的气球,气球只是数量变少。
注意点
--no+参数等于正面提示词中赋予-0.5的权重
原图:
Perfume still life --ar 16:9
- 在这张图中,香水瓶与柔和的花朵静物布置在一起,背景中有精美的花朵元素,营造出一种柔美、温馨的氛围。光线柔和,香水瓶的反射和背景中的花朵相得益彰,整体呈现出优雅的静物艺术风格。
flower::-0.5:
flower::-0.5 ,Perfume still life --ar 16:9
- 通过降低权重 flower:: -0.5,我们成功去掉了花朵,画面更加聚焦于香水瓶的展示。花朵完全消失,背景显得更加简洁。这种方法有效地删除了花朵元素,突出了香水瓶的细节和反射效果。
--no flower:
Perfume still life --ar 16:9 --no flower
- 使用 --no flower 完全去除了花朵元素,香水瓶成为画面的唯一主角。背景更加干净,香水瓶的轮廓和光影效果得到了极大提升,突显出产品的精致。这一效果与降低权重 flower:: -0.5 的效果基本等价,同样达到了简化画面的目的,使得焦点更集中在香水瓶上。
💯小结
通过合理使用 --seed、–tile、–q、–chaos、–weird 和 --no 等指令,不仅能够提高图像的生成质量,还能为创作带来更多的控制和灵感。这篇文章的目的是通过实际案例演示这些指令的效果,让大家在创作AI绘画时能更灵活地实现自己的想法。希望这篇文章能为每位读者的创作带来实用的帮助和启发,让我们在AI绘画的道路上共同进步。- AI绘画正在逐渐改变艺术创作的方式,为设计师、艺术家和普通用户提供了更多的创作可能。展望未来,AI绘画将继续推动艺术的革新,打破传统与技术的界限,实现更多人对于创意表达的追求。无论是在商业、设计还是个人创作领域,AI绘画都将成为一种强大的助力工具,让创作变得更加自由、灵活和多元化。
import torchimport torch.nn as nnimport torch.optim as optimfrom torch.utils.data import Dataset, DataLoaderfrom torchvision import transforms, utilsfrom PIL import Imageimport numpy as npimport cv2import osimport randomclass PaintingDataset(Dataset): def __init__(self, root_dir, transform=None): self.root_dir = root_dir self.transform = transform self.image_files = os.listdir(root_dir) def __len__(self): return len(self.image_files) def __getitem__(self, idx): img_name = os.path.join(self.root_dir, self.image_files[idx]) image = Image.open(img_name).convert('RGB') if self.transform: image = self.transform(image) return imageclass ResidualBlock(nn.Module): def __init__(self, in_channels): super(ResidualBlock, self).__init__() self.conv_block = nn.Sequential( nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=1, padding=1), nn.InstanceNorm2d(in_channels), nn.ReLU(inplace=True), nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=1, padding=1), nn.InstanceNorm2d(in_channels) ) def forward(self, x): return x + self.conv_block(x)class Generator(nn.Module): def __init__(self): super(Generator, self).__init__() self.downsampling = nn.Sequential( nn.Conv2d(3, 64, kernel_size=7, stride=1, padding=3), nn.InstanceNorm2d(64), nn.ReLU(inplace=True), nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1), nn.InstanceNorm2d(128), nn.ReLU(inplace=True), nn.Conv2d(128, 256, kernel_size=3, stride=2, padding=1), nn.InstanceNorm2d(256), nn.ReLU(inplace=True) ) self.residuals = nn.Sequential( *[ResidualBlock(256) for _ in range(9)] ) self.upsampling = nn.Sequential( nn.ConvTranspose2d(256, 128, kernel_size=3, stride=2, padding=1, output_padding=1), nn.InstanceNorm2d(128), nn.ReLU(inplace=True), nn.ConvTranspose2d(128, 64, kernel_size=3, stride=2, padding=1, output_padding=1), nn.InstanceNorm2d(64), nn.ReLU(inplace=True), nn.Conv2d(64, 3, kernel_size=7, stride=1, padding=3), nn.Tanh() ) def forward(self, x): x = self.downsampling(x) x = self.residuals(x) x = self.upsampling(x) return xclass Discriminator(nn.Module): def __init__(self): super(Discriminator, self).__init__() self.model = nn.Sequential( nn.Conv2d(3, 64, kernel_size=4, stride=2, padding=1), nn.LeakyReLU(0.2, inplace=True), nn.Conv2d(64, 128, kernel_size=4, stride=2, padding=1), nn.InstanceNorm2d(128), nn.LeakyReLU(0.2, inplace=True), nn.Conv2d(128, 256, kernel_size=4, stride=2, padding=1), nn.InstanceNorm2d(256), nn.LeakyReLU(0.2, inplace=True), nn.Conv2d(256, 512, kernel_size=4, stride=2, padding=1), nn.InstanceNorm2d(512), nn.LeakyReLU(0.2, inplace=True), nn.Conv2d(512, 1, kernel_size=4, stride=1, padding=1) ) def forward(self, x): return self.model(x)def initialize_weights(model): for m in model.modules(): if isinstance(m, (nn.Conv2d, nn.ConvTranspose2d)): nn.init.normal_(m.weight.data, 0.0, 0.02) elif isinstance(m, nn.InstanceNorm2d): nn.init.normal_(m.weight.data, 1.0, 0.02) nn.init.constant_(m.bias.data, 0)device = torch.device("cuda" if torch.cuda.is_available() else "cpu")generator = Generator().to(device)discriminator = Discriminator().to(device)initialize_weights(generator)initialize_weights(discriminator)transform = transforms.Compose([transforms.Resize(256), transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])])dataset = PaintingDataset(root_dir='path_to_paintings', transform=transform)dataloader = DataLoader(dataset, batch_size=16, shuffle=True)criterion = nn.MSELoss()optimizerG = optim.Adam(generator.parameters(), lr=0.0002, betas=(0.5, 0.999))optimizerD = optim.Adam(discriminator.parameters(), lr=0.0002, betas=(0.5, 0.999))def generate_noise_image(height, width): return torch.randn(1, 3, height, width, device=device)for epoch in range(100): for i, data in enumerate(dataloader): real_images = data.to(device) batch_size = real_images.size(0) optimizerD.zero_grad() noise_image = generate_noise_image(256, 256) fake_images = generator(noise_image) real_labels = torch.ones(batch_size, 1, 16, 16, device=device) fake_labels = torch.zeros(batch_size, 1, 16, 16, device=device) output_real = discriminator(real_images) output_fake = discriminator(fake_images.detach()) loss_real = criterion(output_real, real_labels) loss_fake = criterion(output_fake, fake_labels) lossD = (loss_real + loss_fake) / 2 lossD.backward() optimizerD.step() optimizerG.zero_grad() output_fake = discriminator(fake_images) lossG = criterion(output_fake, real_labels) lossG.backward() optimizerG.step() with torch.no_grad(): fake_image = generator(generate_noise_image(256, 256)).detach().cpu() grid = utils.make_grid(fake_image, normalize=True) utils.save_image(grid, f'output/fake_painting_epoch_{epoch}.png')def apply_style_transfer(content_img, style_img, output_img, num_steps=500, style_weight=1000000, content_weight=1): vgg = models.vgg19(pretrained=True).features.to(device).eval() for param in vgg.parameters(): param.requires_grad = False content_img = Image.open(content_img).convert('RGB') style_img = Image.open(style_img).convert('RGB') content_img = transform(content_img).unsqueeze(0).to(device) style_img = transform(style_img).unsqueeze(0).to(device) target = content_img.clone().requires_grad_(True).to(device) optimizer = optim.LBFGS([target]) content_layers = ['conv_4'] style_layers = ['conv_1', 'conv_2', 'conv_3', 'conv_4', 'conv_5'] def get_features(image, model): layers = {'0': 'conv_1', '5': 'conv_2', '10': 'conv_3', '19': 'conv_4', '28': 'conv_5'} features = {} x = image for name, layer in model._modules.items(): x = layer(x) if name in layers: features[layers[name]] = x return features def gram_matrix(tensor): _, d, h, w = tensor.size() tensor = tensor.view(d, h * w) gram = torch.mm(tensor, tensor.t()) return gram content_features = get_features(content_img, vgg) style_features = get_features(style_img, vgg) style_grams = {layer: gram_matrix(style_features[layer]) for layer in style_features} for step in range(num_steps): def closure(): target_features = get_features(target, vgg) content_loss = torch.mean((target_features[content_layers[0]] - content_features[content_layers[0]])**2) style_loss = 0 for layer in style_layers: target_gram = gram_matrix(target_features[layer]) style_gram = style_grams[layer] layer_style_loss = torch.mean((target_gram - style_gram)**2) style_loss += layer_style_loss / (target_gram.shape[1] ** 2) total_loss = content_weight * content_loss + style_weight * style_loss optimizer.zero_grad() total_loss.backward() return total_loss optimizer.step(closure) target = target.squeeze().cpu().clamp_(0, 1) utils.save_image(target, output_img)