跳到主内容
快讯直播
AI智模界
教程

Qwen-Image-2.1:文生图与指令改图全流程

适用场景

需要一次性解决"出图"和"改图"两类需求的人:先用文生图批量产出素材,再对其中某几张做局部替换、换背景、改风格。Qwen-Image-2.1 把生成与编辑放在同一套调用方式和相近的提示词逻辑里,适合把"生图 → 改图 → 统一风格"串成一条流水线。如果你受够了在三个工具之间来回导图、每次改完风格就跑偏,这套流程值得试。

环境与前置条件

操作系统:Linux(Ubuntu 22.04 一类)、macOS、Windows + WSL2 均可。只走云端 API 的话,系统几乎无所谓,能跑 Python 就行。

运行时:Python 3.9 及以上,建议用虚拟环境隔离依赖。需要 pip 能正常联网拉包。

账号与密钥:在所选平台开通图像生成服务并创建 API Key。模型 ID、调用地址、支持的图片尺寸与并发上限,请以官方文档当前版本为准,不同平台可能略有差异,本文把这几项都放在环境变量里,方便随时替换。

云端 API 路线:磁盘预留几 GB 放素材和产物即可,无显卡要求。

本地部署路线(可选):权重体积通常在几十 GB 量级,建议磁盘预留 60–100 GB;显存 24 GB 及以上体验较顺,显存紧张时用 CPU offload、量化或降低分辨率救急,具体门槛以官方文档当前版本为准。

分步骤部署

下面按"先跑通云端 API,再按需转本地"的顺序推进。云端路线足够覆盖文生图、局部重绘和风格统一。

步骤 1:建目录与虚拟环境

```bash

mkdir -p ~/qwen-image-demo/{in,out,masks}

cd ~/qwen-image-demo

python3 -m venv .venv

source .venv/bin/activate

pip install -U pip

pip install -U openai python-dotenv requests pillow

```

这步在做什么:把项目目录、素材目录(in)、产物目录(out)、掩码目录(masks)先分好,后面脚本按固定路径读写,不容易乱。看到 Successfully installed ... 一堆包名即为成功。

步骤 2:配置密钥与模型 ID

在项目根目录新建 .env

```ini

IMAGE_API_KEY=你的密钥

IMAGE_API_BASE=服务商提供的接口地址

IMAGE_MODEL=控制台里显示的模型 ID

```

.env 不要提交到 Git,把它写进 .gitignore

```bash

echo ".env" >> .gitignore

echo ".venv/" >> .gitignore

```

验证变量能被读到:

```bash

python -c "import os; from dotenv import load_dotenv; load_dotenv(); print(bool(os.environ.get('IMAGE_API_KEY')), os.environ.get('IMAGE_MODEL'))"

```

输出 True 你的模型ID 就对了。

步骤 3:先跑通最小文生图

新建 imgutil.py,把"拿到结果并存盘"这段公共逻辑抽出来,两条路线都会用到:

```python

imgutil.py

import base64, pathlib, requests

def save_result(item, path):

"""兼容两种返回:base64 内联数据 / 临时 URL。"""

path = pathlib.Path(path)

path.parent.mkdir(parents=True, exist_ok=True)

if getattr(item, "b64_json", None):

path.write_bytes(base64.b64decode(item.b64_json))

elif getattr(item, "url", None):

r = requests.get(item.url, timeout=120)

r.raise_for_status()

path.write_bytes(r.content)

else:

raise RuntimeError(f"无法识别的返回结构: {item}")

return path

```

再写 gen_txt2img.py

```python

gen_txt2img.py

import os

from dotenv import load_dotenv

from openai import OpenAI

from imgutil import save_result

load_dotenv()

client = OpenAI(api_key=os.environ["IMAGE_API_KEY"],

base_url=os.environ["IMAGE_API_BASE"])

PROMPT = "一只橘猫坐在木质窗台上,下午的侧逆光,浅景深,胶片质感"

resp = client.images.generate(

model=os.environ["IMAGE_MODEL"],

prompt=PROMPT,

size="1024x1024", # 若平台要求写成 1024*1024,只改这一处;不接受该参数就删掉这行

n=1,

)

out = save_result(resp.data[0], "out/txt2img.png")

print("saved:", out, out.stat().st_size, "bytes")

```

```bash

python gen_txt2img.py

```

出现 saved: out/txt2img.png 数字 bytes 表示成功。

步骤 4:指令改图(整图编辑)

先准备一张原图放进 in/source.png,然后:

```python

edit_image.py

import os

from dotenv import load_dotenv

from openai import OpenAI

from imgutil import save_result

load_dotenv()

client = OpenAI(api_key=os.environ["IMAGE_API_KEY"],

base_url=os.environ["IMAGE_API_BASE"])

with open("in/source.png", "rb") as src:

resp = client.images.edit(

model=os.environ["IMAGE_MODEL"],

image=src,

prompt="把背景换成浅灰色摄影棚背景,人物位置、姿态和服装保持不变,光线方向保持一致",

size="1024x1024",

)

out = save_result(resp.data[0], "out/edit_bg.png")

print("saved:", out)

```

指令改图的提示词按"动词 + 目标 + 保持不变项"三段写,比"弄得好看点"这种描述靠谱得多。有些平台的编辑接口要求传图片 URL 或 base64,字段名可能有差异,照官方文档把上面这一段请求体改掉即可,其余代码不用动。

步骤 5:局部重绘(掩码)

局部重绘的本质是:告诉模型"只有这块区域可以动"。先用 Pillow 画掩码:

```python

make_mask.py

from PIL import Image, ImageDraw

W = H = 1024

BOX = (560, 120, 980, 520) # 左上x, 左上y, 右下x, 右下y

mask = Image.new("RGB", (W, H), "black")

ImageDraw.Draw(mask).rectangle(BOX, fill="white")

mask.save("masks/window.png")

print("mask saved")

```

然后在 edit_image.py 里把掩码一起传进去:

```python

with open("in/source.png", "rb") as src, open("masks/window.png", "rb") as msk:

resp = client.images.edit(

model=os.environ["IMAGE_MODEL"],

image=src,

mask=msk,

prompt="把这片区域里的天空改成黄昏色调,其余区域不要改动",

size="1024x1024",

)

```

注意:不同平台对掩码的黑白约定可能相反(白色表示重绘区,或黑色表示重绘区)。如果发现改错了地方,把掩码反相再用:

```bash

python -c "from PIL import Image, ImageOps; ImageOps.invert(Image.open('masks/window.png').convert('RGB')).save('masks/window_inv.png')"

```

步骤 6:风格统一与批量出图

风格统一的关键不是"每张都写得一样",而是把风格抽成一段固定前缀,主体部分再替换。四段式模板:风格 + 主体 + 镜头/光线 + 排除项

```python

batch.py

import os, json, time

from dotenv import load_dotenv

from openai import OpenAI

from imgutil import save_result

load_dotenv()

client = OpenAI(api_key=os.environ["IMAGE_API_KEY"],

base_url=os.environ["IMAGE_API_BASE"])

STYLE = "柔和的商业插画风格,低饱和莫兰迪色系,简洁构图,大面积留白,柔和顶光"

SUBJECTS = ["一杯手冲咖啡", "一台打开的笔记本电脑", "一盆龟背竹"]

for i, s in enumerate(SUBJECTS, 1):

prompt = f"{STYLE}。主体:{s}。画面中不出现文字与水印。"

t0 = time.time()

try:

resp = client.images.generate(model=os.environ["IMAGE_MODEL"],

prompt=prompt, size="1024x1024", n=1)

p = save_result(resp.data[0], f"out/style_{i:02d}.png")

log = {"i": i, "prompt": prompt, "path": str(p), "ok": True,

"sec": round(time.time() - t0, 1)}

except Exception as e:

log = {"i": i, "prompt": prompt, "ok": False, "err": str(e),

"sec": round(time.time() - t0, 1)}

print(json.dumps(log, ensure_ascii=False))

with open("out/run.log.jsonl", "a", encoding="utf-8") as f:

f.write(json.dumps(log, ensure_ascii=False) + "\n")

time.sleep(1) # 降低触发限流的概率

```

提示词实操的三个具体技巧:

1. 风格前缀固定、只换主体:把 STYLE 写成一个常量,三张图共用,风格漂移会明显减少。

2. 删掉模糊形容词:把"高级感"换成"大面积留白 + 柔和顶光 + 低饱和",可执行性完全不同。

3. 明确写出不要什么:正例是"画面中不出现文字与水印",反例是"不要难看"。否定描述同样要具体。

步骤 7:本地部署(可选)

如果想脱离网络调用,按官方模型页给出的加载示例走,通用流程如下:

```bash

pip install -U torch diffusers transformers accelerate safetensors pillow

```

torch 的 CUDA 版本需与显卡驱动匹配,安装命令以 PyTorch 官方页面给出的方式为准。

```python

local_gen.py —— 类名与参数以官方模型页示例为准

import torch

from diffusers import DiffusionPipeline

MODEL_DIR = "./models/qwen-image" # 本地权重目录

pipe = DiffusionPipeline.from_pretrained(MODEL_DIR, torch_dtype=torch.bfloat16)

pipe.enable_model_cpu_offload() # 显存紧张时开启,会慢一些但跑得动

image = pipe(prompt="一只橘猫坐在木质窗台上,侧逆光,胶片质感",

num_inference_steps=30).images[0]

image.save("out/local.png")

print("saved: out/local.png")

```

编辑能力通常对应另一套权重与 pipeline 类,按官方模型页的示例加载对应目录即可。

验证部署是否成功

文生图验证

```bash

python gen_txt2img.py

python -c "from PIL import Image; im=Image.open('out/txt2img.png'); print(im.size, im.mode)"

```

预期输出形如 (1024, 1024) RGB(或平台默认尺寸),文件大小一般在 100 KB 以上。文件能打开、尺寸非 0 即可认为通了。

编辑验证:确认只改了该改的地方。

```bash

python make_mask.py && python edit_image.py

python - <<'PY'

from PIL import Image, ImageChops

a = Image.open("in/source.png").convert("RGB")

b = Image.open("out/edit_bg.png").convert("RGB")

print("尺寸一致:", a.size == b.size)

print("变化区域:", ImageChops.difference(a, b).getbbox())

PY

```

预期:尺寸一致: True变化区域 返回的矩形大致落在掩码框内。如果返回 None,说明两张图完全相同,编辑没生效。

批量验证

```bash

ls -lh out/style_*.png && wc -l out/run.log.jsonl

```

预期三张图都在,日志行数与出图数量一致,且每行 "ok": true

常见报错与解决

1. ModuleNotFoundError: No module named 'openai'

原因:不在虚拟环境里跑,或者依赖没装成功。

解决:

```bash

source .venv/bin/activate && pip install -U openai python-dotenv requests pillow

```

2. KeyError: 'IMAGE_API_KEY'

原因:.env 没被加载,或变量名与代码里写的不一致。

解决:

```bash

cd ~/qwen-image-demo && python -c "import os; from dotenv import load_dotenv; load_dotenv(); print(bool(os.environ.get('IMAGE_API_KEY')))"

```

输出必须是 True。为 False 就检查 .env 是否在项目根目录、键名有没有拼错。

3. openai.AuthenticationError: Error code: 401 - invalid_api_key

原因:密钥复制不全、首尾带空格或被引号包进去,也可能已失效。

解决:

```bash

python -c "import os; from dotenv import load_dotenv; load_dotenv(); k=os.environ['IMAGE_API_KEY'].strip(); print(repr(k[:4]), len(k))"

```

确认长度正常、没有多余空白,必要时在控制台重新生成密钥再写回 .env

4. openai.BadRequestError: Error code: 400 - InvalidParameter: size

原因:尺寸写法或取值不在平台支持范围内(有的要求 1024*1024,有的只接受特定几档)。

解决:先删掉 size 参数用默认值跑通,再对照官方文档填支持的尺寸:

```bash

python -c "import os; from dotenv import load_dotenv; from openai import OpenAI; load_dotenv(); c=OpenAI(api_key=os.environ['IMAGE_API_KEY'], base_url=os.environ['IMAGE_API_BASE']); print([m.id for m in c.models.list()][:20])"

```

5. openai.NotFoundError: Error code: 404 - model not found

原因:模型 ID 写错,或该模型在当前账号下尚未开通。

解决:在控制台复制准确的模型 ID 覆盖 .env 里的值,确认开通状态后重跑:

```bash

grep IMAGE_MODEL .env

```

6. torch.cuda.OutOfMemoryError: CUDA out of memory

原因:本地部署时显存不够。

解决:开启分层卸载,或先降分辨率试跑。

```bash

PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True python local_gen.py

```

同时在脚本里加上 pipe.enable_model_cpu_offload(),仍不够就换成 pipe.enable_sequential_cpu_offload()

7. 下载结果图时报 requests.exceptions.HTTPError: 403 Client Error

原因:返回的临时链接已过期,或需要鉴权头。

解决:拿到 URL 后立即下载落盘,别把 URL 存下来隔天再用。imgutil.py 里的写法已经是即时下载,只要不改就没事。

后续维护

备份:定期把 .env、提示词模板、masks/out/ 一起归档。密钥单独存放,不要跟产物混在一个压缩包里往外发。产物建议按日期分目录,例如 out/2025-06-01/,回溯时不用翻整个目录。

升级:把当前依赖版本冻结下来,升级前先对比:

```bash

pip freeze > requirements.txt

pip install -U openai && python gen_txt2img.py && python edit_image.py

```

升级 SDK、模型或权重版本后,先用上面两条命令跑一遍核心链路,确认产物正常再切到正式流程。模型 ID 变更时只改 .env,代码无需改动,这也是前面把它做成变量的原因。

日志与监控out/run.log.jsonl 已经记录了每次调用的提示词、产物路径、耗时和成败。可以再加几个统计:

```bash

grep -c '"ok": false' out/run.log.jsonl

awk -F'"sec": ' '{print $2}' out/run.log.jsonl | cut -d, -f1 | sort -n | tail -3

```

第一条看失败次数,第二条看最慢的几次耗时。失败率突然升高,通常指向限流、密钥额度或接口变更,先查这三项。

省钱省时间:先用小尺寸快速试构图,定稿后再出大图;相同提示词与参数的产物落盘缓存,重复请求直接读本地文件;批量任务之间留一秒间隔,减少触发限流的概率。

成本与额度:计费方式、免费额度和并发限制请以官方页面为准,别按经验值估算。

AI 生成本文由 AI 基于公开信息自动生成,仅供参考。