用 Nano Banana 复活图像档案:Google Cloud generative-ai 仓库的一致图像生成实战指南
【免费下载链接】generative-aiSample code and notebooks for Generative AI on Google Cloud, with Gemini Enterprise Agent Platform项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai
导读
本文基于 Google Cloud generative-ai 仓库 的媒体生成(Media Generation)模块,围绕 一致图像生成实战 Notebook 展开,讲解如何用 Nano Banana 图像模型(gemini-3.1-flash-lite-image,即 Nano Banana 2 Lite)从一张老档案图中提取角色、制作角色参考图,并仅凭提示词生成一系列风格与角色完全一致的场景图,最终用networkx把整个生成过程可视化为一颗有向图。读完本文,你将掌握:Nano Banana 的 API 接入与生成参数配置、基于"参考图 + 提示词"的一致图像生成提示工程技巧、以及一套可复用的"资产流水线"(提取→参考图→连续场景→元数据存档)的完整实现思路。
挑战:让沉睡的图像档案重获新生
几乎每个人手里都有一批"旧图":也许是几年前 AI 生成的一次性作品,也许是随手拍下却再没使用的素材。传统做法是拿修图软件去改,这需要非常专业的技术,很多时候甚至不可能完成,于是这些档案就永远躺在文件夹里吃灰。
Notebook 用一句话点出核心痛点:"我们有很多值得在不同场景中复用的既有图像,但修改图像是一道极其复杂、甚至不可能完成的任务。"而状态越来越强的视觉模型让这个问题有了新的解法。作者设定的挑战分为三步:
- 从一张档案图出发——选定一张想复用的旧图;
- 提取角色,生成全新的参考图——把图中角色"挖"出来,做成设计参考;
- 仅用提示词 + 新资产生成一组连续图像——讲述这个角色的旅程故事。
整个过程全部基于 Nano Banana 的图像生成与空间理解能力,不需要任何传统图像编辑软件。
环境搭建与 Gemini API 配置
依赖安装
Notebook 使用如下 Python 包(见 一致图像生成实战 Notebook 的 "Setup" 一节):
google-genai:Google Gen AI Python SDK,几行代码即可调用 Gemini;networkx:图结构管理,用于把生成过程建模为有向图;tenacity:请求重试管理(google-genai的依赖);matplotlib与pillow:数据可视化与图像处理(networkx的依赖)。
安装命令:
%pip install --quiet "google-genai>=2.12.1" "networkx[default]"两种 API 接入方式
调用 Gemini 图像模型有两种方式,Gen AI SDK 提供统一接口,只需通过环境变量区分:
方式一:Agent Platform(原 Vertex AI)
- 前提:一个 Google Cloud 项目,且已启用 Agent Platform API;
- 环境变量:
GOOGLE_GENAI_USE_ENTERPRISE="True"GOOGLE_CLOUD_PROJECT="<PROJECT_ID>"GOOGLE_CLOUD_LOCATION="<LOCATION>"
💡 预览模型(preview)的 location 必须设为
global;正式可用(GA)模型则可就近选择区域。
方式二:Google AI Studio(Gemini API Key)
- 前提:一个 Gemini API key;
- 环境变量:
GOOGLE_GENAI_USE_ENTERPRISE="False"GOOGLE_API_KEY="<API_KEY>"
环境配置建议存放在源码之外:IDE 中用.env文件,Colab 中用左侧面板的 Secrets,Colab Enterprise 与 Workbench 则自动注入项目和区域。
环境自动探测函数
Notebook 提供了一套check_environment()辅助函数,按"手动配置 → 企业环境(Workbench/Colab Enterprise)→ Colab → 本地"的优先级自动探测并设置环境变量,核心逻辑如下:
def get_vars(getenv): # 限制 getenv 调用次数(可能触发 Secret 访问的 UI 确认) if enterprise_str := getenv("GOOGLE_GENAI_USE_ENTERPRISE", ""): enterprise = enterprise_str.lower() in ["true", "1"] else: enterprise = bool(getenv("GOOGLE_CLOUD_PROJECT", "")) project = getenv("GOOGLE_CLOUD_PROJECT", "") if enterprise else "" location = getenv("GOOGLE_CLOUD_LOCATION", "") if project else "" api_key = getenv("GOOGLE_API_KEY", "") if not project else "" return enterprise, project, location, api_key def check_define_env_vars(enterprise, project, location, api_key): match (enterprise, bool(project), bool(location), bool(api_key)): case (True, True, _, _): location = location or "global" # Agent Platform - 项目 [+区域] define_env_vars(enterprise, project, location, "") case (True, False, _, True): define_env_vars(enterprise, "", "", api_key) # Agent Platform - API key case (False, _, _, True): define_env_vars(enterprise, "", "", api_key) # Google AI Studio - API key case _: return False return True配置完成后,通过check_configuration(client)打印当前使用的服务(Agent Platform 或 Google AI Studio)、项目前缀或 API key 掩码,便于排查问题。
模型选择:Nano Banana 家族与 gemini-3.1-flash-lite-image
本挑战选用的模型是Gemini 3.1 Flash-Lite Image(Nano Banana 2 Lite),Notebook 称其为 Nano Banana 家族中速度最快、成本最低的成员,模型 ID 为:
NANO_BANANA_MODEL = "gemini-3.1-flash-lite-image"关于该模型的能力边界,仓库中的 Gemini 3.1 Flash Lite Image 入门教程 提供了可交叉验证的细节:
- 生成的图像均为1K分辨率,并包含 C2PA 内容凭证元数据与 SynthID 水印;
- 一次请求最多可携带 14 张参考图,但参考图数量限制在 3 张以内时一致性最佳;
- 支持从视频生成图像(模型观察视频帧并基于视觉内容生成新图)。
而在本挑战中(Notebook "Gemini model" 一节)还给出了分辨率规则:Nano Banana 2 Lite 生成 1K 图像(1:1时为1024 × 1024像素),其他宽高比按 token 等价的等效分辨率输出;更大的 Nano Banana 模型可生成 2K 或 4K 图像。
生成配置与请求助手函数
生成参数配置
Notebook 用GenerateContentConfig+ImageConfig统一封装请求参数:
RESPONSE_MODALITIES = ["IMAGE"] # 可加 "TEXT" 以获得文本反馈(或用于多轮对话) # 支持的宽高比:1:1, 1:4, 4:1, 1:8, 8:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9 ASPECT_RATIO = "16:9" GENERATION_CONFIG = GenerateContentConfig( response_modalities=RESPONSE_MODALITIES, image_config=ImageConfig( aspect_ratio=ASPECT_RATIO, image_size="1K", output_mime_type="image/png" if client.vertexai else None, ), )几个关键参数的实际影响:
aspect_ratio:直接决定输出画幅。本挑战使用"16:9",生成1376 × 768像素的图像;若省略该参数,Gemini 会取输入图像(多张时取最后一张)的宽高比,自动匹配最接近的受支持比例;image_size:设置为"1K"(Nano Banana 2 Lite 的最高档位);output_mime_type:仅在使用 Agent Platform(client.vertexai为真)时指定image/png,可确保输出格式稳定;response_modalities:声明响应包含图像模态;加上"TEXT"后模型可以输出说明性文字,便于迭代式对话。
generate_content 与重试机制
请求封装函数generate_content(sources, prompt)把若干 PIL 参考图与提示词拼进contents后调用client.models.generate_content,随后从response.candidates[0].content.parts中逐 part 提取文本(用 Markdown 显示)与图像(经part.as_image()._pil_image转成 PIL 图像):
def generate_content(sources, prompt): prompt = prompt.strip() contents = [*sources, prompt] if sources else prompt response = None for attempt in get_retrier(): with attempt: response = client.models.generate_content( model=NANO_BANANA_MODEL, contents=contents, config=GENERATION_CONFIG, ) # ...从 response.candidates[0].content.parts 提取 image 并返回重试器基于tenacity,最多尝试 7 次,首次等待 10 秒、之后每次递增 1 秒;仅在两类ClientError下重试:
def should_retry_request(err): if not isinstance(err, ClientError): return False match err.code: case 400 if err.message is not None and " try again " in err.message: # 项目首次访问 Cloud Storage(服务代理预置)时的瞬时错误 retry = True case 429: # 临时项目配额只有 1 QPM 时的限流错误 retry = True return retry这是生产级请求管理的关键一环:图像生成请求耗时长、偶发限流,加上重试能显著提升 Notebook 在 workshop 等受限环境下的稳定性。
资产管理:把生成过程变成可复用的资产流水线
本挑战最有价值的设计之一,是把"生成结果"抽象为资产(Asset),并记录每张图"由谁生成"。核心数据结构如下:
class AssetId(enum.StrEnum): ARCHIVE = "0_archive" # 原始档案图 ROBOT = "1_robot" # 角色卡(正/背面 + 背包) MOUNTAINS = "2_mountains" # 第一场景:山 VALLEY = "3_valley" # 山谷 FOREST = "4_forest" # 森林 CLEARING = "5_clearing" # 林中空地 ASCENSION = "6_ascension" # 攀山 SUMMIT = "7_summit" # 登顶 BRIDGE = "8_bridge" # 悬索桥 HAMMOCK = "9_hammock" # 吊床(终点) @dataclass class Asset: id: str source_ids: Sequence[str] # 生成该资产所依赖的源资产 ID(祖先) prompt: str # 生成该资产所用的提示词 pil_image: PIL_Image class Assets(dict[str, Asset]): def set_asset(self, asset): # 新资产会覆盖同名旧资产 self[asset.id] = asset def generate_image(source_ids, prompt, new_id=""): sources = [assets[source_id].pil_image for source_id in source_ids] image = generate_content(sources, prompt) if image and new_id: assets.set_asset(Asset(new_id, source_ids, prompt, image))注意Asset记录了两条关键元信息:源资产 ID 列表(血缘关系)和生成提示词。这为后面的"生成图可视化"和"PNG 元数据存档"打下了基础——整个流水线不需要任何数据库,靠数据结构本身就能完整回溯每一张图的来历。
核心流程一:从档案到角色参考图
载入参考档案
Notebook 从公共 URL 拉取一张 2024 年 7 月用 Imagen 3 beta 生成的羊毛毡小蓝机器人图作为档案素材(提示词大意是"白色背景上的一只小手感羊毛毡蓝色机器人玩具")。当年这类一次性生成没有可复现性,机器人似乎"永远消失了"——这正是档案复活的起点:
def load_archive(): image = get_image_from_url(ARCHIVE_URL) # urllib 下载 + PIL.Image.open assets.set_asset(Asset(AssetId.ARCHIVE, [], "", image))简单提取的局限:背景移除 ≠ 真正的提取
第一版提示词试图把机器人"抠"出来:
Convert everything but the robot to pure white pixels.结果机器人被完美提取——但这本质上只是"去背景",很多模型已经能做到。作者特别强调了两点:
- 这类提示词沿用了图形软件的术语("纯白像素"),而现在应该用图像构图的思维来思考;
- 使用传统二值掩码(binary mask)并不一定是好主意,因为物体边缘和阴影承载着形状、纹理、位置、光照等重要信息,粗暴抠图会把这些细节一起抹掉。
角色卡(Character Sheet):基于空间理解的高级提取
于是作者回到档案图,直接让模型生成一张角色设定图(character sheet),一次完成"多角度视图 + 新增道具":
- Scene: Character sheet of the robot, based on the provided image. - Setting: Isolated on a pure white background, razor-sharp focus, vibrant saturated colors, bright studio lighting. - Left Side: Straight-on front view of the robot wearing a small backpack made of warm chocolate-brown suede, with thin, matching straps around the shoulders. - Right Side: Straight-on back view of the robot wearing the same backpack. The backpack's flap is secured by a tiny, matte-brass, rounded-square ring buckle. The back of the robot's head must be completely seamless. - Text: Small sans-serif text. Centered at the top, a caption "ROBOT CHARACTER SHEET". At the bottom, label the left side "FRONT VIEW" and the right side "BACK VIEW".Gemini 具备**空间理解(spatial understanding)**能力,因此能在保持视觉特征的前提下提供不同视角。这次生成有几个值得注意的设计决策:
- 提示词聚焦于场景构图(左正视图/右背视图、文字排版、光照),这是媒体工作室常见的做法;
- 由于只描述了背包的部分特征(比如一个搭扣),未描述的部分每次生成会有差异——如果需要精确控制,可以额外提供真实背包的参考照片,并指示模型"把背包改造成羊毛毡风格";
- 为了简洁,背包直接画进了角色卡;生产级管线通常会把它拆成单独的配件表(accessory sheet);
- 反复生成会保持一致性,保留原图中可见的机器人全部特征。
至此,"角色卡"资产(1_robot)成为后续所有场景的设计基准。
核心流程二:用"参考图 + 提示词"生成连续场景
第一场景定基调
第一张场景图决定了整个故事的整体观感,值得多花时间打磨。作者用角色卡作为唯一参考,生成了"山景":
- Image 1: Reference robot character sheet. - Scene: Macro photography of a beautifully crafted miniature diorama. - Background: Soft focus on an infinite panoramic range of interspersed, dome-like smooth-felt mountains, in random shades of medium blue/green, all with curvy white snowcaps, extending over the entire horizon. - Foreground: On the bottom left, the robot stands on the edge of a medium-gray felt cliff, captured from a 3/4 rear view, looking out over a sea of clouds (made of white cotton). - Lighting: Studio, warm, clean and soft.作者刻意把山形容为"dome-like(圆顶状)",为后面"角色站在山顶"埋下伏笔。这里的经验是:第一场景的提示词可以多迭代几次,选最喜欢的变体,因为它会以级联方式影响后续所有场景。
连续转场:山谷、森林与空地
从第二张场景起,生成输入通常包含两张参考图:角色卡(保角色一致)+ 上一张场景(保故事上下文)。例如"山谷"场景:
- Image 1: Reference robot character sheet. - Image 2: Previous scene. - The robot has descended from the cliff into a gray felt valley. It stands in the center, seen directly from the back. It is holding/reading a felt map. - Large, smooth, round felt rocks in various beige/gray shades are visible on the sides. - Background: The distant infinite panoramic mountain range extending over the entire horizon. A thin layer of clouds obscures its base and the end of the valley. - Lighting: Golden hour light, soft and diffused.这里的提示词工程有三个要点:
- 显式引用输入图编号:
"Image 1:…"、"Image 2:…"至关重要——角色卡里有正/背两个机器人、上一场景里还有一个,不指明编号,"the robot" 可能指代任意一个。更保险的写法是"the [entity] from image [number]"; - 没写的部分 = 创造空间:山谷没有精确描述,因此每次生成会有不同的、有趣的结果;想要更高确定性就把提示词写精确;
- 光照是叙事工具:山谷换成"黄金时刻"光线后,整个场景氛围焕然一新。
森林场景则展示了**控制"跨场景残留物"**的技巧:
- The robot continues its journey through the valley and faces a dense wall of giant, thin trees hiding the entire background. - The robot is on the right, seen from a 3/4 rear angle, looking up at the trees. It is no longer holding the map. Instead, its arms are raised beside its ears. - In the bottom-left and bottom-right corners, rocks (similar to Image 2) are partially visible."no longer holding the map" 这句是故意的:如果不说明,模型会自行决定地图的去向(拿着?扔地上?),导致结果随机。而未描述的部分(如视角、森林细节)则会从上一次场景自然继承,比如光源、质量和方向都会被保留。同理,进入空地场景时只改了地面(绿毡 + 白毡雪),树木大多会被保留。
登山、登顶、桥与吊床
回到最初的山景(用MOUNTAINS作参考而非 VALLEY,直接回到该环境),生成登山场景:
- Scene: A medium-wide shot of the robot climbing a broad, dome-shaped, medium-green mountain. - Composition: The mountain is centered, with the robot on the left slope shown from a 3/4 rear angle. - Action & Details: The robot has both feet on the mountain and uses two miniature ice picks (felt, with brown handles and gray heads) to reach the summit, planting them into the bottom part of the white felt snowcap. - Background: The distant mountain range spans the entire horizon.登顶场景则是"移除道具 + 姿态变化":
- The robot reaches the top and stands on the summit, seen from the front. - It is no longer holding the ice picks, which are planted upright in the snow on either side. - It has both arms raised as a sign of victory. Its face and hands are unchanged.随后进入"大幅重组场景"阶段——用祈使句(imperative)构图:
- Remove the ice picks. - Move the center mountain to the left edge of the image and add a slightly taller medium-blue mountain to the right edge. - Suspend a stylized felt bridge between the two mountains: its deck is made of stylized thick planks of plain felt in various wood shades. - Place the robot in the center of the bridge with one arm pointing toward the blue mountain. - Maintain the background. - View: Close-up.这条提示词展示了多个值得注意的现象:新加的山"既不同又一致";桥以物理上可信的方式连接两座山巅;而Remove the ice picks与前面的no longer holding the map同理——不给模型留出随机决策的空间。作者也坦诚指出局限性:想生成角色"从左向右走"的侧面行走图很难,把左右视图加进角色卡可以解决。
最后是"描述式(descriptive)"提示词的示范——吊床场景:
- The robot is sleeping peacefully in a comfortable brown-and-tan tartan hammock that has replaced the bridge. - Both of the robot's eyes are closed, in a "sleeping" state.桥→吊床的转变既保留了山巅的悬挂点,又让从未出现过的"闭眼侧卧"姿态保持角色一致。至此,作者用 9 张新的一致图像讲完了机器人从山到谷、穿林登山、最后安睡吊床的完整旅程。
生成过程可视化:networkx 有向图与 matplotlib 资产图
所有新资产通过"由…生成(generated from)"关系相连,从数据结构看就是一张有向图。用networkx构建:
def build_graph(assets): graph = nx.DiGraph(assets=assets) for asset in assets.values(): graph.add_node(asset.id, asset=asset) for asset in assets.values(): for source_id in asset.source_ids: graph.add_edge(source_id, asset.id) # 边 = "由 source 生成" return graph布局策略是"把连接最多的节点放中间,其余节点环绕排列":
def compute_node_positions(graph): center_node = most_connected_node(graph) # max(graph.nodes, key=graph.degree) edge_nodes = set(graph) - {center_node} pos = nx.circular_layout(graph.subgraph(edge_nodes)) pos[center_node] = np.array([0.0, 0.0]) return pos进阶的"资产图"则用matplotlib把每个节点渲染成真实的资产缩略图,并做视觉分级:
- 绿色(
#34A853)表示档案来源(无提示词),蓝色(#4285F4)表示新生成的资产(有提示词); - 边用点线样式绘制,中心节点相关边为直边,其余为
rad=0.15的曲线; - 动画版(GIF)按生成顺序逐节点推进,先展示该节点的提示词,再替换为生成的图像;GIF 用 MEDIANCUT 量化统一调色板,首帧停留 3000ms、后续每帧 1000ms 循环播放。
这套可视化既是对"生成步骤的准确总结",也天然是向团队/客户汇报生成管线的好素材。
资产自足化:把提示词与祖先关系写进 PNG 元数据
"你有没有生成过一张好图,却忘了存下当时的精确上下文?"Notebook 的答案是:把资产做成自足(self-sufficient)的——利用 PNG 的元数据块(chunk)直接保存source_ids和prompt,无需数据库,也不怕丢提示词:
def save_asset(asset, folder): image_path = folder / f"{asset.id}.png" metadata = PngInfo() metadata.add_text("source_ids", "\n".join(asset.source_ids)) metadata.add_text("prompt", asset.prompt) asset.pil_image.save(image_path, pnginfo=metadata) def load_asset(image_path): asset_id = image_path.stem with PIL.Image.open(image_path) as img: img.load() image_info = img.info source_ids = image_info.get("source_ids", "").split("\n") if image_info.get("source_ids") else [] prompt = image_info.get("prompt", "") image = img.copy() return Asset(asset_id, source_ids, prompt, image)配套的save_assets会把全部资产存入按时间戳命名的文件夹(如2026-09-13_06-48-49/),load_assets则遍历该文件夹重建完整的Assets,之后可以立刻build_graph重新可视化。加载后即获得"图像 + 提示词 + 血缘关系"三位一体的资产,为自动化管线铺平了道路。
总结与自动化延伸
Notebook 结尾总结了这次挑战的收获,同时也是这套方法的核心价值主张:
- 一张图胜过千言万语:从已有图像生成新图变得前所未有的容易;
- 纯靠构图创作/编辑图像:人人都能当"艺术指导";
- 描述式与祈使式提示词都有效:前者适合自由发挥,后者适合精确控制;
- 空间理解带来 3D 级操作:多视角生成、姿态与道具的增删改;
- 输入输出都能包含文字:角色卡里写文字、按"FRONT/BACK VIEW"标签理解输入;
- 一致性可以多层级保持:角色、场景、纹理、光照、机位/镜头语言;
- 迭代速度大幅提升:仍可迭代,但获得超预期结果的感觉快了 10~100 倍。
从工程角度看,这套流程本质上是一条生成管线,可延伸的方向包括:
- 自动化:改一个节点即可级联重新生成其后代节点;
- 并行变体:同一组图像可以为不同美学风格、受众或模拟场景批量生成多个版本;
- 提示词工程化:为清晰起见文中提示词保持简单,生产环境可做成带标准化参数集的固定模板;
- 风格自由:文中的场景设定是"摄影棚拍摄",实际上任何艺术风格(写实、抽象、2D……)都可行。
延伸阅读:Nano Banana Recipes 笔记本的 12 个实用配方
同属本模块的 Nano Banana Recipes Notebook(模块首页)用另一组模型gemini-2.5-flash-image-preview(Gemini 2.5 Flash Image,即第一代 Nano Banana)整理了 12 个开箱即用的图像生成/编辑配方,可作为一致图像生成的互补练习:
| 配方 | 核心能力 |
|---|---|
| Recipe 1 | 纯文本提示词从零生成图像 |
| Recipe 2 | 用空白画布(blank canvas)控制宽高比 |
| Recipe 3 | 图像外扩(outpainting),智能延伸画布边界 |
| Recipe 4 | 指令式图像编辑(加物件、换背景) |
| Recipe 5 | 风格迁移(如转换为梵高风格油画) |
| Recipe 6 | 老照片修复与着色 |
| Recipe 7 | 多张参考图融合成一个连贯场景 |
| Recipe 8 | 虚拟试穿(模特图 + 服装图) |
| Recipe 9 | 产品场景重置(电商/广告) |
| Recipe 10 | 图像内嵌文字(如菜单、海报) |
| Recipe 11 | 角色一致性(同角色多场景) |
| Recipe 12 | 相机视角迁移(如切换到俯拍机位) |
该 Notebook 的核心配置同样值得对照学习:
MODEL_NAME = "gemini-2.5-flash-image-preview" GENERATION_CONFIG = types.GenerateContentConfig( temperature=1, top_p=0.95, max_output_tokens=32768, response_modalities=["TEXT", "IMAGE"], )其create_blank_canvas用 PIL 在内存中生成指定宽高比的空白画布作为Part传入请求(1:1→1024×1024、16:9→1280×720、9:16→720×1280 等),既控制输出画幅,又给模型提供"构图底版",是本仓库中"画布控制"技巧的典型实现。
如果你想深入 Nano Banana 2 Lite 的更多能力(如视频生成图像、多参考图一致性边界、C2PA/SynthID 内容凭证),可以继续阅读 Gemini 3.1 Flash Lite Image 入门教程。上述所有 Notebook 均可直接在 Colab、Colab Enterprise 或 Workbench 中运行,只需按文中方式配置 Agent Platform 或 Google AI Studio 凭据即可。
【免费下载链接】generative-aiSample code and notebooks for Generative AI on Google Cloud, with Gemini Enterprise Agent Platform项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考