亚马逊AI图像模型Nova深度体验(含源代码)(上)

发布于:2025-02-22 ⋅ 阅读:(18) ⋅ 点赞:(0)

在本系列的上篇中,我们介绍了如何利用Amazon Nova Canvas进行创意图片内容生成,并使用Amazon Bedrock的InvokeModel API进行文本到图像(文生图)的生成。并且介绍了Nova Canvas提供的广泛的功能,包括图像修复、画布扩展、颜色引导等,使其成为强大的AI创意工具。接下来下篇中我们将继续介绍我们上篇中的方案,利用Nova生成一个完整的故事书插画。

调整Nova Canvas的生成结果

编辑提示词(Edit Prompt)

如果生成的图像没有达到预期,或者缺少某些特征,可以通过修改提示词(prompt)来调整结果。例如:

prompt = """
A rundown house with a light, the front door of the house is swung wide open
and a warm fire in a chimney can be seen.
"""

重新运行代码后,会生成符合新描述的图像。

修改随机种子(Change Seed)

如果当前提示词生成的图像不错,但想要探索一些变化,可以更改种子值(seed),以生成不同版本的图像:

seed: 23423423

这将创建一个具有相似风格但不同细节的新图像。

调整cfgScale参数

如果模型生成的图像未能严格按照提示词执行,大家可以调整 cfgScale 参数:

cfgScale: 8.5
  • 值越高(最大10.0):模型会更加严格遵循提示词的描述。
  • 值越低(最小1.1):生成的图像会带有更多随机性,可能出现创造性的变化。

负面提示词(Negative Text )

如果想要去除特定元素,可以使用 negativeText 属性。例如,要生成一张没有窗户的房屋:

negative_prompt = "window, window with light"

# ...

"textToImageParams": {
    "text": prompt,
    "negativeText": negative_prompt
},

这将告诉模型不要生成包含这些元素的图片,再次运行将生成以下图片。

大家现在已经掌握了调整Nova Canvas输出的各种方法,包括修改提示词、调整随机种子、配置cfgScale参数,以及使用负面提示词去除特定元素。

如需了解更多关于提示词优化(Prompt Optimization)和输出调整(Output Tweaking)的详细信息,请参考Nova官方文档。

生成最终输出 - 故事板(Storyboard)

现在,大家已经掌握了Nova Canvas的调整技巧,接下来可以继续生成多个图像并把他们组合生成PDF故事图画集。

大家可以选择一个故事情节,设计图片分镜布局,然后使用Python代码自动生成一个故事图画集,并导出为单页PDF。

更新 requirements.txt

请确保 requirements.txt 文件包含以下依赖项:

boto3
fpdf2

在本地 IDE 或 SageMaker Jupyter Notebook 安装依赖

如果大家使用的是SageMaker Jupyter Notebook,可以在Notebook的第一个代码单元格中运行:

!pip install boto3
!pip install fpdf2

代码示例

该代码将会生成一个完整的故事图画集PDF,包含三幅由Nova Canvas生成的插图。

# Required imports
import base64
import io
import json
import boto3
from PIL import Image
from botocore.config import Config
import time
from fpdf import FPDF

# Create the client instance (5 minute timeout)
bedrock = boto3.client(
    service_name='bedrock-runtime',
    region_name="us-east-1",
    config=Config(read_timeout=300)
)

# Define the default generated image width and height
DEFAULT_IMG_WIDTH = 480
DEFAULT_IMG_HEIGHT = 480

# Cells are used for page layout, this is the size of one cell
CELL_WIDTH = DEFAULT_IMG_WIDTH / 6

# Define a page layout of cells, 1 or 2 cell spans per row, 3 rows per page
page_layout = [[7,5], [12], [8,4]]

# Define the story for each cell
story = [
    """Two bears entering a dark, ominous wood, walking along a grassy path. Seen from behind.""",
    """Two bears in a dark, ominous wood, a small, rundown house with a light on is in front of them. Seen from behind.""",
    """A rundown house with a light, the door of the house is open and a warm fire and pot can be seen through the door.""",
    """A rundown house with a light, the door of the house is open and a warm fire and pot can be seen through the door. A shadowy figure is standing at the door""",
    """A rundown house with a light, the door of the house is open and a warm fire and pot can be seen through the door. A man is standing at the door with an axe. Two bears are running from the house towards the viewer."""
]

def image_from_text(text, width, height, file):
    body = json.dumps({
        "taskType": "TEXT_IMAGE",
        "textToImageParams": {
            "text": text
        },
        "imageGenerationConfig": {
            "numberOfImages": 1,
            "width": width,
            "height": height,
            "cfgScale": 8.0,
            "seed": 0
        }
    })

    response = 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())

    base64_image = response_body.get("images")[0]
    base64_bytes = base64_image.encode('ascii')
    image_bytes = base64.b64decode(base64_bytes)

    image = Image.open(io.BytesIO(image_bytes))
    image.save(file)

    return file

def generate_story(story, page_layout):

    outputs = []
    cells = [cell for row in page_layout for cell in row]

    for idx, text in enumerate(story):
        if idx > 0:
            time.sleep(20)
        file = image_from_text(text, int(CELL_WIDTH * cells[idx]), DEFAULT_IMG_HEIGHT, f"story-{idx}.jpg")
        outputs.append(file)

    return outputs

def build_pdf(images, page_layout, file):
    pdf = FPDF(orientation="portrait")
    pdf.set_margin(0)
    pdf.add_page()
    
    row_height = pdf.eph / len(page_layout)
    cell_width = pdf.epw / 12
    
    print(f"{pdf.epw} {cell_width} {cell_width*7}")
           # full page height, half page width pdf.epw/2

    img_idx = 0
    for r_idx, row in enumerate(page_layout):  
        cursor_y = r_idx * row_height
        
        for c_idx, cell in enumerate(row):    
            cursor_x = 0 if c_idx == 0 else cell_width * row[c_idx - 1]

            pdf.set_y(cursor_y)
            pdf.image(images[img_idx], h=row_height, w=cell_width * cell, x=cursor_x)        

            img_idx += 1
    
    pdf.output(file)

images = generate_story(story, page_layout)
build_pdf(images, page_layout, "storyboard.pdf")

Nova模型生成的完整故事图片故事集如下:

 

调整图片生成风格

假如客户对以上的生成结果很满意,但建议将风格修改为卡通风格。我们可以再次利用Nova Canvas,以内可以通过其调整提示词实现不同的图像风格。

我们修改如下代码中的修改提示词部分,再次运行生成图片。

# ...
# existing code from previous example

def generate_story_with_style(style, story, page_layout, prefix):

    outputs = []
    cells = [cell for row in page_layout for cell in row]

    for idx, text in enumerate(story):
        if idx > 0:
            time.sleep(20)
        file = image_from_text(style + text, int(CELL_WIDTH * cells[idx]), DEFAULT_IMG_HEIGHT, f"{prefix}-story-{idx}.jpg")
        outputs.append(file)

    return outputs

style = "A cartoon style image. "
prefix="cartoon"

styled_images = generate_story_with_style(style, story, page_layout, prefix)
build_pdf(styled_images, page_layout, f"{prefix}-storyboard.pdf")

然后重新运行脚本,便可以生成卡通化的故事图片集。

结论

  • Nova Canvas提供了多种方法调整生成的图像,包括修改提示词、调整种子值、配置 cfgScale 以及负面提示词。
  • 可以批量生成图像,并将其组合成PDF故事图片集,用于快速展示电影、产品、图像、文本等方面的创意概念。
  • 可通过修改提示词风格(如"cartoon style")来快速匹配客户的不同图片生成需求。

通过Nova以上强大的功能,我们就可以仅需几秒就可以生成高质量的图片故事集,极大提高在商品海报、活动营销策划、产品概念展示等方面的工作效率。