testimg.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import cv2
  2. import os
  3. import random
  4. # ================= 配置区域 =================
  5. # 1. 图片文件夹路径
  6. IMG_DIR = r'20251204\images'
  7. # 2. 标签文件夹路径 (YOLO格式的txt)
  8. LABEL_DIR = r'20251204\labels'
  9. # 3. 结果保存路径 (如果不填,默认在当前目录下生成 'output' 文件夹)
  10. OUTPUT_DIR = r'output_result'
  11. # 4. 类别名称列表 (按 classes.txt 的顺序或者是你的模型定义的顺序)
  12. # 如果不知道名字,可以留空,代码会直接显示 ID (如 '0', '1')
  13. CLASSES = ['fire', 'fust']
  14. # CLASSES = [] # 如果不想显示名字,保持为空列表即可
  15. # 5. 是否只显示有标签的图片?(True: 跳过无标签图片; False: 显示所有)
  16. ONLY_SHOW_LABELED = True
  17. # ===========================================
  18. def get_color(cls_id):
  19. """为每个类别生成固定的随机颜色"""
  20. random.seed(cls_id * 10) # 保证同一个类别的颜色在不同图片中是一样的
  21. b = random.randint(0, 255)
  22. g = random.randint(0, 255)
  23. r = random.randint(0, 255)
  24. return (b, g, r)
  25. def plot_one_box(x, img, color=None, label=None, line_thickness=None):
  26. """画框的主函数"""
  27. tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # 线宽
  28. c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3]))
  29. cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA)
  30. if label:
  31. tf = max(tl - 1, 1) # 字体粗细
  32. t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0]
  33. c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3
  34. cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA) # 填充文字背景
  35. cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA)
  36. def yolo_to_xyxy(yolo_line, img_w, img_h):
  37. """将YOLO格式 (class x_center y_center w h) 转换为 (x1, y1, x2, y2)"""
  38. parts = yolo_line.strip().split()
  39. cls_id = int(parts[0])
  40. x_c = float(parts[1])
  41. y_c = float(parts[2])
  42. w = float(parts[3])
  43. h = float(parts[4])
  44. # 还原为像素坐标
  45. x1 = int((x_c - w / 2) * img_w)
  46. y1 = int((y_c - h / 2) * img_h)
  47. x2 = int((x_c + w / 2) * img_w)
  48. y2 = int((y_c + h / 2) * img_h)
  49. # 边界保护,防止画出图片外
  50. x1 = max(0, x1)
  51. y1 = max(0, y1)
  52. x2 = min(img_w, x2)
  53. y2 = min(img_h, y2)
  54. return cls_id, x1, y1, x2, y2
  55. def main():
  56. if not os.path.exists(OUTPUT_DIR):
  57. os.makedirs(OUTPUT_DIR)
  58. print(f"开始处理... 结果将保存到: {OUTPUT_DIR}")
  59. img_files = [f for f in os.listdir(IMG_DIR) if f.lower().endswith(('.jpg', '.jpeg', '.png', '.bmp'))]
  60. for img_file in img_files:
  61. img_path = os.path.join(IMG_DIR, img_file)
  62. label_file = os.path.splitext(img_file)[0] + '.txt'
  63. label_path = os.path.join(LABEL_DIR, label_file)
  64. # 读取图片
  65. img = cv2.imread(img_path)
  66. if img is None:
  67. continue
  68. h, w, _ = img.shape
  69. has_label = False
  70. # 检查是否有对应的txt文件
  71. if os.path.exists(label_path):
  72. with open(label_path, 'r') as f:
  73. lines = f.readlines()
  74. for line in lines:
  75. if not line.strip(): continue
  76. has_label = True
  77. # 解析坐标
  78. try:
  79. cls_id, x1, y1, x2, y2 = yolo_to_xyxy(line, w, h)
  80. # 获取颜色
  81. color = get_color(cls_id)
  82. # 获取标签名称
  83. if CLASSES and 0 <= cls_id < len(CLASSES):
  84. label_name = f"{CLASSES[cls_id]}"
  85. else:
  86. label_name = f"Class {cls_id}"
  87. # 画框
  88. plot_one_box([x1, y1, x2, y2], img, color=color, label=label_name)
  89. except Exception as e:
  90. print(f"解析错误 {label_file}: {e}")
  91. # 决定是否保存
  92. if ONLY_SHOW_LABELED and not has_label:
  93. continue
  94. save_path = os.path.join(OUTPUT_DIR, "vis_" + img_file)
  95. cv2.imwrite(save_path, img)
  96. # 如果想实时看,取消下面两行的注释(按任意键看下一张,按q退出)
  97. # cv2.imshow('Check', img)
  98. # if cv2.waitKey(0) == ord('q'): break
  99. print("处理完成!")
  100. cv2.destroyAllWindows()
  101. if __name__ == "__main__":
  102. main()