utils.py

下面按功能 → 关键逻辑 → 细节说明的方式,朴实地把这段代码拆开讲清楚。


1. 整体作用概述

主要做三件事:

  1. 根据原始图片路径生成“子故障图片”的新文件名
  2. (可选)在图片上画矩形框并保存
  3. 把生成的图片上传到 OBS
  4. 在已有图片上绘制中文说明文字(使用 PIL 解决中文乱码问题)

2. 依赖库说明

from PIL import Image, ImageDraw, ImageFont
import cv2
import os
from urllib.parse import unquote 
import numpy as np
  • cv2 / numpy:读写图片、画矩形
  • PIL (Pillow):专门用来画中文(OpenCV 画中文很麻烦)
  • unquote:防止路径中出现中文编码问题
  • settings:配置目录(如图片保存路径)
  • uploader:上传图片到 OBS
  • process_logger:日志(本文件中未直接使用)

3. get_sub_fault_img_path_and_upload_obs

def get_sub_fault_img_path_and_upload_obs(img_source_path, error_code, draw=None, img_idx=1):

3.1 作用

  • 生成子故障图片
  • 上传到 OBS
  • 返回生成的文件名

3.2 执行流程

  1. 调用 get_sub_fault_img_path 生成图片并返回文件名
  2. 拼接成完整路径
  3. 调用 uploader(full_img_path) 上传
  4. 返回文件名(而不是 OBS 路径)
fname = get_sub_fault_img_path(...)
if fname is not None:
    full_img_path = ...
    status, obs_path = uploader(full_img_path)
    return fname

注意:

  • 上传是否成功不影响返回值
  • 返回的是本地文件名,不是 OBS 路径

4. get_sub_fault_img_path(核心函数)

def get_sub_fault_img_path(img_source_path, error_code, draw=None, img_idx=1):

4.1 解析原始图片文件名

img_fname = os.path.basename(img_source_path)
passtime, line, train, car, yard, direction, camera, fault_code = \
    img_fname.replace(".jpg", "").split("_")

原始图片名格式示例:

AIzt_20250723053306000_M15_15021_06_yard_1_camera_102.jpg

解析得到:

  • passtime:时间戳
  • line:线路(M15)
  • train:车号
  • car:车厢号
  • yard:场段
  • direction:方向
  • camera:相机
  • fault_code:原始故障码

后面会把 line 转成小写(m15


4.2 不画框(draw is None

4.2.1 生成文件名

aizt_时间_线路_车号_车厢_场段_方向_相机_错误码_序号.jpg

示例:

aizt_20250723053306000_m15_15021_06_yard_1_camera_201_1.jpg

4.2.2 处理逻辑

  1. 拼完整保存路径
  2. unquote 防止中文路径乱码
  3. 如果文件已存在:
    • img_idx + 1 递归调用,避免覆盖
  4. 如果不存在:
    • 使用 cv2.imdecode + np.fromfile 读取图片。解决 Windows 中文路径 cv2.imread 失败的问题
    • 保存图片
    • 返回文件名
img = cv2.imdecode(np.fromfile(img_source_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
cv2.imwrite(dinghan_img_save_fp, img)

4.3 画框模式(draw != None

draw 格式:

(left, top, width, height)

4.3.1 文件名区别

..._errorcode_draw_序号.jpg

4.3.2 核心逻辑

  1. 判断文件是否存在,避免重名
  2. 读取原图
  3. 画红色矩形框
cv2.rectangle(
    img,
    (left, top),
    (left + width, top + height),
    (0, 0, 255),
    3
)
  1. 保存并返回文件名

5. draw_tanhuakuai_chinese(中文标注)

5.1 作用

已保存的图片上:

  • 写中文说明文字
  • 位置在矩形框上方
  • 使用 PIL 解决 OpenCV 中文乱码

5.2 读取并转换格式

img = cv2.imread(img_path)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
pil_img = Image.fromarray(img_rgb)

OpenCV → PIL(因为 PIL 才能稳定画中文)


5.3 设置字体

try:
    font = ImageFont.truetype("./simhei.ttf", 36)
except:
    font = ImageFont.load_default()
  • 优先使用 黑体
  • 字体不存在就降级(⚠️ 默认字体可能不支持中文)

5.4 计算文字位置

text = "受流器集电靴碳滑块厚度小于2毫米"
text_height = ...
text_x = left
text_y = top - text_height - 5

文本画在矩形框上方


5.5 绘制文字(带描边)

draw.text(
    (text_x, text_y),
    text,
    font=font,
    fill=(255, 0, 0),
    stroke_width=2,
    stroke_fill=(0, 0, 0)
)
  • 红色文字
  • 黑色描边
  • 提高可读性

5.6 保存结果

img_with_text = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
cv2.imwrite(img_path, img_with_text)

直接覆盖原图


6. 几个设计上的细节总结

  1. 递归避免文件名冲突

    img_idx + 1
    
  2. cv2.imdecode + np.fromfile

    • 专门解决 Windows 中文路径问题
  3. OpenCV + PIL 混合使用

    • OpenCV:画框、性能好
    • PIL:画中文、稳定
  4. 函数职责清晰

    • 生成文件
    • 上传 OBS
    • 中文标注分离
posted @ 2026-01-05 08:56  做梦当财神  阅读(2)  评论(0)    收藏  举报