| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- import cv2
- import os
- import random
- # ================= 配置区域 =================
- # 1. 图片文件夹路径
- IMG_DIR = r'20251204\images'
- # 2. 标签文件夹路径 (YOLO格式的txt)
- LABEL_DIR = r'20251204\labels'
- # 3. 结果保存路径 (如果不填,默认在当前目录下生成 'output' 文件夹)
- OUTPUT_DIR = r'output_result'
- # 4. 类别名称列表 (按 classes.txt 的顺序或者是你的模型定义的顺序)
- # 如果不知道名字,可以留空,代码会直接显示 ID (如 '0', '1')
- CLASSES = ['fire', 'fust']
- # CLASSES = [] # 如果不想显示名字,保持为空列表即可
- # 5. 是否只显示有标签的图片?(True: 跳过无标签图片; False: 显示所有)
- ONLY_SHOW_LABELED = True
- # ===========================================
- def get_color(cls_id):
- """为每个类别生成固定的随机颜色"""
- random.seed(cls_id * 10) # 保证同一个类别的颜色在不同图片中是一样的
- b = random.randint(0, 255)
- g = random.randint(0, 255)
- r = random.randint(0, 255)
- return (b, g, r)
- def plot_one_box(x, img, color=None, label=None, line_thickness=None):
- """画框的主函数"""
- tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # 线宽
- c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3]))
- cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA)
-
- if label:
- tf = max(tl - 1, 1) # 字体粗细
- t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0]
- c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3
- cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA) # 填充文字背景
- cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA)
- def yolo_to_xyxy(yolo_line, img_w, img_h):
- """将YOLO格式 (class x_center y_center w h) 转换为 (x1, y1, x2, y2)"""
- parts = yolo_line.strip().split()
- cls_id = int(parts[0])
- x_c = float(parts[1])
- y_c = float(parts[2])
- w = float(parts[3])
- h = float(parts[4])
- # 还原为像素坐标
- x1 = int((x_c - w / 2) * img_w)
- y1 = int((y_c - h / 2) * img_h)
- x2 = int((x_c + w / 2) * img_w)
- y2 = int((y_c + h / 2) * img_h)
-
- # 边界保护,防止画出图片外
- x1 = max(0, x1)
- y1 = max(0, y1)
- x2 = min(img_w, x2)
- y2 = min(img_h, y2)
- return cls_id, x1, y1, x2, y2
- def main():
- if not os.path.exists(OUTPUT_DIR):
- os.makedirs(OUTPUT_DIR)
-
- print(f"开始处理... 结果将保存到: {OUTPUT_DIR}")
-
- img_files = [f for f in os.listdir(IMG_DIR) if f.lower().endswith(('.jpg', '.jpeg', '.png', '.bmp'))]
-
- for img_file in img_files:
- img_path = os.path.join(IMG_DIR, img_file)
- label_file = os.path.splitext(img_file)[0] + '.txt'
- label_path = os.path.join(LABEL_DIR, label_file)
-
- # 读取图片
- img = cv2.imread(img_path)
- if img is None:
- continue
- h, w, _ = img.shape
-
- has_label = False
-
- # 检查是否有对应的txt文件
- if os.path.exists(label_path):
- with open(label_path, 'r') as f:
- lines = f.readlines()
-
- for line in lines:
- if not line.strip(): continue
- has_label = True
-
- # 解析坐标
- try:
- cls_id, x1, y1, x2, y2 = yolo_to_xyxy(line, w, h)
-
- # 获取颜色
- color = get_color(cls_id)
-
- # 获取标签名称
- if CLASSES and 0 <= cls_id < len(CLASSES):
- label_name = f"{CLASSES[cls_id]}"
- else:
- label_name = f"Class {cls_id}"
-
- # 画框
- plot_one_box([x1, y1, x2, y2], img, color=color, label=label_name)
- except Exception as e:
- print(f"解析错误 {label_file}: {e}")
- # 决定是否保存
- if ONLY_SHOW_LABELED and not has_label:
- continue
-
- save_path = os.path.join(OUTPUT_DIR, "vis_" + img_file)
- cv2.imwrite(save_path, img)
- # 如果想实时看,取消下面两行的注释(按任意键看下一张,按q退出)
- # cv2.imshow('Check', img)
- # if cv2.waitKey(0) == ord('q'): break
- print("处理完成!")
- cv2.destroyAllWindows()
- if __name__ == "__main__":
- main()
|