欢迎来到 Amazon Nova Canvas 工作坊! 在这个动手实践环节中, 我们将探索 Amazon Nova Canvas 强大的功能, 为 Octank 这家高端狗粮公司创建引人注目的视觉广告。
Octank 正在推出一款新的狗粮系列, 需要创造各种视觉资产:
通过本次工作坊, 我们将:
# 内置库
import base64
import io
import json
import os
import sys
# 外部依赖
import boto3
import botocore
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
# 设置 Bedrock 客户端
boto3_bedrock = boto3.client('bedrock-runtime')
以下实用函数可以可视化生成的图像以及可选的参考图像。 它对于显示和比较图像生成任务的结果非常重要, 使我们能够轻松地查看输入、输出和任何相关的颜色信息。
# 实用函数: 定义绘图函数
def plot_images(base_images, prompt=None, seed=None, ref_image_path=None, color_codes=None, original_title=None, processed_title=None):
if ref_image_path and color_codes:
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
num_subplots = 3
elif ref_image_path or color_codes:
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
num_subplots = 2
else:
fig, axes = plt.subplots(1, 1, figsize=(6, 5))
num_subplots = 1
axes = np.array(axes).ravel()
current_subplot = 0
if color_codes:
num_colors = len(color_codes)
color_width = 0.8 / num_colors
for i, color_code in enumerate(color_codes):
x = i * color_width
rect = plt.Rectangle((x, 0), color_width, 1, facecolor=f'{color_code}', edgecolor='white')
axes[current_subplot].add_patch(rect)
axes[current_subplot].set_xlim(0, 0.8)
axes[current_subplot].set_ylim(0, 1)
axes[current_subplot].set_title('颜色代码')
axes[current_subplot].axis('off')
current_subplot += 1
if ref_image_path:
reference_image = Image.open(ref_image_path)
max_size = (512, 512)
reference_image.thumbnail(max_size)
axes[current_subplot].imshow(np.array(reference_image))
axes[current_subplot].set_title(original_title or '参考图像')
axes[current_subplot].axis('off')
current_subplot += 1
axes[current_subplot].imshow(np.array(base_images[0]))
if processed_title:
axes[current_subplot].set_title(processed_title)
elif ref_image_path and seed is not None:
axes[current_subplot].set_title(f'基于参考图像生成的图像\n种子: {seed}')
elif seed is not None:
axes[current_subplot].set_title(f'生成的图像\n种子: {seed}')
else:
axes[current_subplot].set_title('处理后的图像')
axes[current_subplot].axis('off')
if prompt:
print(f"提示: {prompt}\n")
plt.tight_layout()
plt.show()
def save_image(base64_image, output_file):
with open(output_file, 'wb') as file:
file.write(base64.b64decode(base64_image))
Octank 想根据文本描述生成初始的产品包装设计。
# 定义提示
prompt = "一个白色的高级狗粮包装, 上面有一只美国爱斯基摩犬, 专业的产品摄影。狗粮名称为 Octank。"
negative_prompts = "渲染不佳, 背景细节差, 包装细节差, 文字细节差, 模糊的文字"
seed = 42
# 指定存储输出的路径
output_save_path = "images/after_text-to-image.png"
# 生成文本到图像
body = json.dumps(
{
"taskType": "TEXT_IMAGE",
"textToImageParams": {
"text": prompt, # 必需
"negativeText": negative_prompts # 可选
},
"imageGenerationConfig": {
"numberOfImages": 1, # 范围: 1 到 5
"quality": "standard", # 选项: standard 或 premium
"height": 1024,
"width": 1024,
"cfgScale": 7.5, # 范围: 1.0 (exclusive) 到 10.0
"seed": 250 #100 # 范围: 0 到 214783647
}
}
)
response = boto3_bedrock.invoke_model(
body=body,
modelId="amazon.nova-canvas-v1:0",
accept="application/json",
contentType="application/json"
)
response_body = json.loads(response.get("body").read())
response_images = [
Image.open(io.BytesIO(base64.b64decode(base64_image)))
for base64_image in response_body.get("images")
]
# 保存输出
save_image(response_body.get("images")[0], output_save_path)
# 绘制输出
plot_images(response_images, processed_title="生成的产品包装")
Octank 想创建一个他们包装设计的油画风格版本, 同时保持整体布局。
# 定义提示, 参考图像
prompt = "一个带有白色美国爱斯基摩犬的油画风格狗粮包装, 狗粮公司名称为 Octank"
reference_image_path = "images/after_text-to-image.png"
seed = 42# 可以是 0 到 214783647 之间的任意随机数
# 指定存储输出的路径
output_save_path = "images/after_image_cartooning.png"
# 编码参考图像
with open(reference_image_path, "rb") as image_file:
reference_image_base64 = base64.b64encode(image_file.read()).decode("utf-8")
# 根据参考图像生成图像
body = json.dumps(
{
"taskType": "TEXT_IMAGE",
"textToImageParams": {
"text": prompt, # 必需
"conditionImage": reference_image_base64, # 可选
"controlMode": "CANNY_EDGE", # 可选: CANNY_EDGE | SEGMENTATION
"controlStrength": 0.7, # 范围: 0.2 到 1.0,
},
"imageGenerationConfig": {
"numberOfImages": 1,
"seed": seed,
}
}
)
response = boto3_bedrock.invoke_model(
body=body,
modelId="amazon.nova-canvas-v1:0",
accept="application/json",
contentType="application/json"
)
response_body = json.loads(response.get("body").read())
response_images = [
Image.open(io.BytesIO(base64.b64decode(base64_image)))
for base64_image in response_body.get("images")
]
save_image(response_body.get("images")[0], output_save_path)
# 绘制输出
plot_images(response_images, ref_image_path = reference_image_path)
从文本生成图像是强大的, 但在某些情况下, 我们希望模型能够理解某些图像的风格, 并直接将其转移到输出图像中。 而不是从头开始, 图像变体功能使我们能够轻松地进行风格迁移。
现在, Octank 想要一个与参考图像相同风格的狗粮包装, 让我们看看这一步有多容易。
# 定义提示, 参考图像
prompt = "一个白色的高级狗粮包装, 上面有一只美国爱斯基摩犬, 专业的产品摄影。狗粮名称为 Octank"
negative_prompt = "质量差, 分辨率低"
reference_image_path = "images/sketch_dog.png"
seed = 600 # 可以是 0 到 214783647 之间的任意随机数
# 指定存储输出的路径
output_save_path = "images/after_image_variation.png"
# 编码参考图像
with open(reference_image_path, "rb") as image_file:
reference_image_base64 = base64.b64encode(image_file.read()).decode("utf-8")
body = json.dumps({
"taskType": "IMAGE_VARIATION",
"imageVariationParams": {
"text": prompt, # 可选
"negativeText": negative_prompt, # 可选
"images": [reference_image_base64], # 需要一个图像
# "similarityStrength": 1.0
},
"imageGenerationConfig": {
"numberOfImages": 1,
"quality": "premium",
"height": 1024,
"width": 1024,
#"cfgScale": 10,
"seed": seed
}
})
response = boto3_bedrock.invoke_model(
body=body,
modelId="amazon.nova-canvas-v1:0",
accept="application/json",
contentType="application/json"
)
response_body = json.loads(response.get("body").read())
response_images = [
Image.open(io.BytesIO(base64.b64decode(base64_image)))
for base64_image in response_body.get("images")
]
save_image(response_body.get("images")[0], output_save_path)
# 绘制输出
plot_images(response_images, ref_image_path = reference_image_path)
Octank 决定通过在包装上展示不同的狗狗品种来刷新他们的产品线。 但是, 他们希望保持整体设计的一致性, 只更改狗狗图像。 这就是修复图像的用武之地。 对于这个任务, Octank 想要将他们当前包装上的美国爱斯基摩犬替换为哈士奇, 同时保持其余设计不变。
让我们使用修复图像来帮助 Octank 用新的狗狗品种更新他们的包装。
# 定义提示和参考图像
prompt = "一个白色的高级狗粮包装, 上面有哈士奇狗, 专业的产品摄影。狗粮名称为 Octank"
negative_prompts = "质量差, 低分辨率"
reference_image_path = "images/after_image_cartooning.png"
mask_prompt = "美国爱斯基摩犬"
seed = 2 # 可以是 0 到 214783647 之间的任意随机数
with open(reference_image_path, "rb") as image_file:
reference_image_base64 = base64.b64encode(image_file.read()).decode("utf-8")
# 根据参考图像生成图像
body = json.dumps(
{
"taskType": "INPAINTING",
"inPaintingParams": {
"text": prompt, # 可选 - 在遮罩内部要改变的内容
"negativeText": negative_prompts, # 可选
"image": reference_image_base64, # 必需
"maskPrompt": mask_prompt, # "maskImage" 或 "maskPrompt" 是必需的
# "maskImage": "base64-encoded string",
},
"imageGenerationConfig": {
"numberOfImages": 1,
"seed": seed,
}
}
)
response = boto3_bedrock.invoke_model(
body=body,
modelId="amazon.nova-canvas-v1:0",
accept="application/json",
contentType="application/json"
)
response_body = json.loads(response.get("body").read())
response_images = [
Image.open(io.BytesIO(base64.b64decode(base64