根据代码分析,layout_nms 是 PaddleX 中版面检测模型的后处理参数,用于过滤重叠的检测框。
layout_nms: Layout-aware Non-Maximum Suppression(版面感知的非极大值抑制)
# paddlex/inference/models/object_detection/processors.py L736-765
def apply(
self,
boxes: ndarray,
threshold: Union[float, dict],
layout_nms: Optional[bool], # 👈 关键参数
layout_unclip_ratio: Optional[Union[float, Tuple[float, float], dict]],
layout_merge_bboxes_mode: Optional[Union[str, dict]],
) -> Boxes:
"""后处理检测结果"""
# ... threshold 过滤 ...
if layout_nms: # 👈 启用 NMS
selected_indices = nms(boxes[:, :6], iou_same=0.6, iou_diff=0.98)
boxes = np.array(boxes[selected_indices])
功能: 当多个检测框重叠时,保留置信度最高的框,删除冗余框。
# paddlex/inference/models/object_detection/processors.py L614-650
def nms(boxes, iou_same=0.6, iou_diff=0.95):
"""
版面感知的 NMS
Args:
boxes: 检测框 [class_id, score, x1, y1, x2, y2]
iou_same: 同类别框的 IoU 阈值(默认 0.6)
iou_diff: 不同类别框的 IoU 阈值(默认 0.95)
Returns:
保留的框索引
"""
scores = boxes[:, 1]
indices = np.argsort(scores)[::-1] # 按置信度降序排列
selected_boxes = []
while len(indices) > 0:
current = indices[0]
current_box = boxes[current]
current_class = current_box[0]
current_coords = current_box[2:]
selected_boxes.append(current)
indices = indices[1:]
filtered_indices = []
for i in indices:
box = boxes[i]
box_class = box[0]
box_coords = box[2:]
iou_value = iou(current_coords, box_coords)
# 👇 核心逻辑:同类别用低阈值,不同类别用高阈值
threshold = iou_same if current_class == box_class else iou_diff
# 如果 IoU < 阈值,保留该框
if iou_value < threshold:
filtered_indices.append(i)
indices = filtered_indices
return selected_boxes
| 场景 | IoU 阈值 | 说明 |
|---|---|---|
| 同类别框重叠 | iou_same=0.6 |
较严格,IoU > 0.6 则删除低分框 |
| 不同类别框重叠 | iou_diff=0.98 |
较宽松,IoU > 0.98 才删除(允许不同类别框共存) |
示例:
场景 1: 两个 "text" 框重叠
┌─────────────┐
│ text (0.9) │
│ ┌─────────┼──┐
│ │ overlap │ │
└───┼─────────┘ │
│ text (0.7) │
└────────────┘
如果 IoU > 0.6 → 删除 text (0.7)
场景 2: "text" 和 "table" 框重叠
┌─────────────┐
│ text (0.9) │
│ ┌─────────┼──┐
│ │ overlap │ │
└───┼─────────┘ │
│ table(0.8) │
└────────────┘
如果 IoU < 0.98 → 两者都保留(不同类别可以重叠)
predict 时指定from paddlex import create_model
model = create_model(model_name="PP-DocLayout_plus-L")
# 启用 layout_nms
output = model.predict(
"input.png",
layout_nms=True # 👈 启用 NMS
)
# zhch/my_config/PaddleOCR-VL-Client_debug.yaml
SubModules:
LayoutDetection:
module_name: layout_detection
model_name: PP-DocLayoutV2
layout_nms: True # 👈 启用 NMS
threshold: 0.5
from paddlex import create_pipeline
pipeline = create_pipeline(pipeline="layout_parsing")
output = pipeline.predict(
"input.png",
layout_nms=True # 👈 启用 NMS
)
layout_nms=False (默认)检测结果:
┌──────────────────┐
│ text (score=0.95)│
│ ┌───────────────┼─────┐
│ │ overlap │ │
└──┼───────────────┘ │
│ text (score=0.85) │ ← 冗余框
└─────────────────────┘
问题: 存在多个重叠的检测框,造成干扰。
layout_nms=True检测结果:
┌──────────────────┐
│ text (score=0.95)│ ← 仅保留高分框
└──────────────────┘
优势: 自动过滤低分重叠框,输出更干净。
问题:
layout_det_res = {
"boxes": [
{"label": "text", "score": 0.92, "coordinate": [100, 100, 400, 200]},
{"label": "text", "score": 0.78, "coordinate": [110, 110, 410, 210]}, # 重叠
]
}
解决:
# 启用 NMS 后
output = model.predict("input.png", layout_nms=True)
# 仅保留 score=0.92 的框
需求: 表格内有文字,两者需要同时保留
layout_det_res = {
"boxes": [
{"label": "table", "score": 0.88, "coordinate": [50, 50, 500, 300]},
{"label": "text", "score": 0.85, "coordinate": [60, 60, 200, 100]}, # 表格内的文字
]
}
效果:
# 启用 NMS 后,由于是不同类别且 IoU < 0.98,两者都保留 ✅
output = model.predict("input.png", layout_nms=True)
| 文件 | 关键代码 |
|---|---|
[paddlex/inference/models/object_detection/processors.py]processors.py ) |
nms() 函数(L614-650) |
[paddlex/inference/models/object_detection/predictor.py]predictor.py ) |
layout_nms 参数定义(L111) |
[paddlex/inference/pipelines/layout_parsing/pipeline_v2.py]pipeline_v2.py ) |
管道中使用(L1010) |
| 位置 | 默认值 |
|---|---|
| 模型配置 | None (不启用) |
| 管道配置 | True (启用) |
| 手动调用 | 需显式指定 |
| 维度 | 说明 |
|---|---|
| 定义 | 版面感知的非极大值抑制 |
| 作用 | 过滤重叠的检测框 |
| 核心逻辑 | 双阈值策略(同类别严格,不同类别宽松) |
| 适用场景 | 版面检测、目标检测 |
| 是否必需 | 否,但推荐启用 |
| 默认值 | 管道中默认 True,单模型默认 None |
# 最佳实践
model.predict(
"input.png",
threshold=0.5, # 置信度阈值
layout_nms=True, # 👈 启用 NMS,过滤重叠框
layout_unclip_ratio=1.0, # 边界框扩展比例
)
建议: 在生产环境中始终启用 layout_nms=True,以获得更干净的检测结果。