如何扩展M2FP功能?添加新类别或修改输出格式指南
📖 项目背景与核心价值
在计算机视觉领域,人体解析(Human Parsing)是一项关键的细粒度语义分割任务,旨在将人体分解为多个语义明确的身体部位。M2FP(Mask2Former-Parsing)作为基于 ModelScope 平台构建的多人人体解析服务,凭借其高精度、强鲁棒性和易用性,已成为无GPU环境下部署人体解析的理想选择。
该服务不仅集成了强大的ResNet-101 + Mask2Former架构以应对复杂场景中的遮挡与重叠问题,还通过内置的Flask WebUI和自动拼图算法实现了从原始掩码到可视化结果的端到端输出。用户无需关心底层依赖冲突——项目已锁定PyTorch 1.13.1 + MMCV-Full 1.7.1的稳定组合,彻底规避了tuple index out of range和_ext 缺失等常见报错。
但随着应用场景的多样化,开发者常面临两个核心需求: -如何添加新的身体部位类别?-能否自定义输出的颜色映射或文件格式?
本文将围绕这两个工程实践问题,提供一套完整、可落地的功能扩展方案。
🔧 扩展方向一:添加新类别支持
为什么需要新增类别?
标准 M2FP 模型通常预定义了如“头发”、“面部”、“左臂”、“右腿”等约 20 类人体部位。但在特定应用中(如虚拟试衣、医疗康复监测),可能需要识别更精细的子区域,例如: - “耳环佩戴区域” - “手腕纹身区” - “脚踝绑带”
虽然模型本身是训练好的闭集分类器,无法直接识别未见过的类别,但我们可以通过后处理标注机制和标签映射增强的方式,在推理阶段实现逻辑上的“新增类别”。
方案设计:基于 ROI 提取 + 外部检测器联动
由于不能重新训练模型来增加输出通道,我们采用一种模块化扩展策略:
思路:利用现有分割结果提取感兴趣区域(ROI),再接入轻量级外部检测模型判断是否包含新类别特征。
步骤详解
- 获取基础分割结果```python from modelscope.pipelines import pipeline from modelscope.utils.constant import Tasks
parsing_pipeline = pipeline(task=Tasks.image_parsing, model='damo/cv_resnet101_image-parsing_m2fp') result = parsing_pipeline('input.jpg') masks = result['masks'] # list of binary masks for each part labels = result['labels'] # corresponding label names ```
- 定位目标区域(如手部)并裁剪```python import cv2 import numpy as np
def extract_roi(image, mask, padding=20): y_indices, x_indices = np.where(mask) if len(x_indices) == 0 or len(y_indices) == 0: return None x_min, x_max = np.min(x_indices), np.max(x_indices) y_min, y_max = np.min(y_indices), np.max(y_indices)
# 添加边缘缓冲 h, w = image.shape[:2] x_min = max(0, x_min - padding) y_min = max(0, y_min - padding) x_max = min(w, x_max + padding) y_max = min(h, y_max + padding) return image[y_min:y_max, x_min:x_max]# 假设我们要分析“右手”是否有手表 hand_label = 'right_hand' hand_mask = None for m, lbl in zip(masks, labels): if lbl == hand_label: hand_mask = m break
if hand_mask is not None: hand_roi = extract_roi(original_image, hand_mask, padding=15) ```
- 调用外部小模型进行新类别判断```python # 示例:使用一个预训练的手表检测模型(ONNX 或 TorchScript) watch_detector = cv2.dnn.readNetFromONNX('watch_detect.onnx')
blob = cv2.dnn.blobFromImage(hand_roi, 1/255.0, (64, 64), swapRB=True) watch_detector.setInput(blob) output = watch_detector.forward()
has_watch = output[0][0] > 0.5 # 阈值判断 ```
- 更新最终输出标签
python extended_labels = labels.copy() if has_watch: extended_labels.append('wearing_watch_on_right_hand')
✅优势:无需重训主模型,灵活适配业务需求
⚠️局限:依赖额外模型,增加推理延迟
🎨 扩展方向二:自定义输出格式与颜色映射
默认情况下,M2FP 输出的拼图使用固定颜色表(Color Map),且仅支持 PNG 可视化图像输出。但在实际系统集成中,往往需要: - 更丰富的输出格式(JSON、Numpy Array、COCO 格式) - 自定义颜色主题(适配品牌 UI) - 透明背景支持(用于 AR 合成)
1. 修改颜色映射表(Colormap)
原始颜色映射通常定义在一个静态字典中,位于utils/visualize.py或类似路径。
查找并替换 colormap
# 原始默认 colormap(示例) DEFAULT_COLORMAP = { 'background': (0, 0, 0), 'hair': (255, 0, 0), 'face': (0, 255, 0), 'upper_clothes': (0, 0, 255), 'lower_clothes': (255, 255, 0), # ... 其他类别 }自定义暖色调风格
CUSTOM_COLORMAP = { 'background': (0, 0, 0), 'hair': (139, 69, 19), # 深棕 'face': (255, 218, 185), # 肤色 'upper_clothes': (255, 140, 0), # 橙色 'lower_clothes': (128, 0, 128), # 紫色 'left_arm': (0, 255, 255), # 青色 'right_arm': (255, 192, 203), # 粉红 # 可继续扩展... }应用于拼图函数
def apply_colormap(masks, labels, colormap=CUSTOM_COLORMAP): h, w = masks[0].shape output_img = np.zeros((h, w, 3), dtype=np.uint8) for mask, label in zip(masks, labels): color = colormap.get(label, (128, 128, 128)) # 默认灰 output_img[mask] = color return output_img💡 提示:可在 WebUI 中加入“主题切换”按钮,动态加载不同 colormap。
2. 支持多种输出格式导出
为了满足前后端系统对接需求,建议扩展 API 接口以支持多格式响应。
新增输出类型枚举
from enum import Enum class OutputFormat(Enum): PNG = "png" JSON = "json" NUMPY = "npy" COCO_RLE = "coco_rle"Flask 路由扩展
@app.route('/parse', methods=['POST']) def parse_image(): file = request.files['image'] fmt = request.form.get('format', 'png').lower() img_bytes = file.read() nparr = np.frombuffer(img_bytes, np.uint8) image = cv2.imdecode(nparr, cv2.IMREAD_COLOR) result = parsing_pipeline(image) if fmt == 'json': return jsonify({ "labels": result['labels'], "scores": [float(s) for s in result['scores']], "bbox": [[int(b) for b in box] for box in result['boxes']] if 'boxes' in result else None, "width": image.shape[1], "height": image.shape[0] }) elif fmt == 'npy': combined_mask = np.stack(result['masks'], axis=-1) # shape: H x W x N_classes buffer = io.BytesIO() np.save(buffer, combined_mask) buffer.seek(0) return send_file(buffer, mimetype='application/octet-stream', as_attachment=True, download_name='mask.npy') elif fmt == 'coco_rle': rles = [] for mask in result['masks']: rle = mask_util.encode(np.asfortranarray(mask.astype(np.uint8))) rle['size'] = list(mask.shape) rles.append(rle) return jsonify(rles=rles) else: # 默认返回 PNG 图像 colored_img = apply_colormap(result['masks'], result['labels'], CUSTOM_COLORMAP) _, buf = cv2.imencode('.png', colored_img) return Response(buf.tobytes(), mimetype='image/png')前端调用示例
// 获取 JSON 结构数据 fetch('/parse', { method: 'POST', body: formData, headers: { 'Accept': 'application/json' }, data: { format: 'json' } }).then(r => r.json()).then(data => console.log(data));| 输出格式 | 适用场景 | 文件大小 | 可读性 | |--------|---------|--------|-------| | PNG | 展示、预览 | 中等 | 高 | | JSON | 前端交互、日志记录 | 小 | 高 | | NPY | 模型训练、后续处理 | 大 | 低 | | COCO-RLE | 与 Detectron2 等框架兼容 | 小 | 中 |
⚙️ 工程优化建议:提升扩展性与维护性
1. 配置驱动的设计模式
将颜色表、标签映射、输出路径等参数外置为配置文件(如config.yaml):
colormap: hair: [139, 69, 19] face: [255, 218, 185] upper_clothes: [255, 140, 0] output_formats: - png - json - npy enable_transparency: false加载方式:
import yaml with open('config.yaml') as f: config = yaml.safe_load(f)2. 插件式后处理架构
设计接口规范,允许动态注册“后处理器”:
class PostProcessor: def process(self, result: dict, image: np.ndarray) -> dict: raise NotImplementedError class WatchDetector(PostProcessor): def process(self, result, image): # 添加手表检测逻辑 pass # 注册机制 post_processors = [WatchDetector(), TransparencyApplier()] for pp in post_processors: result = pp.process(result, image)3. 日志与调试支持
在关键节点添加日志输出,便于追踪扩展功能的行为:
import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) logger.info(f"Applied custom colormap with {len(CUSTOM_COLORMAP)} entries")✅ 总结:构建可进化的 M2FP 系统
M2FP 不只是一个开箱即用的人体解析工具,更是一个可扩展的视觉中间件平台。通过以下实践,你可以将其能力延伸至更多垂直场景:
📌 核心总结
- 新增类别 ≠ 重训练模型:可通过 ROI 提取 + 外部检测器实现逻辑扩展
- 输出格式应多样化:支持 PNG、JSON、NPY、COCO-RLE 等格式,适应不同下游系统
- 颜色可定制化:通过配置文件管理 colormap,提升产品一致性
- 架构需松耦合:采用插件化设计,便于未来接入新功能模块
🚀 下一步建议1. 将自定义 colormap 封装为 WebUI 下拉菜单选项 2. 实现批量处理模式,支持文件夹输入/输出 3. 集成 OpenVINO 或 ONNX Runtime 进一步加速 CPU 推理
通过合理的技术延展,即使是基于固定模型的服务,也能演化为一个高度灵活、面向未来的智能视觉引擎。