Python 实现 AI 图像生成:调用 Stable Diffusion API 完整教程

Python 实现 AI 图像生成:调用 Stable Diffusion API 完整教程

从零开始学习使用 Python 调用 Stable Diffusion API 生成图像,涵盖本地部署、API 调用、ControlNet、图生图等进阶技巧。

1. 技术架构

Python 客户端

Stable Diffusion API

本地部署
SD WebUI / ComfyUI

云端 API
Replicate / Stability AI

Stable Diffusion 模型

文生图
txt2img

图生图
img2img

局部重绘
inpainting

超分辨率
upscale

输出图像

后处理管道

存储
本地/OSS

2. 图像生成方式对比

50%25%15%10%各生成方式使用占比统计文生图 (txt2img)图生图 (img2img)局部重绘 (inpainting)超分辨率 (upscale)

3. 环境准备

3.1 本地部署 Stable Diffusion WebUI

# 克隆 Stable Diffusion WebUIgit clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git cd stable-diffusion-webui # 启动(开启 API 模式) ./webui.sh --api--listen# Windows 用户 webui.bat --api--listen

3.2 安装依赖

pip install requests Pillow io base64 

4. 核心代码实现

4.1 SD API 客户端封装

# sd_client.pyimport requests import base64 import io import json import time from pathlib import Path from PIL import Image from dataclasses import dataclass, field from typing import Optional @dataclassclassGenerationConfig:"""图像生成配置""" prompt:str="" negative_prompt:str="low quality, blurry, deformed" width:int=512 height:int=512 steps:int=30 cfg_scale:float=7.0 sampler_name:str="DPM++ 2M Karras" seed:int=-1# -1 表示随机 batch_size:int=1 n_iter:int=1# 迭代次数 model: Optional[str]=NoneclassStableDiffusionClient:"""Stable Diffusion API 客户端"""def__init__(self, base_url:str="http://127.0.0.1:7860"): self.base_url = base_url self.api_url =f"{base_url}/sdapi/v1"def_save_base64_image(self, b64_str:str, output_path:str)->str:"""将 base64 图片保存到文件""" img_data = base64.b64decode(b64_str) img = Image.open(io.BytesIO(img_data)) img.save(output_path)return output_path # ---- 文生图 ----deftxt2img(self, config: GenerationConfig, output_dir:str="./output")->list[str]:"""文生图:从文本描述生成图像""" payload ={"prompt": config.prompt,"negative_prompt": config.negative_prompt,"width": config.width,"height": config.height,"steps": config.steps,"cfg_scale": config.cfg_scale,"sampler_name": config.sampler_name,"seed": config.seed,"batch_size": config.batch_size,"n_iter": config.n_iter,}if config.model: self._switch_model(config.model) response = requests.post(f"{self.api_url}/txt2img", json=payload) response.raise_for_status() data = response.json() Path(output_dir).mkdir(exist_ok=True) saved_paths =[]for i, img_b64 inenumerate(data["images"]): path =f"{output_dir}/txt2img_{int(time.time())}_{i}.png" self._save_base64_image(img_b64, path) saved_paths.append(path)print(f"已保存: {path}")return saved_paths # ---- 图生图 ----defimg2img(self, init_image_path:str, prompt:str, denoising_strength:float=0.75, config: GenerationConfig =None, output_dir:str="./output")->list[str]:"""图生图:基于参考图 + 提示词生成新图""" config = config or GenerationConfig()# 读取初始图片并转 base64withopen(init_image_path,"rb")as f: init_images =[base64.b64encode(f.read()).decode()] payload ={"init_images": init_images,"prompt": prompt,"negative_prompt": config.negative_prompt,"width": config.width,"height": config.height,"steps": config.steps,"cfg_scale": config.cfg_scale,"sampler_name": config.sampler_name,"denoising_strength": denoising_strength,"seed": config.seed,} response = requests.post(f"{self.api_url}/img2img", json=payload) response.raise_for_status() data = response.json() Path(output_dir).mkdir(exist_ok=True) saved_paths =[]for i, img_b64 inenumerate(data["images"]): path =f"{output_dir}/img2img_{int(time.time())}_{i}.png" self._save_base64_image(img_b64, path) saved_paths.append(path)print(f"已保存: {path}")return saved_paths # ---- 局部重绘 ----definpaint(self, init_image_path:str, mask_image_path:str, prompt:str, denoising_strength:float=0.85, output_dir:str="./output")->list[str]:"""局部重绘:只修改 mask 区域"""withopen(init_image_path,"rb")as f: init_images =[base64.b64encode(f.read()).decode()]withopen(mask_image_path,"rb")as f: mask = base64.b64encode(f.read()).decode() payload ={"init_images": init_images,"mask": mask,"prompt": prompt,"negative_prompt":"low quality, blurry","denoising_strength": denoising_strength,"inpainting_fill":1,# 0=fill, 1=original, 2=latent noise"inpaint_full_res":True,"steps":30,"cfg_scale":7.0,"sampler_name":"DPM++ 2M Karras","width":512,"height":512,} response = requests.post(f"{self.api_url}/img2img", json=payload) response.raise_for_status() data = response.json() Path(output_dir).mkdir(exist_ok=True) saved_paths =[]for i, img_b64 inenumerate(data["images"]): path =f"{output_dir}/inpaint_{int(time.time())}_{i}.png" self._save_base64_image(img_b64, path) saved_paths.append(path)return saved_paths # ---- 超分辨率 ----defupscale(self, image_path:str, scale:int=2, output_dir:str="./output")->str:"""使用 ESRGAN 进行超分辨率放大"""withopen(image_path,"rb")as f: img_b64 = base64.b64encode(f.read()).decode() payload ={"image": img_b64,"upscaler_1":"R-ESRGAN 4x+","upscaling_resize": scale,} response = requests.post(f"{self.api_url}/extra-single-image", json=payload) response.raise_for_status() data = response.json() Path(output_dir).mkdir(exist_ok=True) path =f"{output_dir}/upscaled_{int(time.time())}.png" self._save_base64_image(data["image"], path)print(f"超分辨率完成: {path}")return path # ---- 模型管理 ----def_switch_model(self, model_name:str):"""切换模型""" response = requests.post(f"{self.api_url}/options", json={"sd_model_checkpoint": model_name},) response.raise_for_status() time.sleep(3)# 等待模型加载deflist_models(self)->list[str]:"""列出可用模型""" response = requests.get(f"{self.api_url}/sd-models")return[m["title"]for m in response.json()]deflist_samplers(self)->list[str]:"""列出可用采样器""" response = requests.get(f"{self.api_url}/samplers")return[s["name"]for s in response.json()]

4.2 批量生成示例

# batch_generate.pyfrom sd_client import StableDiffusionClient, GenerationConfig defbatch_generate_portraits():"""批量生成人物肖像""" sd = StableDiffusionClient()# 查看可用模型和采样器print("可用模型:", sd.list_models()[:5])print("可用采样器:", sd.list_samplers())# 风格列表 styles =["cyberpunk neon city","watercolor painting","oil painting renaissance","anime style","photorealistic 8k",] base_prompt =("portrait of a young woman, detailed face, beautiful eyes, ""dramatic lighting, masterpiece, best quality")for style in styles: config = GenerationConfig( prompt=f"{base_prompt}, {style}", negative_prompt="lowres, bad anatomy, bad hands, text, error", width=512, height=768, steps=30, cfg_scale=7.5,) paths = sd.txt2img(config, output_dir=f"./output/{style.replace(' ','_')}")print(f"风格 [{style}] -> {paths}")if __name__ =="__main__": batch_generate_portraits()

4.3 调用 Stability AI 云端 API

# stability_cloud.pyimport requests import base64 from pathlib import Path from PIL import Image from io import BytesIO classStabilityAIClient:"""Stability AI 官方云端 API"""def__init__(self, api_key:str): self.api_key = api_key self.base_url ="https://api.stability.ai/v2beta"defgenerate(self, prompt:str, aspect_ratio:str="1:1", style:str="photographic", output_path:str="output.png")->str:"""调用 Stable Diffusion 3 生成图像""" response = requests.post(f"{self.base_url}/stable-image/generate/sd3", headers={"Authorization":f"Bearer {self.api_key}","Accept":"image/*",}, files={"none":""}, data={"prompt": prompt,"aspect_ratio": aspect_ratio,"style_preset": style,"output_format":"png",},)if response.status_code !=200:raise Exception(f"API 错误: {response.status_code} - {response.text}")withopen(output_path,"wb")as f: f.write(response.content)print(f"已生成: {output_path}")return output_path # 使用示例if __name__ =="__main__": client = StabilityAIClient(api_key="sk-your-api-key") client.generate( prompt="A majestic dragon flying over a neon-lit cyberpunk city at night, ""highly detailed, cinematic lighting, 8k", aspect_ratio="16:9", style="cinematic", output_path="dragon_city.png",)

4.4 图像后处理管道

# postprocess.pyfrom PIL import Image, ImageEnhance, ImageFilter from pathlib import Path classImagePostProcessor:"""图像后处理:调整色彩、锐化、添加水印"""@staticmethoddefenhance(image_path:str, brightness:float=1.1, contrast:float=1.15, sharpness:float=1.3, output_path:str=None)->str:"""综合增强""" img = Image.open(image_path) img = ImageEnhance.Brightness(img).enhance(brightness) img = ImageEnhance.Contrast(img).enhance(contrast) img = ImageEnhance.Sharpness(img).enhance(sharpness) output_path = output_path or image_path.replace(".","_enhanced.") img.save(output_path, quality=95)return output_path @staticmethoddefadd_watermark(image_path:str, text:str="AI Generated", output_path:str=None)->str:"""添加水印"""from PIL import ImageDraw, ImageFont img = Image.open(image_path).convert("RGBA") overlay = Image.new("RGBA", img.size,(0,0,0,0)) draw = ImageDraw.Draw(overlay)# 半透明白色文字 draw.text((img.width -200, img.height -40), text, fill=(255,255,255,128),) img = Image.alpha_composite(img, overlay).convert("RGB") output_path = output_path or image_path.replace(".","_wm.") img.save(output_path, quality=95)return output_path @staticmethoddefcreate_grid(image_paths:list[str], cols:int=3, output_path:str="grid.png")->str:"""将多张图片拼成网格""" images =[Image.open(p)for p in image_paths] w, h = images[0].size rows =(len(images)+ cols -1)// cols grid = Image.new("RGB",(w * cols, h * rows),"white")for i, img inenumerate(images): row, col =divmod(i, cols) grid.paste(img,(col * w, row * h)) grid.save(output_path, quality=95)print(f"网格图已保存: {output_path}")return output_path 

5. Prompt 工程技巧

Prompt 结构

主体描述

风格关键词

质量修饰词

负面提示词

高质量 Prompt 模板

PROMPT_TEMPLATES ={"人物肖像":("{subject}, {style}, detailed face, expressive eyes, ""dramatic lighting, masterpiece, best quality, ultra detailed"),"风景":("{scene}, {mood}, volumetric lighting, god rays, ""landscape photography, 8k uhd, cinematic composition"),"产品设计":("{product}, minimalist design, studio lighting, ""white background, product photography, professional, 4k"),"动漫":("{character}, anime style, vibrant colors, ""detailed illustration, cel shading, masterpiece"),} NEGATIVE_PROMPTS ={"通用":"lowres, bad anatomy, bad hands, text, error, missing fingers, ""extra digit, cropped, worst quality, low quality, blurry","写实":"illustration, painting, drawing, art, sketch, anime, cartoon, ""CG, render, 3D, watermark, text, font, signature","动漫":"photo, realistic, 3d, western, ugly, duplicate, morbid, ""deformed, bad anatomy, blurry",}

6. 关键参数影响

35%20%15%15%10%5%不同参数对生成质量的影响权重Prompt 质量采样步数 (steps)CFG Scale采样器选择模型选择分辨率

参数推荐值说明
steps25-35步数越多细节越好,但边际递减且更慢
cfg_scale7-12越高越遵循 prompt,过高会过饱和
samplerDPM++ 2M Karras兼顾速度与质量
denoising_strength0.5-0.8图生图降噪强度,越高变化越大
seed-1随机种子,固定可复现

7. 完整使用流程

# complete_demo.pyfrom sd_client import StableDiffusionClient, GenerationConfig from stability_cloud import StabilityAIClient from postprocess import ImagePostProcessor defmain():# ===== 方式一:本地 SD WebUI ===== sd = StableDiffusionClient("http://127.0.0.1:7860")# 文生图 config = GenerationConfig( prompt="A serene Japanese garden with cherry blossoms, ""koi pond, stone bridge, golden hour, cinematic, 8k", negative_prompt="lowres, blurry, text, watermark", width=768, height=512, steps=30, cfg_scale=7.5,) paths = sd.txt2img(config)print(f"生成完成: {paths}")# 图生图if paths: new_paths = sd.img2img( init_image_path=paths[0], prompt="same scene but in autumn, orange and red leaves, snow", denoising_strength=0.6,)print(f"图生图完成: {new_paths}")# 超分辨率if paths: upscaled = sd.upscale(paths[0], scale=2)print(f"超分辨率完成: {upscaled}")# 后处理 pp = ImagePostProcessor()if paths: enhanced = pp.enhance(paths[0]) watermarked = pp.add_watermark(enhanced, text="AI Art")print(f"后处理完成: {watermarked}")# ===== 方式二:云端 API =====# cloud = StabilityAIClient("sk-xxx")# cloud.generate("A futuristic cityscape at sunset", "16:9", "cinematic")if __name__ =="__main__": main()

8. 总结

本文覆盖了 Stable Diffusion 图像生成的完整链路:

  1. 本地部署 SD WebUI 并开启 API 模式
  2. 封装 Python 客户端 支持文生图、图生图、局部重绘、超分辨率
  3. 云端 API 作为无 GPU 环境的替代方案
  4. Prompt 工程 模板化的提示词编写技巧
  5. 后处理管道 增强色彩、添加水印、拼图网格
生成速度参考:RTX 4090 生成 512x512 约 3-5 秒,512x768 约 5-8 秒。云端 API 约 10-20 秒。

Read more

Java Web HTML问卷调查系统系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】

Java Web HTML问卷调查系统系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】

摘要 随着互联网技术的快速发展,在线问卷调查系统已成为企业、教育机构和政府部门收集数据的重要工具。传统的纸质问卷调查方式效率低下,数据统计和分析过程繁琐,而基于Web的问卷调查系统能够实现问卷的快速创建、分发和数据分析,显著提升工作效率。此外,现代用户对系统的交互体验和响应速度提出了更高要求,因此开发一个高效、稳定且用户友好的在线问卷调查系统具有重要的现实意义。关键词:问卷调查系统、Web应用、数据收集、效率提升、用户交互。 本系统采用前后端分离架构,后端基于SpringBoot2框架搭建,结合MyBatis-Plus实现高效数据库操作,MySQL8.0作为数据存储方案,确保系统的高性能和可扩展性。前端使用Vue3框架开发,利用其响应式特性和组件化设计提升用户体验。系统核心功能包括问卷创建、问题管理、用户权限控制、数据统计与可视化分析等,同时支持多终端适配,满足不同场景下的使用需求。关键词:SpringBoot2、Vue3、MyBatis-Plus、MySQL8.0、前后端分离、数据可视化。 数据表设计 问卷信息数据表 问卷信息数据表用于存储用户创建的问卷基本信息,包括标题、

Python爬虫实战:高效解析Web of Science文献数据并导出CSV

1. 从零开始:为什么科研人员需要掌握Python爬虫 如果你是一名研究生、博士生,或者正在从事学术研究,我猜你一定有过这样的经历:为了写一篇综述或者做文献计量分析,你需要手动从Web of Science(WoS)上,一篇一篇地复制粘贴文献的标题、作者、摘要、关键词、发表年份、期刊信息……这个过程不仅枯燥乏味,而且极其容易出错,复制到第50篇的时候,你可能已经头晕眼花,甚至怀疑人生了。我当年读博的时候,为了分析一个领域近十年的研究趋势,需要收集上千篇文献数据,手动操作几乎是不可能完成的任务。正是这种“痛点”,让我下定决心研究如何用技术解放双手。 Python爬虫,听起来像是程序员专属的高深技术,但其实它离我们科研人员并不遥远。简单来说,爬虫就是一个能自动访问网页、抓取并整理信息的程序。对于Web of Science这样的学术数据库,虽然它提供了强大的检索功能,但批量导出详细数据(尤其是摘要、作者机构等)到本地进行深度分析,往往需要付费或者功能受限。自己写一个爬虫,就成了最高效、最灵活的解决方案。它能让你在喝杯咖啡的功夫,

LangChain 实战:大模型对话记忆模块(附完整代码 + Web 案例)

目录 前言:为什么需要对话记忆? 一、核心认知:原始 API vs LangChain 封装 1.1 原生 API 调用的痛点(无记忆) 1.2 LangChain 的价值:封装记忆与简化调用 二、LangChain 记忆模块核心组件 2.1 基础款:ConversationBufferMemory(完整记忆) 2.2 进阶款:窗口记忆与总结记忆 (1)ConversationBufferWindowMemory(窗口记忆) (2)ConversationSummaryMemory(总结记忆) 三、实战 1:LangChain 记忆链(ConversationChain) 四、实战 2:Streamlit 搭建带记忆的聊天

自动化打造信息影响力:用 Web Unlocker 和 n8n 打造你的自动化资讯系统

自动化打造信息影响力:用 Web Unlocker 和 n8n 打造你的自动化资讯系统

一、研究背景 在信息爆炸的时代,及时获取高质量行业资讯成为内容创作者、运营者以及研究者的刚需。无论是IT、AI领域的技术动态,还是招聘、人才市场的趋势新闻,第一时间掌握热点、总结观点并进行内容输出,正逐渐成为提升影响力与构建个人/组织品牌的关键手段。 为实现“日更内容”目标,很多人开始探索自动化的路径——使用爬虫工具定期抓取目标网站内容,借助 AI 模型自动生成摘要,再将结果推送至社群平台。这一流程的核心,是稳定、高效地获取网页数据,在实际操作中,却出现了很多问题: * 首先是出现了验证码,阻断自动化流程; * 紧接着是请求返回403 Forbidden,提示IP被封; * 最终是目标网站直接对我们常用IP段进行了临时封禁,哪怕切换机器或重启网络都无济于事。 按照检查方法,当处于非爬虫操作时,我们在F12控制台输入window.navigator.webdriver时,显示的是false,输入进去出现了刺眼的红色报错,而且显示也出现了True, “Failed to load resource: the server responded with