M2FP+Flask:快速搭建人体解析API服务
🧩 M2FP 多人人体解析服务 (WebUI + API)
在计算机视觉领域,人体解析(Human Parsing)是一项关键的细粒度语义分割任务,旨在将人体图像中的每个像素精确分类到具体的身体部位类别中。与传统的人体姿态估计不同,人体解析不仅识别关键点,还能对头发、面部、上衣、裤子、鞋子等多达数十个语义区域进行像素级标注。
近年来,随着深度学习的发展,基于Transformer架构的Mask2Former模型在多个视觉任务中表现出色。而M2FP(Mask2Former-Parsing)正是基于该框架专为人体解析优化的高性能模型,由ModelScope平台提供支持。它不仅能处理单人场景,更擅长应对多人重叠、遮挡、复杂光照等现实挑战,广泛应用于虚拟试衣、智能安防、AR/VR内容生成等领域。
本项目封装了完整的M2FP 模型推理流程 + Flask Web服务 + 可视化拼图算法,构建了一个开箱即用的多人人体解析系统。无论你是否有GPU设备,都可以通过CPU版本快速部署并调用API服务。
📖 项目简介
本镜像基于 ModelScope 的M2FP (Mask2Former-Parsing)模型构建。
M2FP 是目前业界领先的语义分割算法,专注于多人人体解析任务。它能精准识别图像中多个人物的不同身体部位(如面部、头发、上衣、裤子、四肢等),并输出像素级的分割掩码。
已集成Flask WebUI,内置自动拼图算法,将模型输出的离散 Mask 实时合成为可视化的彩色分割图。
💡 核心亮点: 1.环境极度稳定:已解决 PyTorch 2.x 与 MMCV 的底层兼容性难题,锁定PyTorch 1.13.1 + MMCV-Full 1.7.1黄金组合,零报错。 2.可视化拼图:针对模型返回的原始 Mask 列表,内置了后处理算法,自动叠加颜色并生成完整的语义分割图。 3.复杂场景支持:基于 ResNet-101 骨干网络,能够有效处理多人重叠、遮挡等复杂场景。 4.CPU 深度优化:针对无显卡环境进行了推理加速,无需 GPU 即可快速出图。
🛠️ 技术架构设计解析
1. 模型核心:M2FP (Mask2Former-Parsing)
M2FP 是一种基于Mask2Former 架构改进的专用人体解析模型,其本质是一个解码器增强型的Transformer分割网络。相比传统FCN或U-Net结构,它引入了掩码注意力机制(Mask Attention)和动态卷积头(Dynamic Convolution Head),显著提升了小区域(如手指、眼睛)和边界模糊区域的分割精度。
✅ 关键特性:
- 输入分辨率:默认支持
1024×512或512×512图像 - 输出类别数:共20 类人体部位标签
- 头部(Head)、头发(Hair)、左/右眼(Left/Right Eye)、鼻子(Nose)、嘴巴(Mouth)
- 上身衣物(Upper Clothing)、下身衣物(Lower Clothing)、连体服(Dress)、外套(Coat)
- 左/右手臂(Left/Right Arm)、左/右腿(Left/Right Leg)、左/右手(Hand)、左/右脚(Foot)
背包(Backpack)、帽子(Hat)、围巾(Scarf)、鞋子(Shoes)、其他配饰(Accessory)
骨干网络:ResNet-101 + FPN 特征金字塔,兼顾深层语义与浅层细节
- 推理速度(CPU):约 8~12 秒/张(Intel i7 级别处理器)
该模型已在大量真实街景数据集(如LIP、CIHP)上预训练,具备良好的泛化能力。
2. 后端服务:Flask API 设计
为了便于集成和远程调用,我们使用Flask构建轻量级Web服务,暴露两个核心接口:
| 接口路径 | 方法 | 功能说明 | |--------|------|---------| |/| GET | 返回WebUI页面 | |/api/predict| POST | 接收图片文件,返回解析结果 |
📂 目录结构概览
m2fp-flask-app/ ├── app.py # Flask主程序 ├── models/ # 模型权重缓存目录 ├── static/output/ # 输出图像存储路径 ├── utils/parser.py # M2FP模型加载与推理逻辑 ├── utils/visualizer.py # 彩色拼图生成模块 └── templates/index.html # 前端交互页面💻 实践应用:从零部署一个可运行的人体解析服务
步骤一:环境准备
由于项目已预先打包好依赖项,推荐直接使用提供的Docker镜像启动服务。若需本地安装,请确保满足以下条件:
Python == 3.10 torch == 1.13.1+cpu torchaudio == 0.13.1 torchvision == 0.14.1+cpu mmcv-full == 1.7.1 modelscope == 1.9.5 opencv-python >= 4.6.0 Flask == 2.3.3⚠️ 注意:必须使用
torch 1.13.1及对应版本的mmcv-full,否则会出现_ext扩展缺失或tuple index out of range错误。
可通过如下命令安装核心依赖:
pip install torch==1.13.1+cpu torchvision==0.14.1+cpu torchaudio==0.13.1 --extra-index-url https://download.pytorch.org/whl/cpu pip install mmcv-full==1.7.1 -f https://download.openmmlab.com/mmcv/dist/cpu/torch1.13.0/index.html pip install modelscope==1.9.5 flask opencv-python步骤二:核心代码实现
1. 模型加载与推理封装(utils/parser.py)
# utils/parser.py from modelscope.pipelines import pipeline from modelscope.utils.constant import Tasks class M2FPParser: def __init__(self, model_id='damo/cv_resnet101_image-multi-human-parsing'): self.parser = pipeline(task=Tasks.image_multi_human_parsing, model=model_id) def predict(self, image_path): result = self.parser(image_path) return result['output'] # List of masks and labels此模块利用 ModelScope 提供的统一Pipeline接口,屏蔽底层复杂性,一行代码即可完成模型加载与推理。
2. 可视化拼图算法实现(utils/visualizer.py)
模型返回的是多个二值Mask和对应的类别ID,我们需要将其合成为一张带颜色的语义图。
# utils/visualizer.py import cv2 import numpy as np # 预定义20类颜色映射表 (BGR格式) COLOR_MAP = [ [0, 0, 0], # 背景 - 黑色 [255, 0, 0], # 头发 - 红色 [0, 255, 0], # 上衣 - 绿色 [0, 0, 255], # 裤子 - 蓝色 [255, 255, 0], # 连衣裙 - 青色 [255, 0, 255], # 外套 - 品红 [0, 255, 255], # 鞋子 - 黄色 [128, 64, 128], # 帽子 [244, 35, 232], # 围巾 [70, 70, 70], # 背包 [102, 102, 156], # 左臂 [190, 153, 153], # 右臂 [153, 153, 153], # 左腿 [250, 170, 30], # 右腿 [220, 220, 0], # 左手 [107, 142, 35], # 右手 [152, 251, 152], # 左脚 [70, 130, 180], # 右脚 [220, 20, 60], # 配饰 [255, 128, 0] # 面部 ] def blend_masks_to_image(masks, labels, original_shape): h, w = original_shape[:2] output_img = np.zeros((h, w, 3), dtype=np.uint8) for mask, label in zip(masks, labels): color = COLOR_MAP[label % len(COLOR_MAP)] colored_mask = np.stack([mask * c for c in color], axis=-1) output_img = np.where(colored_mask > 0, colored_mask, output_img) return output_img🔍技术要点解析: - 使用 NumPy 的
np.where实现非覆盖式叠加,避免后绘制的mask遮挡先绘制的区域 - 支持任意数量的人物实例,按顺序分配颜色 - 若类别超出20类,采用模运算循环复用颜色
3. Flask 主服务逻辑(app.py)
# app.py from flask import Flask, request, send_from_directory, render_template import os import uuid from PIL import Image from utils.parser import M2FPParser from utils.visualizer import blend_masks_to_image app = Flask(__name__) parser = M2FPParser() UPLOAD_FOLDER = 'static/uploads' OUTPUT_FOLDER = 'static/output' os.makedirs(UPLOAD_FOLDER, exist_ok=True) os.makedirs(OUTPUT_FOLDER, exist_ok=True) @app.route('/') def index(): return render_template('index.html') @app.route('/api/predict', methods=['POST']) def predict(): if 'image' not in request.files: return {'error': 'No image uploaded'}, 400 file = request.files['image'] if file.filename == '': return {'error': 'Empty filename'}, 400 # 保存上传图片 input_path = os.path.join(UPLOAD_FOLDER, file.filename) img = Image.open(file.stream) img.save(input_path) # 模型推理 try: result = parser.predict(input_path) masks = result['masks'] # List[np.array(H,W)] labels = result['labels'] # List[int] orig_shape = img.size[::-1] + (3,) # (W,H) -> (H,W,C) # 生成可视化图像 vis_image = blend_masks_to_image(masks, labels, orig_shape) output_path = os.path.join(OUTPUT_FOLDER, str(uuid.uuid4())[:8] + '.png') cv2.imwrite(output_path, vis_image) return { 'result_url': f'/static/output/{os.path.basename(output_path)}', 'num_persons': len(set(labels)), # 统计人数 'classes_detected': list(set(labels)) } except Exception as e: return {'error': str(e)}, 500 if __name__ == '__main__': app.run(host='0.0.0.0', port=7860, debug=False)✅工程化亮点: - 使用
uuid生成唯一输出文件名,防止并发冲突 - 自动创建缺失目录,提升鲁棒性 - 异常捕获机制保障服务不中断 - 返回JSON包含元信息(人数、检测类别),便于前端展示统计信息
步骤三:前端界面交互(templates/index.html)
HTML 页面采用简洁布局,包含上传按钮、原图预览区和结果展示区,并通过Ajax提交请求:
<!-- templates/index.html --> <!DOCTYPE html> <html> <head> <title>M2FP 人体解析服务</title> <style> body { font-family: Arial; text-align: center; margin-top: 40px; } .container { max-width: 1200px; margin: 0 auto; } .image-box { display: inline-block; margin: 20px; width: 45%; } img { max-width: 100%; height: auto; border: 1px solid #ddd; } </style> </head> <body> <div class="container"> <h1>🧩 M2FP 多人人体解析服务</h1> <form id="uploadForm" enctype="multipart/form-data"> <input type="file" name="image" accept="image/*" required /> <button type="submit">上传并解析</button> </form> <div class="image-box"> <h3>原始图像</h3> <img id="inputImage" src="" style="display:none;" /> </div> <div class="image-box"> <h3>解析结果</h3> <img id="outputImage" src="" style="display:none;" /> <p id="info"></p> </div> </div> <script> document.getElementById('uploadForm').onsubmit = async (e) => { e.preventDefault(); const formData = new FormData(e.target); const res = await fetch('/api/predict', { method: 'POST', body: formData }); const data = await res.json(); if (data.error) { alert('Error: ' + data.error); } else { document.getElementById('inputImage').src = URL.createObjectURL(e.target.image.files[0]); document.getElementById('inputImage').style.display = 'block'; document.getElementById('outputImage').src = data.result_url; document.getElementById('outputImage').style.display = 'block'; document.getElementById('info').innerText = `检测到 ${data.num_persons} 人,涉及 ${data.classes_detected.length} 类身体部位`; } }; </script> </body> </html>🚀 使用说明
- 镜像启动后,点击平台提供的HTTP按钮。
- 点击“上传图片”,选择一张包含人物的照片(单人或多人均可)。
- 等待几秒后,右侧将显示解析后的结果:
- 不同颜色代表不同的身体部位(如红色代表头发,绿色代表衣服等)。
- 黑色区域代表背景。
📦 依赖环境清单
| 组件 | 版本 | 说明 | |------|------|------| | Python | 3.10 | 基础运行环境 | | ModelScope | 1.9.5 | 模型加载与Pipeline管理 | | PyTorch | 1.13.1+cpu | CPU版推理引擎,修复兼容性问题 | | MMCV-Full | 1.7.1 | OpenMMLab核心库,解决_ext缺失错误 | | OpenCV | >=4.6.0 | 图像读写与可视化合成 | | Flask | 2.3.3 | 轻量级Web服务框架 |
💡避坑指南: - 不要升级 PyTorch 至 2.0+,会导致
mmcv._ext加载失败 - 若出现ImportError: cannot import name 'resize' from 'mmcv',请确认安装的是mmcv-full而非mmcv- Windows 用户建议使用 WSL 或 Docker 避免编译问题
🎯 性能优化建议(CPU场景)
尽管M2FP原生为GPU设计,但我们通过以下手段实现了CPU下的高效推理:
- 图像降采样预处理:在送入模型前将图像缩放到
512x512,减少计算量 - 禁用梯度计算:使用
torch.no_grad()防止内存泄漏 - 模型半精度量化(可选):对CPU进一步启用INT8量化(需ONNX支持)
- 异步队列处理:对于高并发场景,可引入Celery或Redis做任务队列调度
未来还可结合ONNX Runtime或TorchScript进行模型固化,进一步提升推理效率。
📊 应用场景拓展
| 场景 | 应用方式 | 示例 | |------|----------|-------| | 虚拟试衣 | 分离上衣/裤子区域,替换纹理 | 更换T恤图案 | | 智能监控 | 检测异常着装行为 | 安保人员识别 | | 医疗康复 | 跟踪肢体运动轨迹 | 中风患者动作评估 | | 内容审核 | 识别敏感部位暴露 | 视频平台合规过滤 | | AR滤镜 | 精准贴图到面部/头发 | 美颜App特效 |
🏁 总结与最佳实践建议
本文详细介绍了如何基于M2FP 模型 + Flask 框架快速搭建一个稳定可用的多人人体解析API服务。该项目具有以下优势:
- ✅开箱即用:完整封装模型、WebUI、可视化逻辑
- ✅跨平台兼容:纯CPU运行,适合边缘设备或低成本部署
- ✅易于扩展:提供标准RESTful API,方便集成至现有系统
- ✅高度可定制:颜色方案、类别映射、输出格式均可修改
✅ 推荐最佳实践:
- 生产环境建议使用Nginx + Gunicorn + Flask替代内置开发服务器
- 定期清理 output 文件夹,避免磁盘占满
- 增加请求频率限制,防止恶意刷图
- 前端添加loading动画,改善用户体验(当前响应时间约8~12秒)
🌐 下一步你可以尝试: - 将服务容器化为Docker镜像发布到私有Registry - 添加gRPC接口以支持更高性能调用 - 结合OpenPose实现“姿态+解析”联合分析
现在,你已经拥有了一个功能完整、工程稳定的人体解析服务框架——只需上传图片,即可获得专业级的像素级人体分割结果。