如果给一个叫“安东尼”的人一套本地 AI 生成环境,他会怎么用算法造出一批“随机假卡”?这篇文章就来拆这个事。这里的“假卡”不是拿来伪造球星卡、交易卡或任何实体卡牌,而是用算法批量生成卡牌样图,跑一个可以复制的“随机造卡流水线”。标题里的“储君篇”可以理解为这个系列里偏模板化、偏批量化的一个篇章——你不需要懂太多美术,只需要把提示词、随机种子、固定模板和接口服务串起来,就能得到一整组风格统一、元素随机的卡面图。
先把结论放前面:这个流程的核心是四个模块——随机提示词组合、统一卡面模板、批量 API 生成、自动排版导出。只要能跑通 Stable Diffusion WebUI 或 ComfyUI 的本地 API 服务,再用一段 Python 脚本控制随机种子和参数,剩下的就是批量出图和整理目录的事。下面会完整演示环境准备、启动方式、接口调用、批量任务和常见坑。想直接抄作业的,可以重点看第 4 节到第 6 节。
1. 随机假卡生成流水线:核心能力速览
| 能力项 | 说明 |
|---|---|
| 项目类型 | 本地 AI 图像批量生成 + 卡面排版自动化 |
| 技术核心 | Stable Diffusion 系列模型、随机种子控制、提示词模板组合、Pillow 图文排版 |
| 主要功能 | 随机生成卡牌底图、统一卡牌版式、批量导出 PNG、支持接口调用 |
| 硬件门槛 | 有 NVIDIA 显卡的 Windows / Linux 机器最合适;具体显存需求需按模型版本测试,没有显卡也可以用纯 CPU 跑但速度会明显偏慢 |
| 显存占用 | 取决于模型、分辨率、批大小;本文不写死具体数字,第 7 节会给观察方法 |
| 支持平台 | Windows / Linux / macOS(macOS 依赖实际情况,N 卡兼容性更好) |
| 启动方式 | 命令行启动 WebUI 或 ComfyUI API 服务,再用本地脚本提交任务 |
| 是否支持 API | 支持,可调用本地 HTTP 接口批量提交生成任务 |
| 是否支持批量任务 | 支持,建议把提示词、种子、输出路径全部写在 JSON 配置里,按队列循环生成 |
| 适合场景 | 个人收藏卡样图、虚拟实体卡设计预研、桌游角色卡原型、自动化素材生产 |
| 不适合场景 | 伪造真实球星卡 / 交易卡、未授权使用真实球员或真人肖像、任何以假乱真的商业行为 |
这套流水线本质上不复杂,一句话概括:用“随机提示词 + 随机种子”控制 AI 画面的多样性,再用“固定模板 + 自动排版”控制成品的一致性。
2. 适用场景与使用边界
先讲适合谁。如果你手头有几千张统一的卡面需求,比如桌游卡、虚拟收藏卡、训练用样本卡,人工一张张用在线工具生成会疯掉的。适合本地算法批量生成。如果你需要“看起来是同系列但每张都不同”的效果,这套随机组合机制正好对路。抛开娱乐语境,它也是一个很好的 AI 批处理工程演示:本地 API、JSON 配置、批量循环、失败日志、结果去重,这些组合起来就是一个小型生成管线。
再讲不适合什么。不适合用来做真实球星卡的“假卡”。真实球星卡涉及肖像权、商标、球队标识、联盟授权,AI 生成图不能解决版权问题。哪怕只是自己收藏,只要涉及真实球员姓名和照片,也会踩肖像权边界。第二个不适合的场景是拿它去伪造稀有卡、欺骗其他收藏者,这不仅仅是合规问题,还可能涉及法律风险。还有一类不适合:如果只是想快速得到一张效果惊艳的封面图,不需要批量,那没必要套这套流水线,直接开 WebUI 手写提示词更快。
安全边界必须划清楚:
- 生成卡面素材时,优先使用无版权人物、虚拟形象、自绘素材或已获授权的素材库。
- 不要用真实公众人物姓名生成可被误解为官方卡牌的内容。
- 不要把 AI 生成卡片挂到二手平台或交易渠道冒充实体卡。
- 涉及批量生成的素材,建议在输出图片右下角加“AI Demo / Not Official”水印,便于和真实卡区分。
3. 随机造卡本地部署:环境准备与前置条件
下面给一套通用检查清单。具体版本以你安装模型的说明为准,不要把下面写法直接当成唯一答案。
3.1 操作系统与硬件
- 操作系统:Windows 10/11、Ubuntu 20.04/22.04 都可以。
- GPU:NVIDIA 显卡优先,显存越大越稳。没有材料的支持结论,建议至少从 6GB 显存开始测,实际能不能跑取决于模型选择和参数。
- CPU 模式:可以跑,但出图速度会慢很多,适合功能验证,不适合批量。
- 磁盘空间:至少要预留 30GB 以上。Stable Diffusion 模型文件本身就有几个 GB,再加上出图结果、Python 依赖和日志,空间很快会被吃掉。
3.2 基础软件
需要安装:
- Python 3.10 / 3.11。
- Git。
- NVIDIA 显卡驱动 + CUDA 环境。具体版本看 PyTorch 要求。
- Stable Diffusion WebUI 或 ComfyUI。二者都能提供 HTTP API,二选一即可。
- Pillow、requests 等 Python 库,用于排版和接口调用。
3.3 前置检查命令
python --version git --version nvidia-sminvidia-smi能显示驱动版本和显存总量。如果命令找不到,说明驱动没装好,先去装驱动。PyTorch 是否能用 GPU,可以用下面命令快速验证:
python -c "import torch; print(torch.cuda.is_available())"输出True代表 GPU 可用,输出False就说明 CUDA 版本或 PyTorch 安装有问题。这个检查点解决了,后面启动 WebUI 才不容易卡在设备识别环节。
4. 一键启动与本地 API 服务
这里以 Stable Diffusion WebUI 为例,因为它的 HTTP API 最直白。ComfyUI 的流程类似,只是 API 格式不同,会在第 6 节给出对应说明。
4.1 克隆并安装 WebUI
git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git cd stable-diffusion-webuiWindows 下一般直接运行webui-user.bat,Linux 下运行:
bash webui.sh第一次启动会下载依赖并加载模型,时间比较长。模型文件需要放在models/Stable-diffusion/目录下,文件名随意,WebUI 会按模型名识别。
4.2 以 API 模式启动
WebUI 默认启动会同时打开 Web 页面和 API 服务。为了让批量任务更稳定,建议手动指定监听地址和端口:
# Linux 示例,实际启动脚本路径以你的安装目录为准 cd stable-diffusion-webui python launch.py --api --listen 127.0.0.1 --port 7860Windows 可以在webui-user.bat里加环境变量:
set COMMANDLINE_ARGS=--api --listen 127.0.0.1 --port 7860启动成功后,终端会显示本地访问地址。如果只在本机调用,建议--listen 127.0.0.1,不要直接暴露到公网。
4.3 验证服务是否可用
浏览器打开http://127.0.0.1:7860/sdapi/v1/txt2img,如果返回 405 或 404 属正常现象,因为该接口只接受 POST。更好的验证方式是看根路径能否打开:
curl -s http://127.0.0.1:7860/ | head -20也可以直接请求http://127.0.0.1:7860/sdapi/v1/options获取当前配置。能返回 JSON,说明服务已经正常起来了。
5. 功能测试与效果验证
造卡流水线建议按四步测试:单张随机卡、提示词组合、批量生成、自动排版。
5.1 随机种子单卡测试
测试目的:确认本地服务能出图,并且随机种子确实能改变画面。
先用 WebUI 页面手动填一个提示词,比如:
card game illustration, fantasy character portrait, glowing runes, strong contrast, high detail负面提示词填:
lowres, bad anatomy, watermark, text, blurry, jpeg artifacts把Seed设为-1代表每次随机,点击生成。如果页面能出图,说明基础链路没问题。
接着测试种子稳定性:把同一提示词分别用 Seed 1、Seed 2、Seed 3 各生成一张,对比卡面元素差异。这一步决定了后面批量生成好不好用。如果种子变化不明显,检查是不是“高清修复”或“变体”功能干扰了随机性。
5.2 提示词组合测试
随机假卡的重点是“随机”,但随机不能变成全乱。建议使用角色 + 背景 + 风格 + 稀有度四段式模板:
| 模板位置 | 可替换词 |
|---|---|
| 角色 | 战士 / 法师 / 游侠 / 龙裔 / 机械守卫 |
| 背景 | 地牢 / 雪原 / 浮空岛 / 遗迹 / 星港 |
| 风格 | 油画风 / 日系平涂 / 赛博朋克 / 水墨风 |
| 稀有度 | 普通铜框卡 / 稀有银框卡 / 史诗金框卡 |
用 Python 按随机权重组合提示词,再提交给 API。注意风格词不要混太多,否则容易串风格。建议每张卡只保留一种主风格词。
5.3 批量生成测试
写一个 Python 脚本循环请求/sdapi/v1/txt2img,每张图使用独立随机种子,并把参数记录到 JSON,方便追踪。
import requests import random import base64 import io from PIL import Image import os api_url = "http://127.0.0.1:7860/sdapi/v1/txt2img" characters = ["warrior", "mage", "ranger", "dragonkin"] backgrounds = ["dungeon", "snowfield", "floating island", "ruins"] styles = ["oil painting style", "japanese anime style", "cyberpunk style", "ink painting style"] rarities = ["common", "rare", "epic"] output_dir = "./generated_cards" os.makedirs(output_dir, exist_ok=True) for i in range(20): char = random.choice(characters) bg = random.choice(backgrounds) style = random.choice(styles) rarity = random.choice(rarities) prompt = f"{char}, {bg}, {style}, card game illustration, high detail" seed = random.randint(1, 999999999) payload = { "prompt": prompt, "negative_prompt": "lowres, bad anatomy, watermark, text, blurry, jpeg artifacts", "seed": seed, "steps": 30, "width": 768, "height": 1024, "cfg_scale": 7, "sampler_name": "DPM++ 2M Karras", "batch_size": 1 } resp = requests.post(api_url, json=payload, timeout=300) data = resp.json() if "images" in data: img_data = base64.b64decode(data["images"][0]) img = Image.open(io.BytesIO(img_data)) # 保存底图,命名规则:序号_稀有度_角色.png file_name = f"{i+1:03d}_{rarity}_{char}.png" img.save(os.path.join(output_dir, file_name)) print(f"[OK] {file_name} seed={seed}") else: print(f"[FAIL] {i+1} error: {data}")脚本跑完后,检查generated_cards目录。判断成功的标准:20 张图全部能保存,图片尺寸正确,人眼可见的风格差异明显,没有大面积黑图或纯色图。
失败时优先排查三类问题:
- 请求超时:
timeout=300不够就再加,或者把steps调低。 - 返回 500:看 WebUI 终端日志,通常是显存不足或提示词包含不支持的 token。
- 输出全是同一个风格:检查随机种子是否真的传入,有时候请求里 seed 写死会导致所有图一样。
5.4 自动排版输出
底图生成后,还需要把卡牌文字信息压到图上。这里用 Pillow 做一层简单排版。先准备文本字段:稀有度、卡名、序号、编号。
from PIL import Image, ImageDraw, ImageFont import os card_dir = "./generated_cards" output_dir = "./cards_with_text" os.makedirs(output_dir, exist_ok=True) try: font_large = ImageFont.truetype("arial.ttf", 56) font_small = ImageFont.truetype("arial.ttf", 36) except IOError: font_large = ImageFont.load_default() font_small = ImageFont.load_default() for file_name in os.listdir(card_dir): if not file_name.endswith(".png"): continue parts = file_name.replace(".png", "").split("_") # 文件命名示例:001_epic_warrior.png uid = parts[0] rarity = parts[1] name = parts[2] img = Image.open(os.path.join(card_dir, file_name)).convert("RGB") draw = ImageDraw.Draw(img) # 底部压一条半透明黑带,提高文字可读性 overlay = Image.new("RGBA", img.size, (0, 0, 0, 0)) od = ImageDraw.Draw(overlay) od.rectangle([0, img.height - 160, img.width, img.height], fill=(0, 0, 0, 160)) img = img.convert("RGBA") img = Image.alpha_composite(img, overlay).convert("RGB") draw = ImageDraw.Draw(img) draw.text((60, img.height - 150), f"{rarity.upper()} - {name.title()}", fill=(255, 255, 255), font=font_large) draw.text((60, img.height - 80), f"NO.{uid}", fill=(200, 200, 200), font=font_small) img.save(os.path.join(output_dir, file_name)) print(f"[SAVE] {output_dir}/{file_name}")这段脚本会在卡片底部生成半透明信息栏。如果文字溢出,把字号调小或加长底部色带高度。排版完成后的图,可以直接用于预览、归档或文档展示,但不能直接视为“可流通实体卡设计成品”,因为还差版权审核和印刷标准。
6. 接口 API 与批量任务设计
6.1 WebUI API 请求格式
WebUI 的/sdapi/v1/txt2img是最常用的接口。返回 JSON 里images是 base64 编码的图片列表。需要注意,batch_size和n_iter同时控制输出数量:
batch_size:每次生成几张图。n_iter:循环几轮。
如果你的显存不充裕,建议保持batch_size=1,通过外部 Python 循环控制数量。否则显存峰值容易突然拉高。
6.2 批量任务队列设计
批量任务不能光写个for循环。更稳妥的结构是:先用 JSON 配置任务清单,再写执行器读取配置并逐条处理。
{ "base_dir": "./generated_cards", "output_dir": "./cards_with_text", "tasks": [ { "id": "001", "rarity": "epic", "character": "warrior", "background": "dungeon", "style": "oil painting style", "seed": 123456 }, { "id": "002", "rarity": "rare", "character": "mage", "background": "floating island", "style": "japanese anime style", "seed": 654321 } ] }执行器读取tasks列表,把每个任务拼成提示词,提交 API,保存图片,并把状态写入日志。这样如果跑到第 15 张失败,重启脚本后可以跳过已完成任务,不用从头再来。
6.3 失败重试与状态记录
批量任务里最常见的坑是:某一张图超时,整个队列中断。建议给每次请求加 5 分钟超时,并对失败任务做 3 次重试:
for attempt in range(3): try: resp = requests.post(api_url, json=payload, timeout=300) if resp.status_code == 200: break except requests.exceptions.Timeout: print(f"task {task_id} timeout, retry {attempt + 1}")每次生成完成后,把task_id、seed、prompt、输出文件名、耗时写到logs.csv。遇到效果不好的图,至少能知道是哪一组随机参数导致的。
6.4 ComfyUI API 说明
ComfyUI 也可以做批量生成,但它的 API 格式和 WebUI 不一样。ComfyUI 的 API 是一整个workflowJSON,里面定义了节点连接关系,调用方式通常是:
import json import urllib.request workflow_path = "workflow_api.json" with open(workflow_path, "r", encoding="utf-8") as f: workflow = json.load(f) # 这里需要根据当前节点 id 修改 prompt 和 seed # 具体字段名以 ComfyUI 导出的 workflow 为准 data = json.dumps({"prompt": workflow}).encode("utf-8") req = urllib.request.Request("http://127.0.0.1:8188/prompt", data=data, headers={"Content-Type": "application/json"}) resp = urllib.request.urlopen(req, timeout=300) print(resp.read().decode("utf-8"))所以如果你是要做“可复制造卡流水线”,我建议优先用 WebUI 的/sdapi/v1/txt2img,因为参数更扁平、更容易做批量循环。ComfyUI 胜在节点灵活,但要把工作流导出成 API 格式,上手成本高一些。
7. 资源占用与性能观察方法
这节不写死任何具体显存数字,因为不同模型、不同分辨率、不同采样步数差异太大了。下面讲怎么观察和调优。
7.1 显存占用怎么观察
生成图片时,另开一个终端,用nvidia-smi查看进程显存:
nvidia-smi -l 1-l 1表示每秒刷新一次。重点看/stable-diffusion-webui 或 python进程对应显存占用。启动 WebUI 后显存就占一部分,生成时会再加一层峰值。观察时不要只看瞬时数字,要盯住生成过程中的最高值。
7.2 哪些参数影响最大
从常见实践看,影响排列大致是:
- 分辨率:1024x1024 比 768x1024 更吃显存,等比调大会明显拉高峰值。
- 采样步数:步数越高耗时越长,显存增量小于分辨率影响,但会拖慢批量速度。
- 批量大小:
batch_size从 1 调到 2,显存几乎接近翻倍,风险很高。 - 模型版本:SD 1.5、SDXL、Pony、Illustrious 等不同模型,底层结构和文本编码器不同,显存占用差异很大。
- 高清修复:
hires fix会先把低分辨率图生成,再放大,放大阶段显存占用会二次升高。
7.3 如何降低显存占用
- 保持
batch_size=1,用循环代替并行。 - 分辨率从 640x832 起步,不要一上来就跑 1024。
- 开启 WebUI 的
medvram或lowvram启动参数,会限制显存策略。 - 关掉多余插件,部分预览类插件也会吃显存。
- 如果显存不足导致黑图,优先降低分辨率,而不是降步数。
7.4 CPU 推理是什么体验
没有独显时,SD 出图只能靠 CPU 硬算,单张 768x1024 图可能耗时几十秒到几分钟。功能验证可以,批量任务不建议。如果你必须用 CPU,把steps调到 18 到 20,分辨率降到 512x768,先确认输出质量,再考虑数量。
7.5 端口和进程管理
WebUI 默认端口是 7860,ComfyUI 默认是 8188。如果端口被占,启动会提示 address already in use。处理方式:
# 查看端口占用 netstat -ano | grep 7860 # Linux 杀进程 kill -9 <PID>Windows 用资源管理器或:
netstat -ano | findstr 7860 taskkill /PID <PID> /F批量任务跑完后,服务进程不会自动退出,需要手动关。长时间挂机生成时建议设置输出目录按日期分目录,避免文件散落。
8. 随机假卡生成常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 启动后页面打不开 | 服务未完全启动、端口被占用或防火墙拦截 | 查看启动日志、检查端口 | 换端口重启,或关闭防火墙限制 |
| 生成的黑图或纯色图 | 显存不足、提示词冲突、步数太低 | 查看终端报错、降低分辨率 | 降低分辨率或步数,关掉高清修复 |
| 所有卡片画面高度相似 | 随机种子没有生效、提示词模板过于单一 | 检查请求参数里的 seed 字段 | 每次调用显式传随机种子,扩宽词库 |
| 批量生成中途卡住 | 某次请求超时或接口无响应 | 看日志停在哪个任务 | 增加 timeout,添加失败重试和断点续跑 |
| 生成的图片有乱码文字 | 模型直接画了文字但效果不可控 | 检查负面提示词已有 text | 优先后期排版加文字,不要依赖 AI 出字 |
| 调用 API 返回 500 | 模型加载失败、参数字段写错 | 看 WebUI 终端堆栈 | 核对请求字段名,确认模型文件已放到目录 |
| 显存不足导致崩溃 | 单图分辨率过高或 batch_size 过大 | 观察 nvidia-smi 峰值 | 调低分辨率,batch_size 保持 1 |
| 出图风格混搭 | 风格词叠加太多 | 检查提示词模板 | 每张卡只保留一个主风格词 |
| 本地 API 被外部访问 | 启动时用了--listen 0.0.0.0且无访问限制 | 检查监听地址 | 改回127.0.0.1,或加访问密钥 |
| 输出的卡面缺少真实卡质感 | 缺少边框、底纹、文字排版 | 看底图与成品卡差别 | 用 Pillow 补框线、稀有度背板、编号条 |
排查的基本原则很简单:先看终端日志,再看请求参数,最后看显存和磁盘。如果是批量任务,不要一次性跑 100 张,先跑 5 张确认参数稳定,再扩量。
9. 最佳实践与使用建议
把这套流水线当工程来做,而不是当“抽卡娱乐”来做,有几个建议很实用。
第一,第一次只跑小参数。比如先用steps=20、width=768、height=1024、batch_size=1跑 5 张,确认没有黑图和显存崩溃,再慢慢加数量和分辨率。不要一上来就 50 张,不然中途炸了很难定位问题。
第二,把输入词库、配置文件和输出目录分开。词库存成 Python 列表,配置文件存成 JSON,输出目录按日期或任务号命名。这样每次生成的参数、种子、prompt 都能追踪。用一段logs.csv记录每次成功图片的种子和提示词,比到时候翻截图靠谱得多。
第三,加“去重”意识。随机种子虽然能保证画面不同,但相近提示词 + 相近种子可能会出非常相似的图。批量生成后,可以按文件大小和图片哈希粗筛一遍:
# Linux/macOS 下按 md5 找重复图 find ./generated_cards -name "*.png" -exec md5sum {} \; | sort | uniq -w32 -dWindows 可以用 Python 计算哈希。重复图要么删掉,要么把提示词模板里的角色词、背景词再多扩一倍。
第四,生成结束后要做人工抽查。算法不会判断“这张卡面侵权”或“这个文字排版歪了”。如果你要对外展示,需要有人眼审核环节。批量任务跑完不等于成品可用。
第五,接口服务注意访问边界。本地 API 不要轻易绑定0.0.0.0。如果真要同一局域网内调试,也要清楚别人访问你的 7860 端口就能直接生成图片,风险自负。最稳妥的是只用127.0.0.1,同一脚本在服务器本机跑。
第六,涉及人物、品牌、队徽、真实名称时,先确认授权。你要生成的是“随机假卡”,就不要用真人真名。建议在系统提示词里要求产出虚拟角色名,比如用“mage”代替“某个明星球员”。
第七,发布或商用前做效果复核。AI 生成卡面往往会出现手指、文字拼写、边缘瑕疵。缩略图看着还行,放大看可能完全不能看。如果用于正式产品,建议先做超分和二次修图,必要时人工润色。
10. 总结与下一步
回到“假如安东尼使用算法生成随机假卡”这个场景。用这套流程,你只需要有一台能跑 Stable Diffusion 的机器,装好 WebUI,把提示词模板、随机种子、批量脚本、排版脚本串起来,就能批量得到一批风格统一但内容随机的卡面图。最值得试的是随机种子 + 四段式提示词组合的玩法,它性价比最高,改动小,出图差异明显。
最容易踩的坑有三个:一是没有先跑小批量就开大流程,导致显存或超时问题把整个队列打断;二是随机种子没有真正传进去,结果 50 张图全是一个模子;三是忘了做合规边界检查,把包含真实人物姓名或受版权保护标识的内容放进批量任务。先跑通 5 张,再扩展词库,再加大批量,是性价比最高的路径。
后续可以继续扩展的方向包括:把 HTML 文本模板改成 SVG 排版,做更精细的卡牌 UI;接入微信机器人或 Web 服务,让用户输入关键词就随机发卡;加入人脸一致性方案生成系列角色卡;甚至把输出结果接入自动化存档系统,按稀有度自动归档。每一个方向都可以单独再写一篇,核心底座就是本文这条生成 + 排版 + 批量的流水线。