当前位置: 首页 > news >正文

analyze.py

目录
  • 整体功能概述
  • 1. check_error(result)
    • 1.1 作用:
    • 1.2 特点:
  • 2. remove_outside_boundingbox(result, width)
    • 2.1 为什么?
    • 2.2 步骤:
    • 2.3 注意点:
  • 3. remove_approximate_result(items)
    • 3.1 预设去重规则 remove_task
    • 3.2 按车厢号分组
    • 3.3 查找同一车厢 + 相机组 + 组件的检测项
    • 3.4 多相机、同部件、同车厢 → 按 x 坐标聚类
      • 3.4.1 关键逻辑:
      • 3.4.2 只保留每簇第一个,其余删除:
    • 3.5 小结(remove_approximate_result)
  • 4. get_short_image_results_middle(result)
    • 4.1 初始化与读取输入
    • 4.2 获取长图路径 + 文件名拆分
    • 4.3 使用 imdecode 读取图片
      • 4.3.1 为什么不用 cv2.imread?
    • 4.4 获取原图尺寸
    • 4.5 取出检测框信息
    • 4.6 设定裁剪子图宽度 cut_width
    • 4.7 遍历每个检测框 rect
      • 4.7.1 跳过无需裁剪的类型
    • 4.8 深拷贝当前框,避免修改原框
    • 4.9 计算裁剪图的中心 mid_x(核心逻辑)
      • 4.9.1 宽度非常大的框(> 子图宽度)
      • 4.9.2 普通框
    • 4.10 根据 mid_x 计算裁剪窗口左右边界
    • 4.11 如果右边越界,整体左移
    • 4.12 截取子图
    • 4.13 修正子图内的检测框坐标
    • 4.14 保存子图(本地)
    • 4.15 准备 OBS 上传路径(文件名编码)
    • 4.16 上传 OBS
    • 4.17 生成子图 JSON
    • 4.18 用子图的 left 作为 key 保存
    • 4.19 返回所有子图 JSON
    • 4.20 总结:核心逻辑图
  • 5. assemble_results(sub_results, full_result, width, height)
  • 6.整体流程总结图


import copy
import cv2
import os
import json
import gc
import numpy as np
  • copy:深拷贝检测框,避免污染原始结果
  • cv2 + numpy:图像解码、裁剪、保存
  • gc:内存回收(虽然后面没显式用)
  • json:结果结构使用 JSON 风格字典
from aionet import uploader
from config.logger_config import process_logger
from config import settings
  • uploader:上传 OBS(华为对象存储)
  • process_logger:进程级日志
  • settings:全局配置

整体功能概述

这段代码属于一个 图像检测 post-processing(后处理)模块,典型用于:

  • AI 检测模型返回结果的进一步过滤
  • 删除越界或无效的检测框
  • 冗余检测结果去重(例如多个相机拍摄到重复目标)
  • 对检测框进行裁剪生成子图
  • 将子图上传到 OBS(对象存储)
  • 最终合成一个包含所有子图结果的 JSON

整体结构如下:

模型检测结果 → 后处理├─ check_error:检查模型返回是否包含 error_code├─ remove_outside_boundingbox:移除超出原图宽度的框├─ remove_approximate_result:去重(不同相机得到的、同一个部件的相近结果)├─ get_short_image_results_middle:裁剪子图并上传└─ assemble_results:组装小图检测结构并返回

1. check_error(result)

检查返回结果是否含有 error_code。

def check_error(result):detect_info = result["result"]["faults"][0]if "error_code" in detect_info:process_logger.info(...)

1.1 作用:

  • 某些模型可能输出 error_code 代表检测失败。
  • 如果存在 error_code,则记录日志。

1.2 特点:

  • 无返回值,只用于日志监控。

2. remove_outside_boundingbox(result, width)

删除 “左 + 宽度 > 图像宽度” 的框

new_list = [rect for rect in fault_info if rect["left"] + rect["width"] <= width]

2.1 为什么?

检测模型可能输出越界框,裁剪子图会出错,因此先过滤。

2.2 步骤:

  1. fault_info 列表中每个元素是一个检测框:

    {"left": ..., "top": ..., "width": ..., "height": ...}
    
  2. 条件过滤:

    left + width <= 图像宽度
    
  3. 替换原 fault_info,再返回。

2.3 注意点:

  • 如果图像是宽图,left 可能很大(长图拼接)。
  • 返回 result 保持结构一致。

3. remove_approximate_result(items)

核心逻辑: 去重不同相机、不同角度拍到的 同一故障目标。

这是整个代码最复杂的函数。


3.1 预设去重规则 remove_task

remove_task = {"轮缘润滑装置":[["10", "11"],["14", "13"]],"橡胶盖":[["10","8"],["14","9"]]
}

含义:

  • 同一个故障场景由多个相机拍摄
  • 某些相机(如 10、11)会拍摄到同一个目标
  • 如果两个相机结果高度相似,应只保留一个

3.2 按车厢号分组

grouped_by_car[car_number].append((idx, item))
  • seq = 车厢号

  • 保留原始索引,方便后面删除

3.3 查找同一车厢 + 相机组 + 组件的检测项

camera = item["check"][0]["position"]
detections = item["check"][0]["detections"]

必须同时满足:

  • 相机在指定相机组中
  • 有检测结果
  • faultname 包含目标组件
  • other 中存在 x 坐标

items 中每个元素如:

{"seq": "06","check": [{"position": "10", "detections": [...]}]
}

最终结构:

{"车厢号": [(原索引, item对象),...]
}

3.4 多相机、同部件、同车厢 → 按 x 坐标聚类

3.4.1 关键逻辑:

if abs(curr_x - prev_x) < settings.X_APPROXIMATE_THRESHOLD:同一簇

含义:

  • 如果检测结果横向位置非常接近(如相差 < 25 像素)
  • 可以认为是“同一个故障被不同相机拍到”

3.4.2 只保留每簇第一个,其余删除:

for i in range(1, len(cluster)):keep_indices.discard(cluster[i][0])

3.5 小结(remove_approximate_result)

功能:
在以下条件同时满足时,认为是重复项并去除:

  • 同一车厢
  • 同一部件(如轮缘润滑装置)
  • 同一个相机组(比如相机 10/11)
  • x 坐标非常近(小于阈值 settings.X_APPROXIMATE_THRESHOLD)

结果:返回不重复的检测列表。


4. get_short_image_results_middle(result)

核心任务:

  1. 读取一张 长图(长条监控图)
  2. 对每个检测框生成一个 以该故障为中心的正方形子图
  3. 修正该子图中的检测框坐标
  4. 将子图保存到本地,并上传到 OBS
  5. 返回所有子图的检测 JSON,用于进一步处理

4.1 初始化与读取输入

all_sub_detect_json = {}
detect_info = result["result"]["faults"][0]
  • result 是模型返回的整体检测结果结构
  • faults 是一个列表,每个 fault 对应一种部件,这里默认只取第一个
  • all_sub_detect_json 用于保存输出

4.2 获取长图路径 + 文件名拆分

long_img_path = detect_info["path"]
_, long_img_fname = os.path.split(long_img_path)
long_img_name, long_img_extension = os.path.splitext(long_img_fname)

例如:

20250706044153000_M15_15004_06_香江北路_1_走行部左.jpg

拆分后:

  • long_img_name = 没有扩展名的部分
  • long_img_extension = 文件扩展名(.jpg)

后面存子图时要用。


4.3 使用 imdecode 读取图片

long_img = cv2.imdecode(np.fromfile(long_img_path, dtype=np.uint8), -1)

4.3.1 为什么不用 cv2.imread?

因为中文路径会导致 cv2.imread 读取失败。
np.fromfile + imdecode 是处理中文路径的惯用方法。


4.4 获取原图尺寸

H, W = long_img.shape[:2]
  • H = 高度
  • W = 宽度

4.5 取出检测框信息

fault_info = detect_info["fault_info"]

fault_info 是一个列表,每个元素是:

{"left": xxx,"top": xxx,"width": xxx,"height": xxx,"defect_name": "xxxxxx","defect_area": "xxxx"
}

4.6 设定裁剪子图宽度 cut_width

cut_width = H

裁剪的子图一定是正方形,宽=高=原图高度

理由:

  • 原图是长条图(横向长)
  • 故障框一般在中部
  • 每个子图裁剪为正方形便于后续网络处理/展示

4.7 遍历每个检测框 rect

for idx, rect in enumerate(fault_info):

4.7.1 跳过无需裁剪的类型

if any(x in rect["defect_name"] for x in [...]):continue

包含关键字的 defect_name 都属于:

  • 正常
  • 无法判断
  • 遮挡
  • 非真实故障

这些不需要生成故障子图,直接跳过。


4.8 深拷贝当前框,避免修改原框

sub_rect = copy.deepcopy(rect)

4.9 计算裁剪图的中心 mid_x(核心逻辑)

if rect["width"] > cut_width:mid_x = rect["left"]
else:mid_x = rect["left"] + rect["width"]//2

4.9.1 宽度非常大的框(> 子图宽度)

采用:

mid_x = 左边界

理由:框太宽,中心太偏,要以左边当中心,否则裁剪不合理。

4.9.2 普通框

采用:

中心 = 左 + 半宽

4.10 根据 mid_x 计算裁剪窗口左右边界

sub_img_left = mid_x - cut_width//2 if mid_x - cut_width//2 > 0 else 0
sub_img_right = sub_img_left + cut_width
  • mid_x - cut_width/2 是左边界
  • 不能 < 0,否则从 0 截起

4.11 如果右边越界,整体左移

offset_x = sub_img_right - W
if offset_x > 0:sub_img_left -= offset_xsub_img_right -= offset_x

作用:

  • 避免 sub_img_right > 图像宽度
  • 同时往左移,使得子图仍然是正方形

4.12 截取子图

sub_im = long_img[:, sub_img_left:sub_img_right]

子图是:

  • 高度:原图 H
  • 宽度:cut_width

4.13 修正子图内的检测框坐标

sub_rect["left"] -= sub_img_left

因为子图的 left = 原图的 left - 裁剪窗口左边界

特殊情况:框宽 > cut_width,需要截断

if rect["width"] > cut_width:sub_rect["width"] = cut_width//2

避免子图中过宽的框。


4.14 保存子图(本地)

sub_img_path = os.path.join(settings.ERROR_IMG_DIR, long_img_name+"_"+str(idx).zfill(3)+".jpg")
cv2.imencode('.jpg', sub_im)[1].tofile(sub_img_path)

4.15 准备 OBS 上传路径(文件名编码)

文件名解析:

pass_time, line, train_code, carriage_number, station, direction, camera = long_img_name.split("_")

生成如下结构:

pass_time_相机_车厢号_故障区域_故障名_序号.jpg

用于上传 OBS:

obs_sub_img_path = ...

4.16 上传 OBS

status, obs_path = uploader(...)

上传的是 未画框的子图


4.17 生成子图 JSON

sub_fault_info_json = {"result": {"faults":[{"path": sub_img_path,"fault_info":[sub_rect],"defect_count": 1,"part": detect_info["part"],"left": sub_img_left,"top": 0,"height": H,"width": cut_width}]}
}

4.18 用子图的 left 作为 key 保存

all_sub_detect_json[sub_img_left] = sub_fault_info_json

这样可以按子图在原图中的顺序输出(按 left 排序)。


4.19 返回所有子图 JSON

return all_sub_detect_json

4.20 总结:核心逻辑图

原图
│
├─ 遍历每个检测框 rect
│    ├─ 跳过正常/无法判断类
│    ├─ 计算裁剪中心 mid_x
│    ├─ 计算子图左右边界
│    ├─ 截取子图
│    ├─ 修正子图中的框坐标
│    ├─ 保存本地 + OBS
│    ├─ 构建子图 JSON
│    └─ 插入结果
│
└─ 返回所有子图结果

5. assemble_results(sub_results, full_result, width, height)

最终组装所有子图结果

返回结构:

{"path": 原长图路径,"width": 长图宽度,"height": 长图高度,"short_result": [{"path": 子图路径,"left": 子图在原图中的位置,"top": ..."width": ..."height": ..."result": 子图的检测信息}]
}

用于输出给上一级系统。


6.整体流程总结图

AI检测结果(result)↓
[1] check_error ——日志检查错误↓
[2] remove_outside_boundingbox ——过滤越界框↓
[3] remove_approximate_result ——去除重复结果↓
[4] get_short_image_results_middle ——生成小图 + 上传OBS + 返回JSON↓
[5] assemble_results ——组装最终返回值

http://www.jsqmd.com/news/197761/

相关文章:

  • 2026年合肥全屋定制品牌推荐:设计落地能力与服务体系双维度实测盘点。 - 十大品牌推荐
  • 为什么顶尖数据团队都在用GPT生成R代码:9个你不知道的秘密优势
  • Python 使用 Tkinter + openpyxl 处理 Excel 文件并显示实时进度条
  • 2025年长三角环保景观楼盘服务排行榜,新测评精选香杉悦楼盘项目合作服务商推荐 - 工业设备
  • GitHub镜像网站也能下载IndexTTS 2.0?国内访问加速方法分享
  • aionet
  • 可穿戴设备语音反馈:低延迟调用IndexTTS 2.0 API
  • Pelco KBD300A 模拟器:TEST02.重构后键盘部分的测试操作一步一步详细指导
  • Slack工作流自动化:通过IndexTTS 2.0播报通知消息
  • remap_json.py
  • Wireshark抓包实操:ModbusTCP报文格式说明新手教程
  • 2025年课程顾问AI陪练系统推荐:课程顾问智能体哪家专业? - myqiye
  • 2025年轻骨料混凝土制造企业交货期/源头厂家信誉度/售后服务排名推荐 - mypinpai
  • 2025年智能运维品牌供应商推荐:服务不错的智能运维品牌商有哪些? - 工业设备
  • 2026年靠谱的透明四方袋/铝塑复合四方袋厂家推荐及选择指南 - 品牌宣传支持者
  • 2026年知名的钙粉选粉机/组合式选粉机厂家推荐及采购指南 - 品牌宣传支持者
  • 2025专项财税服务TOP5权威推荐:专业专项财税服务找哪家? - 工业品牌热点
  • Git commit规范写作技巧,搭配IndexTTS 2.0生成代码注释语音
  • 2025年重庆热门茶馆推荐:苗品记隐茶馆口碑如何? - myqiye
  • Meta新发布Voicebox不及预期?IndexTTS 2.0已落地实用
  • 频率响应奈奎斯特图:MATLAB实战案例解析
  • Web端集成IndexTTS 2.0:打造在线语音生成平台全流程
  • 【多元统计分析进阶之路】:基于R语言的PCA实战案例精讲
  • R语言随机森林模型精度提升7步法:数据预处理到超参数调优全流程
  • 如何用R语言打造期刊主编青睐的图表?揭秘高影响力论文配色密码
  • 用自然语言描述控制情绪:“愤怒地质问”也能精准合成?
  • 2025年天津短视频拍摄公司排名:靠谱、售后好、案例多的企业推荐全解析 - mypinpai
  • 数字人交互语音新选择:IndexTTS 2.0提升语音清晰度与稳定性
  • 新手必看:Allegro导出Gerber文件入门教程
  • 2025年靠谱隧道风筒布加工厂/制造厂/服务商排名 - 工业设备