大数跨境
0
0

系列教程二十三 | 基于 Qwen-Image-Edit-2509 构建多角度产品图生成器

系列教程二十三 | 基于 Qwen-Image-Edit-2509 构建多角度产品图生成器 BitaHub社区
2025-12-05
0
导读:上传一张产品图,即可自动生成广角、特写、俯拍、左右 45° 等多角度电商级展示图。本教程基于 Qwen-Image-Edit-2509,结合多角度 LoRA 与 Lightning 加速,通过 Gra

前言


在电商内容爆发的今天,“产品图质量”几乎决定了转化率。但对于个人卖家、小团队、初创品牌来说,请摄影棚、租场景、搭灯光……成本高、门槛高,也耗费大量时间。


而现在,只需上传一张普通产品图,你就能自动生成——广角、特写、左右 45°、俯拍、多比例、多背景的高质量产品展示图,适用于电商主图、详情页、社媒素材等。


本期教程将带你从 0 到 1,使用 Qwen-Image-Edit-2509 + 多角度 LoRA + Lightning 加速 LoRA,构建一个基于 Gradio 的可视化产品图优化应用。


⚡无需本地显卡
⚡无需复杂环境
⚡所有模型已上传 BitaHub,可一键转存、直接使用


🌟 为什么选择 Qwen-Image-Edit-2509 + 多角度 LoRA?


Qwen-Image-Edit-2509 是当前最稳定的图像编辑模型之一,具备更强的细节保持与多图一致性能力。然而,常规文生图模型对“角度控制”并不擅长,经常出现:


❌ 产品形变
❌ 材质改变
❌ 结构重绘
❌ 无法保持同一物体


为了实现“摄影棚里转动相机”的效果,我们加载了两个关键 LoRA:


🔧1. 多角度控制 LoRA (Qwen-Edit-2509-Multiple-angles)


可稳定执行以下虚拟相机指令,相当于是为模型加上了“可控摄像机”。


  • 将镜头转为广角镜头

  • 将镜头转为特写镜头

  • 将镜头向左旋转 45°

  • 将镜头向右移动

  • 将镜头转为俯视


⚡2. Lightning LoRA(Qwen-Image-Lightning


启用后可大幅加速推理,适合批量生成。



👉 这三个模型均已上传至 Bitahub,用户可直接转存到自己云端一键复用。


一.准备工作


1.模型准备

进入对应的模型主页进行转存。




2.创建开发环境


将上述转存好的模型挂载到 BitaHub 工作台的文件存储中。



最后,选择单卡 A100 GPU,并通过JupyterLab访问方式进入开发环境。


二.环境配置


# Transformers / Diffusers / 加速 / PEFT / SafeTensorspip install -q transformers>=4.44.0 accelerate>=0.33.0 safetensors>=0.4.3 diffusers @ git+https://github.com/huggingface/diffusers.git peft==0.18.0# 图像处理和UIpip install -q Pillow>=10.2.0 numpy>=1.26.0 gradio==5.9.1


三.核心代码


首先导入项目运行所需的库,包括图像处理、模型加载与推理,以及搭建交互界面的工具,为整个应用的运行提供环境支持。


import ioimport zipfilefrom typing import ListTupleOptionalimport gcimport torchfrom PIL import Imagefrom diffusers import QwenImageEditPlusPipeline import gradio as gr

随后定义一个函数来获取 GPU 配置,包括设备类型、计算精度、显卡名称和显存信息,同时指定了最大批量、注意力切片和 VAE 切片等参数,然后将结果存入 gpu_config 变量供后续使用。

def get_gpu_config():    return {        'device''cuda',        'dtype': torch.bfloat16,        'gpu_name': torch.cuda.get_device_name(0),        'vram_gb': torch.cuda.get_device_properties(0).total_memory / 1e9,        'max_batch'4,        'enable_attention_slicing'False,        'enable_vae_slicing'False,    }gpu_config = get_gpu_config()


此外,我们还需定义模型和数据的路径以及一些辅助配置,包括基础模型和两个 LoRA 模型的路径、不同拍摄角度对应的文字描述、预设的背景场景文本,以及常用的图片宽高比,用于在生成图像时快速组合提示词和调整输出尺寸。


HF_BASE_MODEL = "/model/Qwen-Image-Edit-2509"LORA_ANGLES = "/model/Qwen-Edit-2509-Multiple-angles"LORA_LIGHTNING = "/model/Qwen-Image-Lightning"ANGLE_MACROS = {    "Wide-angle""将镜头转为广角镜头",    "Close-up""将镜头转为特写镜头",    "Forward""将镜头向前移动",    "Left""将镜头向左移动",    "Right""将镜头向右移动",    "Down""将镜头向下移动",    "Rotate 45° Left""将镜头向左旋转45度",    "Rotate 45° Right""将镜头向右旋转45度",    "Top-down""将镜头转为俯视",}BACKGROUND_PRESETS = {    "(None)": None,    "Pure Studio (white seamless)""in a professional studio with seamless white background, soft shadows, product centered",    "Soft Gray Studio""in a professional studio with seamless soft gray background, gentle vignette, softbox lighting",    "Lifestyle (cozy desk)""on a cozy wooden desk near a window, soft natural light, minimal props",    "Lifestyle (marble)""on a clean white marble surface, bright daylight, subtle reflections",    "Lifestyle (outdoor)""outdoors on a neutral table, soft shade, bokeh background",}ASPECT_RATIOS = {    "1:1 (Square)": (1024, 1024),    "4:3 (Standard)": (1024, 768),    "3:4 (Portrait)": (768, 1024),    "16:9 (Widescreen)": (1024, 576),    "9:16 (Mobile)": (576, 1024),    "3:2 (Photo)": (1024, 683),    "2:3 (Portrait Photo)": (683, 1024),}


下面这段代码先从本地路径加载基础的 Qwen 图像编辑模型,并将其移动到指定 GPU,同时根据配置启用注意力切片或 VAE 切片以节省显存。随后加载用于多角度生成的 LoRA 权重,并定义了一个函数来控制LoRA使用模式模式,当启用“Lightning LoRA”快速模式时,会额外加载加速 LoRA,并设置对应的适配器组合,否则只使用默认角度 LoRA。


pipe = QwenImageEditPlusPipeline.from_pretrained(    HF_BASE_MODEL,    torch_dtype=gpu_config['dtype'],   )pipe.to(gpu_config['device'])if gpu_config['enable_attention_slicing']:    pipe.enable_attention_slicing()if gpu_config['enable_vae_slicing']:    pipe.enable_vae_slicing()# 加载 LoRApipe.load_lora_weights(LORA_ANGLES, adapter_name="angles")current_mode = {"fast"False}def set_pipeline_mode(use_lightning: bool):    global current_mode      if use_lightning and not current_mode["fast"]:        pipe.load_lora_weights(LORA_LIGHTNING, adapter_name="lightning")        pipe.set_adapters(["angles""lightning"], adapter_weights=[1.01.0])        current_mode["fast"] = True    elif not use_lightning and current_mode["fast"]:        pipe.set_adapters(["angles"], adapter_weights=[1.0])        current_mode["fast"] = False    elif not use_lightning and not current_mode["fast"]:        pipe.set_adapters(["angles"], adapter_weights=[1.0])set_pipeline_mode(False)


我们还需要定义一些函数工具,首先通过 compose_prompt 函数将用户选择的角度、背景预设、自定义场景和额外风格组合成最终的生成提示词。resize_image 函数则会把输入图片按目标长宽比缩放并裁剪,以适配模型的输入尺寸。

generate_images 是核心生成函数,它根据用户选择的角度和其他参数循环生成图像,每次都调用模型生成对应角度的结果,并将生成的图片收集到列表中返回。create_zip 则将生成的图片打包成 ZIP 文件,方便用户下载。整个流程实现了从用户输入到多角度图像生成,再到批量导出的完整操作。


def compose_prompt(angle_phrase: str,                   bg_preset_text: Optional[str],                   custom_scene: str,                   extra_style: str) -> str:    parts = [angle_phrase]    if bg_preset_text:        parts.append(f"{bg_preset_text}")    if custom_scene.strip():        parts.append(custom_scene.strip())    if extra_style.strip():        parts.append(extra_style.strip())    return " | ".join(parts)
def resize_image(img: Image.Image, target_size: Tuple[intint]) -> Image.Image:    target_w, target_h = target_size    orig_w, orig_h = img.size    scale = max(target_w / orig_w, target_h / orig_h)    new_w = int(orig_w * scale)    new_h = int(orig_h * scale)    img = img.resize((new_w, new_h), Image.Resampling.LANCZOS)     left = (new_w - target_w) // 2    top = (new_h - target_h) // 2    img = img.crop((left, top, left + target_w, top + target_h))        return img
def generate_images(    source_img: Image.Image,    angle_keys: List[str],    bg_key: str,    custom_scene: str,    extra_style: str,    aspect_ratio: str,    use_lightning: bool,    seed: int,    steps: int,    guidance_scale: float,    true_cfg_scale: float,    images_per_prompt: int,    progress=gr.Progress()) -> List[Image.Image]:       if source_img is None:        return [], "WARNING: Please upload an image first!"        if not angle_keys:        return [], "WARNING: Please select at least one angle!"      target_size = ASPECT_RATIOS[aspect_ratio]    source_img = resize_image(source_img, target_size)      set_pipeline_mode(use_lightning)    results = []    generator = torch.manual_seed(seed)      bg_preset_text = BACKGROUND_PRESETS.get(bg_key)        total_angles = len(angle_keys)        for idx, angle_name in enumerate(angle_keys):        progress((idx + 1) / total_angles, f"Generating {angle_name}..."        angle_phrase = ANGLE_MACROS[angle_name]        full_prompt = compose_prompt(angle_phrase, bg_preset_text, custom_scene, extra_style)           inputs = {            "image": [source_img],            "prompt": full_prompt,            "generator": generator,            "true_cfg_scale": true_cfg_scale,            "negative_prompt"" ",            "num_inference_steps": steps,            "guidance_scale": guidance_scale,            "num_images_per_prompt": images_per_prompt,            "height": target_size[1],            "width": target_size[0],        }             with torch.inference_mode():            out = pipe(**inputs)           for img_idx, im in enumerate(out.images):            results.append(im)     return results
def create_zip(images: List[Image.Image]) -> Optional[str]:    if not images:        return None    zip_path = "product_shot_booster.zip"    with zipfile.ZipFile(zip_path, mode="w", compression=zipfile.ZIP_DEFLATED) as zf:        zf.writestr("manifest.txt""Product Shot Booster Export\nGenerated angles exported as PNG files.\n")        for idx, img in enumerate(images):            buf = io.BytesIO()            img.save(buf, format="PNG")            zf.writestr(f"angle_{idx+1:03d}.png", buf.getvalue())    return zip_path


最后,我们实现了一个基于 Gradio 的可视化工具,用于对产品图片进行多角度生成和优化。用户可以上传一张产品图,选择拍摄角度、背景预设、画面比例以及自定义场景描述和风格说明,工具会调用 QwenImageEditPlusPipeline 模型生成对应的多角度图像。支持启用 Lightning LoRA 的快速模式以加速生成过程,用户还可以调整随机种子、推理步数、引导强度等高级参数。生成的多张图片会显示在界面中,同时可以打包成 ZIP 文件供下载,方便批量保存。整体功能是让用户无需编程即可快速生成高质量、不同角度和风格的产品图片。


with gr.Blocks(title="产品图优化加速器", theme=gr.themes.Soft()) as demo:    gr.Markdown("<h1 style='text-align: center;font-weight: bold;'>产品图优化加速器</h1>")    with gr.Row():        with gr.Column(scale=1):            input_image = gr.Image(                label="产品图片",                type="pil",                height=300            )             angle_choices = gr.CheckboxGroup(                choices=list(ANGLE_MACROS.keys()),                value=["Wide-angle""Close-up""Rotate 45° Left""Rotate 45° Right""Top-down"],                label="拍摄角度"            )             aspect_ratio = gr.Dropdown(                choices=list(ASPECT_RATIOS.keys()),                value="1:1 (Square)",                label="画面比例"            )            bg_preset = gr.Dropdown(                choices=list(BACKGROUND_PRESETS.keys()),                value="(None)",                label="背景预设"            )             custom_scene = gr.Textbox(                label="自定义场景描述",                placeholder="如:'置于哑光黑桌面,带轻微反射'",                lines=2            )                extra_style = gr.Textbox(                label="风格说明",                value="专业摄影棚灯光、高清晰度、适用于电商拍摄",                lines=2            )        with gr.Column(scale=2):            output_gallery = gr.Gallery(                  label="生成结果",                  show_label=True,                  columns=3,                  height="auto",                  object_fit="contain"              )            info_output = gr.Markdown("")            zip_output = gr.File(label="下载全部(ZIP)")    with gr.Accordion("高级设置"open=False):        with gr.Row():            use_lightning = gr.Checkbox(                label="快速模式(Lightning LoRA)",                value=False,                info="启用 Lightning LoRA 加速 "            )               seed = gr.Number(                label="Seed",                value=123,                precision=0            )              steps = gr.Slider(                label="Inference Steps",                minimum=10,                maximum=60,                value=28,                step=1            )        with gr.Row():            guidance_scale = gr.Slider(                label="Guidance Scale",                minimum=0.0,                maximum=8.0,                value=1.0,                step=0.1            )            true_cfg_scale = gr.Slider(                label="True CFG Scale",                minimum=0.0,                maximum=10.0,                value=4.0,                step=0.1            )             images_per_prompt = gr.Slider(                label="Images per Angle",                minimum=1,                maximum=4,                value=1,                step=1            )    generate_btn = gr.Button("开始生成", variant="primary", size="lg")    def generate_and_zip(*args):      images = generate_images(*args)      zip_file = create_zip(images) if images else None      return images, zip_file     generate_btn.click(        fn=generate_and_zip,        inputs=[            input_image,            angle_choices,            bg_preset,            custom_scene,            extra_style,            aspect_ratio,            use_lightning,            seed,            steps,            guidance_scale,            true_cfg_scale,            images_per_prompt        ],        outputs=[output_gallery, zip_output]    )demo.launch(share=True, debug=True, show_error=True)


四.项目效果展示



将上述代码保存为 app.py,打开终端运行 python app.py 即可启动。上传一张产品照片,你可以一键输出:

  • 多角度视图(±45°、俯拍、广角、特写…)

  • 多背景风格(棚拍白底、灰棚、生活场景、户外)

  • 多画幅(1:1、3:4、16:9、9:16 等)

  • 批量生成 ZIP 打包下载



🎉 欢迎到 BitaHub 体验完整 Demo,开启你的 AI 产品摄影之旅!


【声明】内容源于网络
0
0
BitaHub社区
BitaHub是一个开放的AI和深度学习社区,为广大开发者提供先进的、有竞争力的GPU算力资源及数据集、模型资源,同时提供了一个全流程的AI开发平台,包括模型训练、推理、数据集管理。
内容 50
粉丝 0
BitaHub社区 BitaHub是一个开放的AI和深度学习社区,为广大开发者提供先进的、有竞争力的GPU算力资源及数据集、模型资源,同时提供了一个全流程的AI开发平台,包括模型训练、推理、数据集管理。
总阅读18
粉丝0
内容50