本节摘要:本节建素材段。先定位:素材层坐在分镜与生成之间,供给三类东西——首帧图(图生视频的画面锚)、参考图(风格与主体的样板)、补充素材(剪辑段用的空镜与贴图);来路也有三条——文生图生成、免费素材源采集、存量素材复用。然后重点讲文生图:它是首帧的主要来源,经济学是「图便宜视频贵」——在挑图阶段反复挑选,视频段只花一次钱;风格统一靠固定风格前缀,提示词直接复用分镜的 visual 字段加设定卡(第 3.2 节),不另起炉灶。免费素材源的部分强调合规:授权逐源核实、许可证随文件落盘。最后是素材库的管理:每张图带 sidecar 元数据(来源、提示词、种子、许可证、用途),内容哈希做精确去重,感知哈希抓近重。批量采集公开素材还有一条浏览器自动化路线,与《浏览器智能体实战》一书互为参照。
分镜 JSON ──▶ ┌──────────────────────────────┐ ──▶ 生成任务清单(首帧就位) │ 素材段 │ │ 来路:文生图 │ 免费素材源 │ 存量 │ ──▶ 剪辑段的补充画面 │ 产出:首帧图 │ 参考图 │ 空镜贴图 │ └──────────────────────────────┘ │ ▼ build/03_assets/(文件 + sidecar 元数据成对落盘)
三条来路的分工:文生图管「画面锚」(首帧、定妆参考图),免费素材源管「真实感空镜」(天空、街景、质感贴图),存量素材管「品牌资产」(logo、包装、旧项目可复用镜头)。判断一条素材走哪条来路,看两个问题:需要与主角严格一致吗(需要就走生成加设定卡)、需要真实世界质感吗(需要就采集,生成的「真实感」仍有塑料味)。
首帧组的提示词公式承接第 3.2 节,不发明新写法:visual 字段 + 风格前缀 + 设定卡。风格前缀是全片统一的一句话(从 project.json 的 style 来),设定卡是主角或场景的固定描述块:
# first_frame_prompt.py —— 首帧提示词的组装(复用分镜字段,不另起炉灶) def build_image_prompt(shot, style, character_sheet): parts = [style, character_sheet, shot["visual"]] return ",".join(p for p in parts if p) # 示例(风格前缀与设定卡全片共用): STYLE = "温暖手作感,暖色调,胶片颗粒" SHEET = "老修表匠,七十岁,灰白短发,深棕色围裙,戴单边放大镜" # build_image_prompt(镜头101, STYLE, SHEET) # → 温暖手作感,暖色调,胶片颗粒,老修表匠,七十岁,灰白短发,深棕色围裙, # 戴单边放大镜,钟表铺内景,台灯暖光下,老人双手捧着怀表端详
挑图经济学:一张 1080p 图的生成成本约为一段视频的几十分之一(示意口径),所以策略是图海挑图、视频一次——每个镜头出四到八张候选,人花十秒挑一张,挑中的才作为 i2v 任务的首帧;不满意就改提示词重出图,浪费的是零头。首帧定稿后,镜头的构图、主体、色调全部落定,视频生成的确定性直接继承第 3.2 节的首帧锚。
免费不等于随便用。三类常见源与注意点(授权条款随时会改,以各站点当期条款为准):
| 源类型 | 代表(纯文字列举) | 常见授权 | 注意 |
|---|---|---|---|
| 综合图库 | Unsplash、Pexels、Pixabay | 多为宽松商用、免署名 | 站内搜出的赞助内容另算;人物图有肖像议题 |
| 音效音乐库 | 各免费音乐库与 cc 授权平台 | CC0 或 CC BY 居多 | CC BY 必须署名;音乐授权比图片复杂,逐曲核实 |
| 字体 | 各开源字体项目 | OFL 等 | 「个人免费商用收费」的坑最多,逐字体重核 |
三条合规动作:下载时落许可证——把授权页截图或条款文本存进 sidecar,两周后你将无法回忆当时条款长什么样;记录来源与日期——同一素材在不同时期的授权可能变化,你唯一能主张的是「下载当日它是这个授权」;不碰明令禁止的用途——不少免署名授权明确排除敏感话题用途,用在视频里前扫一眼排除条款。批量采集公开素材可以上浏览器自动化:用《浏览器智能体实战》一书的方法写采集智能体,video-use(browser-use 生态的视频方向项目,约 29k stars,社区口径)是同生态的参照——但自动化的合规边界不变:遵守目标站点服务条款、控制速率、只采授权允许的内容。
素材一多,两个问题必然出现:「这张图哪来的」与「这俩是不是同一张」。方案是 sidecar 元数据加双哈希去重。sidecar 是与图片同名不同扩展名的 JSON,许可证随文件走:
# asset_meta.py —— sidecar 元数据结构(shot_101.first.json 的内容) meta = { "file": "shot_101.first.png", "source": "text2image", "prompt": "温暖手作感,暖色调,胶片颗粒,钟表铺内景……", "seed": 101, "license": "generated", "license_evidence": "生成记录见 build 日志", "created": "2026-10-16", "usage": ["first_frame"], }
# asset_dedup.py —— 内容哈希精确去重加感知哈希近重检测(标准库加 Pillow) import hashlib from pathlib import Path from PIL import Image def content_hash(path): return hashlib.sha256(Path(path).read_bytes()).hexdigest()[:16] def simple_phash(path, size=8): img = Image.open(path).convert("L").resize((size, size)) pixels = list(img.getdata()) avg = sum(pixels) / len(pixels) bits = "".join("1" if p > avg else "0" for p in pixels) return int(bits, 2) def hamming(a, b): return bin(a ^ b).count("1") def scan(asset_dir): entries = [] for path in sorted(Path(asset_dir).glob("*.png")): entries.append({"name": path.name, "chash": content_hash(path), "phash": simple_phash(path)}) exact, near = [], [] for i, a in enumerate(entries): for b in entries[i + 1:]: if a["chash"] == b["chash"]: exact.append((a["name"], b["name"])) elif hamming(a["phash"], b["phash"]) <= 8: near.append((a["name"], b["name"])) return exact, near
两个哈希分工:内容哈希抓「完全同一文件」(多次下载、多个项目重复入库),感知哈希抓「几乎同一画面」(同图不同压缩、微调色)——后者才是素材库的真实病灶,人眼扫库永远扫不出来。近重不自动删,报告出来人定夺:同一空镜用了两个镜头,观众是能看出来的。
库建起来了,边界也要画清楚——下一节把素材、音乐、字体的授权类型与发布前合规清单一次说透。