ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

流程图结构化解析:Faster R-CNN+几何关系推理实战

流程图结构化解析:Faster R-CNN+几何关系推理实战 简介本资源是一套基于Python与Faster R-CNN框架实现的流程图智能识别系统源码面向计算机视觉方向的学习者、AI工程实践者及自动化文档处理开发者解决流程图图像中图形符号、连接线与文字信息的端到端检测、结构化建模与JSON输出问题。压缩包共58个文件含43个Python核心模块覆盖模型构建、数据预处理、箭头识别、图结构生成、多GPU训练等全流程、6张JPG/PNG测试图像、1个XML标注示例、1个Shell训练脚本及README等辅助文件整体仅1.6MB轻量易部署。已有55人学习下载资源结构清晰主干含Faster R-CNN自定义实现backbone、RPN、ROI Head、流程图节点/边重建逻辑node.py/graph.py、专用箭头关键点识别模块arrow_recognize/arrow_keypoint_predict.py及训练数据自动化构造工具construct.py提供从数据准备、模型训练到推理输出的完整闭环能力。1. 这不是OCR也不是通用目标检测一个专为流程图“解构-重建”而生的Faster R-CNN实战系统你有没有试过把一张手绘流程图拍照扔进YOLOv8里——结果框出一堆“疑似矩形”和“疑似箭头”但完全不知道哪个是开始节点、哪条线连着哪个判断框、文字标签该挂在哪这不是模型不行是任务定义错了。本项目不是做“流程图图像分类”或“粗粒度目标检测”而是完成一次结构化语义解构把一张图拆成「节点椭圆/矩形/菱形 连接关系带方向的箭头 文本内容OCR后绑定到节点」三元组并最终输出可被Graphviz、Mermaid或业务系统直接消费的JSON拓扑结构。它用Faster R-CNN作为底层检测引擎但所有上层逻辑——从箭头方向判定、节点类型校验、连接关系推理到最终JSON Schema生成——全部由node.py、graph.py、arrow_recognize/下的模块重写。这意味着你不能直接拿COCO预训练权重微调就跑通必须用它自带的split_data.py构造符合flowchart_tree_data.py定义的树状标注格式且预测后必须走recognition.py的后处理流水线。适合正在做BPMN自动解析、低代码平台图形导入、或企业知识图谱中流程资产数字化的一线算法工程师与全栈开发。2. 从零启动环境搭建、数据准备与模型加载的硬核三步链2.1 环境依赖为什么必须用Python 3.7–3.9 PyTorch 1.9.0项目根目录下requirements.txt明确锁定了torch1.9.0cu111和torchvision0.10.0cu111CUDA 11.1而非最新版。这不是保守是避坑刚需faster_rcnn_framework.py中RoIAlign的output_size参数在PyTorch 1.10中行为变更会导致roi_head.py中box_features尺寸错位训练时loss_classifier直接nanfeature_pyramid_network.py依赖torch.nn.functional.interpolate的align_cornersFalse默认行为该行为在1.12中被标记为deprecated但项目未做兼容transform.py中自定义的Resize类使用PIL.Image.BICUBIC插值在OpenCV 4.8与PIL 10.0组合下会触发DecompressionBombWarning而项目未加Image.MAX_IMAGE_PIXELS None防护。提示不要用pip install -r requirements.txt一键安装。先创建conda环境conda create -n flowchart python3.8再手动执行pip install torch1.9.0cu111 torchvision0.10.0cu111 --extra-index-url https://download.pytorch.org/whl/cu111 pip install -r requirements.txt --no-deps pip install opencv-python4.5.5.64 numpy1.21.6 pillow8.4.0 lxml4.9.12.2 数据构造split_data.py不是脚本是数据协议编译器项目不接受VOC或COCO格式标注。它强制要求输入为images/下的原始图 output.xml由construct.py生成最终产出train/val/test三份my_dataset.py可读取的.json文件。关键逻辑在split_data.py第127行# split_data.py line 127 for xml_path in xml_list: tree ET.parse(xml_path) root tree.getroot() # 强制提取 object 下的 name 必须为 start, end, process, decision, arrow # 且 arrow 节点必须含 points 子标签格式为 x1,y1;x2,y2 # 否则跳过该样本 —— 这是硬性过滤非警告这意味着你不能用LabelImg随便标。必须用项目自带的Tools.py启动GUI标注工具python Tools.py它会强制你在画箭头时点击起点→终点→自动拟合贝塞尔曲线并生成points字段。若你用其他工具生成XML需确保所有object的name值严格匹配setting.py中NODE_TYPES [start, end, process, decision]和ARROW_TYPE arrow每个arrow必须有bndbox用于R-CNN检测和points用于方向判定construct.py会校验points中坐标是否在图像边界内越界样本直接丢弃。2.3 模型加载train_res50_fpn.py里的三个隐藏开关运行训练前必须检查train_res50_fpn.py中的三个关键配置num_classes不是4节点1背景而是len(setting.NODE_TYPES) 1 11为arrow类1为背景即5 1 1 7。若设为5roi_head.py中cls_logits维度错配报size mismatchpretrained路径默认指向network_files/resnet50_fpn_model.pth但该文件实际是ResNet50-FPN的backbone权重不含RPN和ROI Head。项目已将完整权重存于network_files/faster_rcnn_resnet50_fpn_coco.pthCOCO预训练需手动替换data_loader的collate_fnmy_dataset.py中collate_fn对arrow类做了特殊padding——boxes维度扩展为(N, 5)第5维存is_arrowflag1.0。若你跳过此步直接用default_collaterpn_function.py中compute_loss会因targets维度不匹配崩溃。3. 预测流水线从predict.py到JSON输出的七层解析3.1predict.py不只是model.eval()而是四阶段状态机predict.py的主循环不是简单model(image)而是按recognition.py定义的状态流转# predict.py line 89 for img_path in image_list: # Stage 1: 原图→Faster R-CNN检测 → 输出 raw_boxes, raw_labels, raw_scores detections model(img_tensor) # Stage 2: 节点过滤 → 只保留 score 0.7 且 label in NODE_TYPES 的框 node_dets filter_nodes(detections, score_thresh0.7) # Stage 3: 箭头专项处理 → 单独调用 arrow_keypoint_predict.py 推理箭头端点 arrow_dets arrow_predictor.predict(img_path, detections[arrow]) # Stage 4: 关系绑定 → 用 node_dets 和 arrow_dets 计算几何距离角度生成 edge_list graph build_graph(node_dets, arrow_dets) # 最终输出 JSON json.dump(graph.to_dict(), open(f{img_path}.json, w))注意arrow_keypoint_predict.py是一个独立子模型HRNet变体它不依赖主Faster R-CNN的arrow检测框而是对整图做高分辨率热图回归定位箭头起点/终点像素坐标。这是项目最精妙的设计——避免了“先检测箭头框再在框内找端点”的误差累积。3.2arrow_recognize/箭头方向判定的几何学真相箭头关系不是靠IOU匹配而是基于欧氏距离与向量夹角的双重判决。核心逻辑在arrow_recognize/arrow.py第203行# arrow.py line 203 def compute_edge_relation(start_pt, end_pt, node_boxes): start_pt, end_pt: (x, y) 箭头端点坐标 node_boxes: [(x1,y1,x2,y2), ...] 所有节点检测框 返回: (source_node_id, target_node_id, edge_type) # Step 1: 找离 start_pt 最近的节点距离 30px→ 候选源节点 src_candidates [i for i, box in enumerate(node_boxes) if distance(start_pt, center_of_box(box)) 30] # Step 2: 找离 end_pt 最近的节点距离 30px→ 候选目标节点 tgt_candidates [i for i, box in enumerate(node_boxes) if distance(end_pt, center_of_box(box)) 30] # Step 3: 若唯一匹配则直接绑定否则计算向量夹角 if len(src_candidates) 1 and len(tgt_candidates) 1: return src_candidates[0], tgt_candidates[0], direct # Step 4: 多候选时计算 arrow_vector 与 node_center_vector 的夹角 arrow_vec np.array(end_pt) - np.array(start_pt) for src_id in src_candidates: for tgt_id in tgt_candidates: src_center center_of_box(node_boxes[src_id]) tgt_center center_of_box(node_boxes[tgt_id]) src2tgt_vec tgt_center - src_center cos_angle np.dot(arrow_vec, src2tgt_vec) / (np.linalg.norm(arrow_vec) * np.linalg.norm(src2tgt_vec)) if cos_angle 0.85: # 夹角 30° return src_id, tgt_id, direct return None, None, unbound这个0.85阈值对应30°是血泪经验低于0.75误连率飙升高于0.9漏连率陡增。它直指流程图本质——箭头是人为绘制的示意线不是物理连线必须容忍30°以内的手绘偏差。3.3 JSON Schema为什么flowchartTreeNode.py定义了严格的父子关系最终输出的JSON不是扁平列表而是嵌套树结构由flowchartTreeNode.py的FlowchartTreeNode类序列化{ type: process, text: 用户登录, id: node_0, children: [ { type: decision, text: 密码正确, id: node_1, children: [ { type: process, text: 跳转首页, id: node_2 }, { type: process, text: 提示错误, id: node_3 } ] } ] }关键约束children数组长度必须 ≤ 2决策节点最多两个分支start节点必须无父节点且children长度 ≥ 1end节点必须无children若检测到decision节点有3个以上childrengraph.py会触发raise ValueError(Decision node has more than 2 children)中断输出。这并非bug而是对BPMN规范的硬编码——项目默认你处理的是标准流程图不是UML活动图。4. 避坑指南五个让调试时间翻倍的隐蔽陷阱4.1 现象train_res50_fpn.py报错RuntimeError: Expected all tensors to be on the same device原因distributed_utils.py中init_distributed_mode()默认启用多卡但你的机器只有单卡。model被torch.nn.parallel.DistributedDataParallel包装后optimizer.step()时model.parameters()仍在GPU0而loss计算中某处torch.zeros()在CPU上。解决注释掉train_res50_fpn.py第45行utils.init_distributed_mode(args)并确保args.world_size 1args.rank 0。4.2 现象predict.py输出JSON中text字段为空字符串原因recognition.py调用OCR模块时默认使用rapidocr但项目未在requirements.txt中声明其版本。rapidocr0.2.0因PIL 8.4.0的Image.fromarray()返回uint16而非uint8导致OCR输入图像通道异常识别失败。解决降级pip install rapidocr0.1.12并在recognition.py第62行OCR初始化后加# recognition.py line 62 self.ocr RapidOCR(det_db_thresh0.3, det_db_box_thresh0.5) # 加入强制转换 from PIL import Image import numpy as np def fix_ocr_input(img_np): if img_np.dtype np.uint16: img_np (img_np / 256).astype(np.uint8) # 16bit→8bit return Image.fromarray(img_np)4.3 现象draw_box_utils.py画出的检测框严重偏移但坐标数值看起来正常原因transform.py中Resize类的interpolation参数默认为PIL.Image.BILINEAR但draw_box_utils.py第37行cv2.rectangle()绘制时假设输入图已是原始尺寸。而predict.py中transforms.Compose先Resize(800)再ToTensor()导致坐标未反向缩放。解决在predict.py第102行draw_box_utils.draw_objs()前插入# predict.py line 102 orig_h, orig_w img_pil.height, img_pil.width scale_h, scale_w orig_h / 800.0, orig_w / 800.0 detections[boxes][:, [0,2]] * scale_w detections[boxes][:, [1,3]] * scale_h4.4 现象validation.py中mAP计算为0但plot_curve.py显示loss持续下降原因coco_eval.py中prepare_for_coco_detection()函数对arrow类的bbox做了错误归一化——它将points坐标x1,y1;x2,y2直接当作[x,y,w,h]传入COCO API而COCO要求[x,y,w,h]必须是轴对齐矩形。解决修改validation.py第89行arrow类检测结果不参与mAP计算# validation.py line 89 if label ! setting.ARROW_TYPE: coco_results.append({ image_id: image_id, category_id: label, bbox: [x, y, w, h], score: score })4.5 现象train_multi_GPU.py启动后进程卡死nvidia-smi显示GPU显存占用为0原因train_multi_GPU.py依赖torch.distributed.launch但项目未提供--nproc_per_node参数且args.dist_url默认tcp://127.0.0.1:23456在无nccl后端支持的环境中会无限等待。解决放弃多卡训练改用train_res50_fpn.py单卡模式若必须多卡请先验证torch.distributed.is_available()返回True并手动设置export NCCL_IB_DISABLE1。5. 进阶技巧用flowchart_tree_data.py定制你的领域流程图语法5.1 扩展节点类型三步注入新图形如“数据库”图标项目默认只支持5种节点但flowchart_tree_data.py是语法扩展入口。添加database节点需三步修改setting.py在NODE_TYPES末尾追加database并定义其颜色# setting.py NODE_COLORS { start: (0, 255, 0), end: (255, 0, 0), process: (0, 0, 255), decision: (255, 165, 0), database: (128, 0, 128), # 新增 }更新my_dataset.py的__getitem__在label_map字典中加入database: 5原arrow类ID变为6重写flowchartTreeNode.py的to_dict()方法为database节点添加专属字段# flowchartTreeNode.py line 155 def to_dict(self): base super().to_dict() if self.type database: base[connection_string] self.connection_string # 新增字段 base[tables] self.tables # 新增字段 return base5.2 箭头语义增强从“有向线段”到“带条件标签的边”默认箭头仅输出edge_type: direct但业务流程常需condition: status success。实现方式在arrow_recognize/recognize_arrow.py在ArrowRecognizer类中新增OCR子模块对箭头附近区域start_pt与end_pt连线两侧5px带状区域截取图像调用rapidocr识别文本正则匹配if.*?then|else|when||!等关键词将结果注入graph.py生成的edge对象# graph.py line 210 edge_obj { source: src_id, target: tgt_id, condition: ocr_result or default, # 新增字段 type: direct }5.3 JSON Schema验证用jsonschema防止下游系统崩溃项目输出JSON无Schema校验易因字段缺失导致下游解析失败。在predict.py末尾加入验证# predict.py line 130 import jsonschema from jsonschema import validate SCHEMA { type: object, properties: { type: {enum: [start, end, process, decision, database]}, text: {type: string}, id: {type: string}, children: { type: array, items: {$ref: #} } }, required: [type, id] } try: validate(instancegraph.to_dict(), schemaSCHEMA) except jsonschema.exceptions.ValidationError as e: print(fJSON Schema violation at {e.json_path}: {e.message}) # 可选择抛出异常或降级为warning从那以后我每次交付流程图识别模块都强制在predict.py末尾跑一遍jsonschema.validate并把SCHEMA定义抽成独立文件schema/flowchart_v1.json——不是为了显得专业是避免凌晨三点被运维电话叫醒说“你们导出的JSON少了个id字段整个审批流崩了”。希望帮到你。本文还有配套的精品资源点击获取
返回列表