AI图生图完整实战:基于阿里云百炼通义万相

目录

  1. 什么是图生图
  2. 应用场景
  3. 环境搭建与依赖安装
  4. 阿里云百炼平台配置
  5. 完整代码实现
  6. 代码逐行解析
  7. 运行测试
  8. 常见问题
  9. 总结

一、什么是图生图

图生图(Image-to-Image)是一种基于现有图片,根据文字指令进行修改或生成新图片的人工智能技术。

核心原理:用户提供一张原始图片,并输入修改指令,AI模型理解指令后,在保留原图主体特征的基础上进行修改。

输入 输出

原图 + "把背景换成海滩,保持人物不变" 🖼️ 修改后的图片

通俗理解:就像有一个专业的修图师,你告诉他"把这张照片背景换成海滩",他就能帮你完成修改。

文生图 vs 图生图

对比维度 文生图 图生图

输入 仅文字描述 图片 + 文字指令

输出 全新图片 基于原图修改

适用场景 从零创作 编辑、修改、风格转换

典型指令 "生成一只猫" "把这只猫变成动漫风格"


二、应用场景

场景 说明 示例指令

人像美化 调整照片风格、换背景 "把背景换成海滩,保持人物不变"

产品图优化 更换商品颜色、背景 "把产品颜色改成红色,白色背景"

风格迁移 改变图片艺术风格 "把图片改成水墨画风格"

细节增强 增加图片细节和清晰度 "增加细节,4K高清"

创意设计 快速迭代设计方案 "把这张草图改成插画风格"


三、环境搭建与依赖安装

3.1 依赖库清单

text 复制代码
python-dotenv>=1.0.0
requests>=2.31.0
Pillow>=10.0.0

库名 用途

python-dotenv 从 .env 文件读取 API Key

requests 发送 HTTP 请求调用 API

Pillow 创建示例图片、处理图片信息

3.2 一键安装

bash 复制代码
pip install python-dotenv requests Pillow -i https://pypi.tuna.tsinghua.edu.cn/simple

3.3 创建项目目录

bash 复制代码
mkdir ai_image_to_image
cd ai_image_to_image

3.4 项目文件结构

复制代码
ai_image_to_image/
├── .env                 # API Key 配置文件
├── image_to_image.py    # 图生图主程序
├── input_images/        # 输入图片目录(放你要修改的图片)
├── output_images/       # 输出图片目录(修改后的图片)
└── README.md           # 说明文档

四、阿里云百炼平台配置

4.1 获取 API Key

  1. 访问 阿里云百炼控制台
  2. 使用手机号或支付宝扫码登录
  3. 选择地域:华北2(北京)
  4. 左侧菜单找到 "API Key" → 点击 "创建API Key"
  5. 复制并保存生成的 API Key(以 sk- 开头)

4.2 配置环境变量

在项目根目录创建 .env 文件:

bash 复制代码
DASHSCOPE_API_KEY="sk-你的API Key"

⚠️ 安全提示:不要将 .env 文件提交到 GitHub,建议添加到 .gitignore

4.3 免费额度说明

新用户开通阿里云百炼后,自动获得免费额度:

· 文生图:前50张免费(图生图消耗免费额度)

· 有效期:90天

· 可在控制台开启"免费额度用完即停"避免意外扣费


五、完整代码实现

python 复制代码
"""
图生图(Image-to-Image)完整实现
使用阿里云百炼原生 API(异步调用模式)
功能:基于现有图片进行修改
"""

import os
import time
import base64
import requests
from datetime import datetime
from dotenv import load_dotenv
from PIL import Image

# ========== 初始化配置 ==========
# 加载 .env 文件中的环境变量
load_dotenv()

# 获取 API Key(从 .env 文件读取)
API_KEY = os.getenv("DASHSCOPE_API_KEY")

# 阿里云百炼 API 地址(北京地域)
BASE_URL = "https://dashscope.aliyuncs.com"

# 创建输入输出目录
INPUT_DIR = "input_images"    # 存放待修改的图片
OUTPUT_DIR = "output_images"   # 存放修改后的图片
os.makedirs(INPUT_DIR, exist_ok=True)
os.makedirs(OUTPUT_DIR, exist_ok=True)

print("=" * 60)
print("🎨 图生图(Image-to-Image)实战")
print("=" * 60)


def image_to_image(image_path: str, prompt: str, size: str = "1024*1024"):
    """
    图生图核心函数(异步调用模式)
    
    参数:
        image_path: 输入图片路径(本地文件)
        prompt: 修改指令,如 "把背景换成海滩"
        size: 输出图片尺寸,可选 "1024*1024", "768*1024", "1024*768"
    
    返回:
        修改后的图片本地路径,失败返回 None
    """
    print(f"\n📷 输入图片: {image_path}")
    print(f"📝 修改指令: {prompt}")
    print(f"📐 输出尺寸: {size}")
    
    try:
        # ========== 步骤0:读取并编码图片 ==========
        # 图生图 API 需要将图片转换为 base64 格式
        with open(image_path, "rb") as f:
            image_data = f.read()
            base64_image = base64.b64encode(image_data).decode('utf-8')
        
        # 根据文件扩展名确定 MIME 类型
        if image_path.lower().endswith('.png'):
            mime_type = "image/png"
        else:
            mime_type = "image/jpeg"
        
        # ========== 步骤1:创建异步任务 ==========
        # 图生图 API 端点
        create_url = f"{BASE_URL}/api/v1/services/aigc/text2image/image-synthesis"
        
        # 请求头设置
        headers = {
            "X-DashScope-Async": "enable",      # 启用异步模式
            "Authorization": f"Bearer {API_KEY}", # API 认证
            "Content-Type": "application/json"   # 请求体格式
        }
        
        # 请求体参数
        payload = {
            "model": "wanx-v1",                 # 图生图使用 wanx-v1 模型
            "input": {
                "prompt": prompt,               # 修改指令
                "image": f"data:{mime_type};base64,{base64_image}"  # base64 图片
            },
            "parameters": {
                "size": size,                   # 输出图片尺寸
                "n": 1                          # 生成图片数量
            }
        }
        
        print("📤 提交任务...")
        create_response = requests.post(create_url, headers=headers, json=payload)
        
        # 检查创建任务是否成功
        if create_response.status_code != 200:
            print(f"❌ 创建任务失败: {create_response.text}")
            return None
        
        # 获取任务 ID(用于后续查询结果)
        result = create_response.json()
        task_id = result.get("output", {}).get("task_id")
        if not task_id:
            print(f"❌ 未获取到 task_id: {result}")
            return None
        
        print(f"✅ 任务已创建,task_id: {task_id}")
        
        # ========== 步骤2:轮询查询结果 ==========
        query_url = f"{BASE_URL}/api/v1/tasks/{task_id}"
        
        print("⏳ 等待生成...")
        max_attempts = 30      # 最多尝试30次
        attempt = 0
        
        while attempt < max_attempts:
            time.sleep(2)      # 每2秒查询一次,避免频繁请求
            
            # 查询任务状态
            query_response = requests.get(query_url, headers={
                "Authorization": f"Bearer {API_KEY}"
            })
            
            if query_response.status_code != 200:
                print(f"⚠️ 查询失败: {query_response.text}")
                attempt += 1
                continue
            
            result = query_response.json()
            task_status = result.get("output", {}).get("task_status")
            
            # 任务成功完成
            if task_status == "SUCCEEDED":
                # 获取图片 URL
                image_urls = result.get("output", {}).get("results", [])
                if image_urls:
                    image_url = image_urls[0].get("url")
                    print(f"✅ 图片修改成功")
                    
                    # 下载图片到本地
                    img_response = requests.get(image_url)
                    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                    filename = f"{OUTPUT_DIR}/img2img_{timestamp}.png"
                    
                    with open(filename, "wb") as f:
                        f.write(img_response.content)
                    
                    print(f"💾 图片已保存: {filename}")
                    return filename
                else:
                    print("❌ 未获取到图片 URL")
                    return None
            
            # 任务失败
            elif task_status == "FAILED":
                error_msg = result.get("output", {}).get("message", "未知错误")
                print(f"❌ 任务失败: {error_msg}")
                return None
            
            # 任务处理中(PENDING、RUNNING等状态)
            else:
                print(f"⏳ 处理中... 状态: {task_status}")
            
            attempt += 1
        
        print("❌ 超时:任务未在预期时间内完成")
        return None
        
    except Exception as e:
        print(f"❌ 修改失败: {str(e)}")
        return None


def create_sample_image():
    """
    创建一个简单的示例图片(用于测试)
    如果没有输入图片,自动生成一个蓝色方块作为测试
    """
    img = Image.new('RGB', (512, 512), color='lightblue')
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    sample_path = f"{INPUT_DIR}/sample_{timestamp}.png"
    img.save(sample_path)
    print(f"📝 已创建示例图片: {sample_path}")
    return sample_path


def display_image_info(image_path: str):
    """
    显示图片信息(尺寸、格式等)
    
    参数:
        image_path: 图片文件路径
    """
    if image_path and os.path.exists(image_path):
        img = Image.open(image_path)
        print(f"📷 图片信息: {img.size[0]}x{img.size[1]}, {img.format}")
        return img
    return None


# ========== 测试示例 ==========
if __name__ == "__main__":
    print("\n💡 使用说明:")
    print("   1. 将需要修改的图片放入 input_images/ 目录")
    print("   2. 程序会自动处理第一张图片")
    print("   3. 如果没有图片,会自动创建示例图片\n")
    
    # 检查是否有输入图片
    input_files = [f for f in os.listdir(INPUT_DIR) 
                   if f.endswith(('.png', '.jpg', '.jpeg'))]
    
    if not input_files:
        print("未找到输入图片,创建示例图片...")
        test_image = create_sample_image()
    else:
        test_image = f"{INPUT_DIR}/{input_files[0]}"
        print(f"使用图片: {test_image}")
    
    print("\n" + "-" * 40)
    print("示例:修改图片风格")
    print("-" * 40)
    
    # 调用图生图函数
    result = image_to_image(
        image_path=test_image,
        prompt="把图片改成动漫风格,色彩鲜艳,增加细节",
        size="1024*1024"
    )
    
    # 显示结果信息
    if result:
        display_image_info(result)
    
    print("\n" + "=" * 60)
    print("🎉 图生图演示完成!")
    print("=" * 60)

六、代码逐行解析

6.1 核心概念:图生图的特殊要求

图生图相比文生图,多了两个关键步骤:

步骤 文生图 图生图

图片输入 不需要 需要读取并编码为 base64

模型名称 wan2.5-t2i-preview wanx-v1

input 字段 只需 prompt 需要 prompt + image

6.2 图片编码解析

python 复制代码
# 读取图片二进制数据
with open(image_path, "rb") as f:
    image_data = f.read()

# 转换为 base64 字符串
base64_image = base64.b64encode(image_data).decode('utf-8')

# 添加 data URL 前缀(API 要求格式)
image_field = f"data:{mime_type};base64,{base64_image}"

data URL 格式说明:

· data: - 固定前缀

· image/png - MIME 类型

· ;base64, - 编码方式分隔符

· [base64字符串] - 实际图片数据

6.3 MIME 类型判断

python 复制代码
if image_path.lower().endswith('.png'):
    mime_type = "image/png"   # PNG 格式
else:
    mime_type = "image/jpeg"  # JPG/JPEG 格式

6.4 与文生图的关键区别

对比项 文生图 图生图

API 端点 /api/v1/services/aigc/image-generation/generation /api/v1/services/aigc/text2image/image-synthesis

模型名称 wan2.5-t2i-preview wanx-v1

input 字段 {"prompt": "..."} {"prompt": "...", "image": "data:..."}

图片处理 不需要 需要 base64 编码

6.5 异步调用流程

复制代码
┌─────────────────────────────────────────────────────────────┐
│                     图生图异步调用流程                        │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  步骤1:准备图片                                             │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐     │
│  │ 读取本地图片 │ -> │ Base64编码  │ -> │ data URL    │     │
│  └─────────────┘    └─────────────┘    └─────────────┘     │
│                                              │               │
│                                              ▼               │
│  步骤2:提交任务                                             │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐     │
│  │ POST 请求   │ -> │ 获得task_id │ -> │ 打印确认    │     │
│  └─────────────┘    └─────────────┘    └─────────────┘     │
│                                              │               │
│                                              ▼               │
│  步骤3:轮询结果                                             │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐     │
│  │ 每2秒查询   │ -> │ 检查状态    │ -> │ SUCCEEDED   │     │
│  └─────────────┘    └─────────────┘    └─────────────┘     │
│                                              │               │
│                                              ▼               │
│  步骤4:保存结果                                             │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐     │
│  │ 下载图片    │ -> │ 保存到本地  │ -> │ 返回路径    │     │
│  └─────────────┘    └─────────────┘    └─────────────┘     │
│                                                              │
└─────────────────────────────────────────────────────────────┘

七、运行测试

7.1 准备输入图片

方式一:手动放置图片

将任意图片放入 input_images/ 目录

方式二:自动创建示例图片

如果没有图片,程序会自动创建一个蓝色方块作为测试

7.2 执行脚本

bash 复制代码
python image_to_image.py

7.3 预期输出

复制代码
============================================================
🎨 图生图(Image-to-Image)实战
============================================================

💡 使用说明:
   1. 将需要修改的图片放入 input_images/ 目录
   2. 程序会自动处理第一张图片
   3. 如果没有图片,会自动创建示例图片

未找到输入图片,创建示例图片...
📝 已创建示例图片: input_images/sample_20260115_143025.png

----------------------------------------
示例:修改图片风格
----------------------------------------

📷 输入图片: input_images/sample_20260115_143025.png
📝 修改指令: 把图片改成动漫风格,色彩鲜艳,增加细节
📐 输出尺寸: 1024*1024
📤 提交任务...
✅ 任务已创建,task_id: 8f3b6a1c-9d4e-4f2a-8c1e-3b5f7a9d2c1e
⏳ 等待生成...
⏳ 处理中... 状态: PENDING
⏳ 处理中... 状态: RUNNING
✅ 图片修改成功
💾 图片已保存: output_images/img2img_20260115_143045.png
📷 图片信息: 1024x1024, PNG

============================================================
🎉 图生图演示完成!
============================================================

7.4 查看生成结果

bash 复制代码
ls output_images/
# 输出: img2img_20260115_143045.png

ls input_images/
# 输出: sample_20260115_143025.png

八、常见问题

Q1:提示 No module named 'dotenv'

bash 复制代码
pip install python-dotenv

Q2:提示 API Key 无效

检查 .env 文件中的 API Key 是否正确,注意不要有多余空格或引号。

Q3:提示图片文件过大?

图生图 API 对图片大小有限制(建议不超过 10MB),可以先用工具压缩图片。

Q4:生成失败,提示 404?

检查 API 地址是否正确,北京地域使用 https://dashscope.aliyuncs.com

Q5:生成速度慢?

图片生成需要 5-15 秒,属于正常现象。

Q6:支持哪些图片格式?

支持 PNG、JPG、JPEG 格式。

Q7:修改效果不理想?

可以优化修改指令,例如:

· "把图片改成动漫风格,色彩鲜艳"

· "增加细节,高清画质"

· "把背景换成海滩日落"


九、修改指令编写技巧

9.1 好的指令结构

复制代码
[修改类型] + [目标效果] + [细节要求]

9.2 指令示例

修改类型 示例指令

风格转换 "把图片改成水墨画风格"

背景替换 "把背景换成海滩日落"

细节增强 "增加图片细节,4K高清"

色彩调整 "色彩更鲜艳,明亮"

综合修改 "改成动漫风格,色彩鲜艳,增加细节"

9.3 效果对比

指令 预期效果

"改成动漫风格" 变为日系/美式动漫风格

"改成水墨画风格" 变为中国传统水墨效果

"增加细节,高清" 提高清晰度和细节

"色彩鲜艳" 饱和度提升


十、总结

本文实现了图生图的核心功能:

步骤 功能 代码实现

0 图片编码 base64.b64encode()

1 提交任务 requests.post() + 异步头

2 获取任务ID response.json()["output"]["task_id"]

3 轮询结果 while 循环 + time.sleep()

4 下载图片 requests.get(image_url)

5 保存本地 open(filename, "wb")

文生图 vs 图生图对比

对比项 文生图 图生图

API 端点 image-generation/generation text2image/image-synthesis

模型 wan2.5-t2i-preview wanx-v1

输入 只有 prompt prompt + image

图片处理 不需要 需要 base64 编码

核心代码模板(精简版):

python 复制代码
# 1. 编码图片
with open(image_path, "rb") as f:
    base64_image = base64.b64encode(f.read()).decode('utf-8')

# 2. 提交任务
response = requests.post(api_url, headers=headers, json={
    "model": "wanx-v1",
    "input": {
        "prompt": prompt,
        "image": f"data:image/png;base64,{base64_image}"
    },
    "parameters": {"size": "1024*1024", "n": 1}
})
task_id = response.json()["output"]["task_id"]

# 3. 轮询结果
while True:
    time.sleep(2)
    result = requests.get(f"{base_url}/api/v1/tasks/{task_id}", headers=headers)
    if result.json()["output"]["task_status"] == "SUCCEEDED":
        image_url = result.json()["output"]["results"][0]["url"]
        break

相关推荐
一只AI打工虾的自我修养1 小时前
Mac mini 本地AI工作站配置指南(2026实战):从零打造 M4 Mac mini AI 开发环境
人工智能·macos
CodePlayer竟然被占用了1 小时前
少即是多:GPT-5.5 Prompt 官方指南的核心转变
人工智能
liuyunshengsir1 小时前
手写最基础的大模型推理并使用Profile监控GPU性能消耗情况
人工智能·深度学习·机器学习
翼龙云_cloud1 小时前
阿里云代理商:阿里云部署的Hermes Agent 钉钉接入指南
人工智能·阿里云·云计算·钉钉·ai 智能体·hermes agent
user29876982706541 小时前
五、深入 Claude Code CLI 源码:终端 UI 的 React 实现
人工智能
znhb991 小时前
九九AI驱动脱硫脱硝及氨逃逸精准控制技术,实现环保、经济、运维三重升级
运维·人工智能
_Evan_Yao1 小时前
当 if 成为性能判官:分支预测、流水线冲刷与 Java 中的“猜谜游戏”
人工智能·游戏
丝雨_xrc2 小时前
CSDN 发布 AI 数字营销 OS,重新定义内容营销增长范式!
人工智能