- 人工智能
- 媒体生成
- 计算机视觉
- 深度学习
【免费下载链接】sd-webui-controlnet
WebUI extension for ControlNet
本篇指南聚焦 sd-webui-controlnet 仓库中位于 tests/web_api/full_coverage/ 的 Full Coverage 测试目录:它们是一组只在本机运行、要求全部模型就绪的端到端 Web API 回归测试,通过设置CONTROLNET_TEST_FULL_COVERAGE环境变量即可启用。读完本文,你将掌握该测试套件的启用方式、模板化测试基础设施(APITestTemplate)的工作原理,以及深度估计、局部重绘(Inpaint)和 IP-Adapter 三大类全量用例的具体覆盖点,并能据此在本机复现整套回归流程。
Full Coverage 测试是什么:定位与设计动机
tests/web_api/full_coverage/README.md 对该目录给出了精炼的定义:
Full Coverage Tests —— Tests that only run locally with all models available. Set environment variable
CONTROLNET_TEST_FULL_COVERAGEto any value to enable these tests.
翻译过来即:Full Coverage 测试是一组只在本机运行的测试,前提是本机已备齐全部模型;只要把环境变量CONTROLNET_TEST_FULL_COVERAGE设置为任意值即可启用。
它与常规 Web API 测试(tests/web_api/ 下的用例)的核心差异在于运行环境和资源前提:
- 常规 API 测试可在 CI/CPU 环境执行(tests/web_api/template.py 中的
disable_in_cq装饰器会跳过不适用于 CQ 运行的用例,且is_cq_run模式下会自动把steps降为 3、宽高降为 64 以加速); - Full Coverage 测试则刻意不进入 CI:它们需要逐一下载、加载并推理大量 ControlNet 模型(含 SD15 与 SDXL 两代模型家族),只有本机资源充裕时才有意义。
目录本身的结构(共 6 个文件)清晰地体现了职责划分:
| 文件 | 职责 |
|---|---|
| README.md | 套件说明与启用开关 |
| template.py | 模板化测试基础设施:图片读取、载荷构造、结果对比 |
| depth_test.py | 深度估计类预处理器与模型的组合矩阵测试 |
| inpaint_test.py | 局部重绘/扩展绘制的多模式、多缩放策略测试 |
| ipadapter_test.py | IP-Adapter 系列(含 FaceID)与多输入组合测试 |
__init__.py | 包标识(空文件) |
启用方式:CONTROLNET_TEST_FULL_COVERAGE 环境变量
启用机制在 template.py 中实现,仅一行判断:
is_full_coverage = os.environ.get("CONTROLNET_TEST_FULL_COVERAGE", None) is not None也就是说,只要该环境变量被设置(值是什么并不重要,空字符串也算),is_full_coverage即为True。各测试类的setUp会据此决定是否运行,例如:
class TestInpaintFullCoverage(unittest.TestCase): def setUp(self): if not is_full_coverage: pytest.skip()未设置该变量时,所有 Full Coverage 用例都会被pytest.skip()直接跳过,这正是 README 所谓"启用"的准确含义——它并非默认运行的测试。
启用后还需配合另一个变量CONTROLNET_TEST_SD_VERSION决定被测的模型家族(同样定义于 template.py):
sd_version = StableDiffusionVersion( int(os.environ.get("CONTROLNET_TEST_SD_VERSION", StableDiffusionVersion.SD1x.value)) )StableDiffusionVersion枚举的取值为:UNKNOWN = 0、SD1x = 1、SD2x = 2、SDXL = 3(默认 1,即 SD1.x)。这与 tests/README.md 中的说明一致:1 对应 SD1.x、2 对应 SD2.x、3 对应 SDXL。IP-Adapter 用例会依据该值自动选择 SD15 或 SDXL 的模型清单,而深度用例则会主动跳过 SDXL(见 depth_test.py 的注释 "TODO test SDXL")。
测试基础设施:APITestTemplate 与模板化载荷
所有 Full Coverage 用例都复用 template.py 中定义的APITestTemplate类,它把"构造请求 → 调用 A1111 Web API → 保存/对比输出图"封装成一行调用。
默认 ControlNet 单元参数
用例未覆盖的单元字段全部取自default_unit字典:
default_unit = { "control_mode": "Balanced", # 控制模式:平衡 "enabled": True, # 启用该单元 "guidance_end": 1, # 引导结束步数比例 "guidance_start": 0, # 引导开始步数比例 "low_vram": False, # 低显存模式 "pixel_perfect": True, # 像素完美(自动匹配分辨率) "processor_res": 512, # 预处理器分辨率 "resize_mode": "Crop and Resize", # 缩放模式:裁剪并缩放 "threshold_a": -1, # 阈值 a(-1 表示自动/默认) "threshold_b": -1, # 阈值 b(-1 表示自动/默认) "weight": 1, # 控制强度 }可见这套全量测试默认采用"Balanced 控制模式 + 像素完美开启 + Crop and Resize 缩放"的经典配置;threshold_a/b传-1则交由底层预处理器回退到各自默认值(常规 API 测试中-100会被判定为非法值并打印告警,见 tests/web_api/generation_test.py)。
生成请求模板
模板同时内置了img2img_payload与txt2img_payload两套完整请求体,核心字段包括:
- 通用:
batch_size: 1、cfg_scale: 7、steps: 10、sampler_name: "Euler a"、seed: 42、正向提示词"(masterpiece: 1.3), (highres: 1.3), best quality,"; - img2img 专属:
denoising_strength: 0.75、resize_mode: 0、mask 相关(mask_blur: 4、inpaint_full_res: 0等); - txt2img 专属:高分辨率修复(
enable_hr: False、hr_upscaler: "Latent"、hr_scale: 2)与tiling: False等。
构造时用{**base_payload, **payload_overrides}合并覆盖,ControlNet 单元则统一写入alwayson_scripts["ControlNet"]["args"]列表,天然支持多单元场景(template.py)。
执行与结果对比
exec()的核心流程是:向http://localhost:7860/sdapi/v1/{txt2img|img2img}发起 POST 请求,取回 JSON 中的images(base64 PNG),解码后写入目标目录,然后与期望图逐像素对比(template.py):
- 写期望模式:当环境变量
CONTROLNET_SET_EXP为"True"(默认值)时,输出图写入expectations/目录,作为"黄金标准"; - 回归验证模式:当
CONTROLNET_SET_EXP非"True"时,输出图写入results/test_result_{时间戳}/目录,并与expectations/中的同名图比对。
对比算法expect_same_image(template.py)使用 OpenCV 计算像素差,要求np.isclose(img1, img2, rtol=0.5, atol=1)的匹配像素占比不低于 95%才算通过;失败时还会把超过阈值 30 的差异像素高亮保存为*_diff.png,便于人工排查。
此外,测试资源图片统一从 tests/web_api/ 的images目录加载:1girl.png、mask.png、mask_small.png、portrait/人像集、living_room.webp客厅图等,均通过cv2.imread+ base64 编码为字符串嵌入请求体。
深度估计全量用例:模块 × 模型组合矩阵
depth_test.py 中的TestDepthFullCoverage将 5 个深度预处理器与 3 个深度模型做笛卡尔积遍历:
general_depth_modules = [ "depth", "depth_leres", "depth_leres++", "depth_anything", "depth_anything_v2", ] hand_refiner_module = "depth_hand_refiner" general_depth_models = [ "control_sd15_depth_anything [48a4bc3a]", "control_v11f1p_sd15_depth [cfd03158]", "t2iadapter_depth_sd15v2 [3489cd37]", ] hand_refiner_model = "control_sd15_inpaint_depth_hand_fp16 [09456e54]"每个子用例命名为depth_txt2img_{module}_{model},以txt2img方式生成,payload 覆盖为steps: 20、width: 768、height: 512,输入图固定为living_room_img,并附带general_negative_prompt(一组高强度负面提示词,权重最高达(fused fingers:1.61051))。值得注意的是这里调用exec(result_only=False),即保存并对比全部输出图,而非只取第一张。depth_hand_refiner模块及其配套的control_sd15_inpaint_depth_hand_fp16模型也在清单中,用于验证手部深度细化链路。
局部重绘全量用例:双生成类型 × 三种缩放 × 三种模块
inpaint_test.py 是覆盖维度最密集的测试文件,test_inpaint同时遍历:
- 生成类型:
img2img(mask 放在 A1111 请求体的init_images/mask字段)与txt2img(mask 放在 ControlNet 单元的image字段内,格式为{"image": ..., "mask": ...}); - 缩放模式:
Just Resize(不保持比例直接缩放)、Crop and Resize、Resize and Fill,且针对每种模式给出了对应的输出画布尺寸:Crop 对应 512×512(内切适配)、Resize and Fill 对应 768×768(外切填充),img2img 模式下同步设置 A1111 侧的resize_mode; - 重绘模块:
inpaint_only、inpaint、inpaint_only+lama,模型统一为control_v11p_sd15_inpaint [ebff9138]。
其余用例则分别锁定特定语义,值得逐条关注:
| 用例 | 验证点 |
|---|---|
test_inpaint_no_mask | 不提供 mask 时重绘应失败,且输出中不应包含 ControlNet 检测图 |
test_inpaint_double_mask | A1111 请求体与 ControlNet 单元同时提供 mask 时,应优先使用 ControlNet 单元的 mask(对应 mask_small 与 mask 尺寸不同的可辨识场景) |
test_img2img_mask_on_unit | 仅把 mask 放在单元上(inpaint_global_harmonious的用法场景) |
test_outpaint_without_mask | 使用inpaint_only+lama在无 mask条件下向外扩图,img2img 与 txt2img 各验证一次,画布扩至 768×768 |
test_inpaint_crop | 结合 A1111 的inpaint_full_res: True,对比 ControlNet 单元inpaint_crop_input_image: True/False两种裁剪行为的输出差异 |
这些用例印证了 ControlNet 局部重绘的核心行为约定:mask 既可在 A1111 侧传入,也可作为单元输入传入;后者具备更高优先级,并且inpaint_only+lama模块可以脱离 mask 独立完成扩图任务(Lama 模型负责填充缺失区域,见 scripts/preprocessor/lama_inpaint.py 与 annotator/lama/)。
IP-Adapter 全量用例:SD15/SDXL 模型族与多输入组合
ipadapter_test.py 覆盖了 IP-Adapter 的两大模型家族。AdapterSetting命名元组封装了module(预处理器)与model(适配器模型),并支持附加 LoRA:
sd15_normal = AdapterSetting("ip-adapter_clip_sd15", "ip-adapter_sd15 [6a3f6166]") sd15_light = AdapterSetting("ip-adapter_clip_sd15", "ip-adapter_sd15_light [be1c9b97]") sd15_plus_face = AdapterSetting("ip-adapter_clip_sd15", "ip-adapter-plus-face_sd15 [71693645]") sd15_full_face = AdapterSetting("ip-adapter_clip_sd15", "ip-adapter-full-face_sd15 [852b9843]") sdxl_normal = AdapterSetting("ip-adapter_clip_sdxl", "ip-adapter_sdxl [d5d53548]") sdxl_vit = AdapterSetting("ip-adapter_clip_sdxl_plus_vith", "ip-adapter_sdxl_vit-h [75a08f84]") sdxl_plus_vit = AdapterSetting("ip-adapter_clip_sdxl_plus_vith", "ip-adapter-plus_sdxl_vit-h [f1f19f7d]") sdxl_plus_vit_face = AdapterSetting("ip-adapter_clip_sdxl_plus_vith", "ip-adapter-plus-face_sdxl_vit-h [c60d7d48]")测试类依据sd_version自动选择清单:SD1.x 下测 4 个 SD15 变体,SDXL 下测 4 个 SDXL 变体。所有用例均以 txt2img 生成 512×512 图、20 步,且额外叠加一个 openpose 单元固定姿态,以便在不同设置之间进行公平的图对比。正向提示词使用"1girl, simple background, (white_background: 1.2), portrait",并分别以"带general_negative_prompt/ 不带负面提示词"两种条件各跑一遍。
三个方法分别验证 IP-Adapter 的输入形态:
test_adapter:单张人像输入;test_adapter_multi_inputs:portrait/目录全部人像作为多个独立单元输入,每个单元权重均分为1 / len(portrait_imgs);test_adapter_real_multi_inputs:一张图内包含多张参考图的列表("image": [{"image": img} for img in portrait_imgs]),验证"真实多输入"格式。
FaceID 变体
TestIPAdapterFaceIdFullCoverage进一步覆盖人脸身份保持系列,SD1.x 下包括ip-adapter-faceid_sd15(配ip-adapter-faceid_sd15_lora)、faceid-plus、faceid-plusv2与faceid-portrait四种设置,SDXL 下为ip-adapter-faceid_sdxl;LoRA 通过提示词<lora:{name}:0.6>注入(AdapterSetting.lora_prompt属性)。其多输入用例同样分为多单元均分权重与列表式多输入两种形态。
本地运行流程:从启动测试服务到执行全量用例
结合 tests/README.md 的说明,完整本地流程如下(注意当前工作目录必须是 A1111 根目录):
- 安装测试依赖:
pip install -r requirements-test.txt; - 启动测试服务(CPU 环境即可,需要
--api-server-stop支持自动关停):
python -m coverage run \ --data-file=.coverage.server \ launch.py \ --skip-prepare-environment \ --skip-torch-cuda-test \ --test-server \ --do-not-download-clip \ --no-half \ --disable-opt-split-attention \ --use-cpu all \ --api-server-stop- 启用 Full Coverage 并指定模型家族:设置
CONTROLNET_TEST_FULL_COVERAGE=1(任意值均可)与CONTROLNET_TEST_SD_VERSION(1=SD1.x,2=SD2.x,3=SDXL);首次运行保持CONTROLNET_SET_EXP=True以生成期望图; - 执行测试:
python -m pytest -vv --junitxml=test/results.xml \ --cov ./extensions/sd-webui-controlnet \ --cov-report=xml \ --verify-base-url ./extensions/sd-webui-controlnet/tests- 查看覆盖率:文本报告
python -m coverage report -i,HTML 报告python -m coverage html -i。
另外 tests/conftest.py 会预先设置IGNORE_CMD_ARGS_ERRORS=1,避免 WebUI 误解析 pytest 的命令行参数导致测试启动失败。
使用建议与注意事项
- 期望图是团队的回归资产:
expectations/目录下的 PNG 是后续每次运行对比的基准,变更模型版本或预处理器行为时应有意识地重新生成(将CONTROLNET_SET_EXP置为"True"); - 结果目录自带时间戳:
results/test_result_{YYYYMMDD-HHMMSS}/按运行时刻隔离,失败时同时产出_diff.png差异高亮图,方便定位是预处理器输出变化还是采样器行为漂移; - 资源开销大是设计使然:本套件要求所有模型就绪,深度用例约 15 组组合、重绘用例约 18 组组合、IP-Adapter 用例每设置各跑 2 类负面条件,在 GPU 环境下运行更为实际;若要快速冒烟,可回归常规 tests/web_api/ 用例集。
总的来说,Full Coverage 测试套件以极简的开关设计(一个环境变量)承载了仓库最核心的三类模型能力的端到端回归验证,是评估 sd-webui-controlnet 在"全部模型就绪"前提下行为是否稳定的重要本地测试手段。
- 人工智能
- 媒体生成
- 计算机视觉
- 深度学习
【免费下载链接】sd-webui-controlnet
WebUI extension for ControlNet
相关推荐
wvp-GB28181-pro GB28181 视频平台:Docker 三步部署与生产避坑指南
wvp GB28181 pro GB28181 视频平台:Docker 三步部署与生产避坑指南 wvp GB28181 pro 是一个开箱即用的 GB28181
后端音视频前端axe-core 全量集成测试(Full Integration Tests)运行机制与实战指南
axe core 全量集成测试(Full Integration Tests)运行机制与实战指南 导读 :本文以 axe core 仓库中 test/integ
测试Agent Zero 配置全指南:settings.json、LLM 角色体系与 A0_SET_ 环境变量覆盖机制
Agent Zero 配置全指南:settings.json、LLM 角色体系与 A0_SET_ 环境变量覆盖机制 Agent Zero(A0)将全部运行配置收
人工智能大模型AI AgentAgent 框架自主智能体多智能体工具调用MCP 服务浏览器控制
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考