import cv2 import numpy as np from ultralytics import YOLO # ====================== 用户配置 ====================== MODEL_PATH = 'best.pt' IMAGE_PATH = '/media/hx/04e879fa-d697-4b02-ac7e-a4148876ebb0/dataset/point2/train/1.jpg' # 👈 修改为你的具体图像路径 OUTPUT_DIR = './output_images' # 固定点(例如标定得到的理论位置) FIXED_REF_POINT = (535.0, 605)# (x, y),单位:像素 def calculate_scale(width_mm, width_px): """ 计算缩放因子(单位:mm/px) :param width_mm: 实际宽度(单位:毫米) :param width_px: 宽度的像素数量 :return: 缩放因子(单位:mm/px) """ if width_px == 0: print("像素宽度不能为0") return None return width_mm / float(width_px) # 示例使用: # 假设我们知道一个参考物体的实际宽度是50毫米,在图像中占据100个像素 width_mm = 70.0 # 实际宽度(单位:毫米) width_px = 42 # 在图像中的宽度(单位:像素) SCALE_X= calculate_scale(width_mm, width_px) print(f"水平方向的缩放因子为: {SCALE_X:.3f} mm/px") def calculate_scale_y(height_mm, height_px): """ 计算垂直方向的缩放因子(单位:mm/px) :param height_mm: 实际高度(单位:毫米) :param height_px: 高度的像素数量 :return: 缩放因子(单位:mm/px) """ if height_px == 0: print("像素高度不能为0") return None return height_mm / float(height_px) # 同样地,对于高度来说 height_mm = 890.0 # 实际高度(单位:毫米) height_px = 507 # 在图像中的高度(单位:像素) SCALE_Y = calculate_scale_y(height_mm, height_px) print(f"垂直方向的缩放因子为: {SCALE_Y:.3f} mm/px") # 创建输出目录 import os os.makedirs(OUTPUT_DIR, exist_ok=True) # ====================== 可视化函数(增强版)====================== def draw_keypoints_and_offset(image, kpts_xy, kpts_conf, orig_shape, fixed_point, scale_x, scale_y): """ 在图像上绘制关键点、中心点、参考点、偏移箭头和文本 :param image: OpenCV 图像 :param kpts_xy: (N, K, 2) 坐标 :param kpts_conf: (N, K) 置信度 :param orig_shape: 原图尺寸 (H, W) :param fixed_point: 固定参考点 (fx, fy) :param scale_x: x方向缩放 mm/px :param scale_y: y方向缩放 mm/px :return: 处理后的图像,偏移信息列表 """ colors = [(0, 0, 255), (255, 0, 0), (0, 255, 0), (255, 255, 0)] # 1红, 2蓝, 3绿, 4青 results_info = [] for i in range(len(kpts_xy)): xy = kpts_xy[i] # (K, 2) conf = kpts_conf[i] if kpts_conf.ndim == 2 else kpts_conf[i:i+1] # 检查是否有至少两个关键点 if len(xy) < 2: print(f"⚠️ 实例 {i} 的关键点数量不足2个") continue p1 = xy[0] # 第一个关键点 p2 = xy[1] # 第二个关键点 c1 = conf[0] if hasattr(conf, '__len__') else conf c2 = conf[1] if hasattr(conf, '__len__') else conf if c1 < 0.5 or c2 < 0.5: print(f"⚠️ 实例 {i} 的前两个关键点置信度过低: c1={c1:.3f}, c2={c2:.3f}") continue # 转为整数坐标(仅用于绘制) p1_int = tuple(map(int, p1)) p2_int = tuple(map(int, p2)) h, w = orig_shape valid = all(0 <= x < w and 0 <= y < h for x, y in [p1, p2]) if not valid: print(f"⚠️ 实例 {i} 的关键点超出图像边界") continue # 绘制前两个关键点 cv2.circle(image, p1_int, radius=15, color=colors[0], thickness=-1) # 红色 cv2.circle(image, p2_int, radius=15, color=colors[1], thickness=-1) # 蓝色 # 标注编号 cv2.putText(image, "1", (p1_int[0] + 20, p1_int[1] - 20), cv2.FONT_HERSHEY_SIMPLEX, 1.5, colors[0], 5) cv2.putText(image, "2", (p2_int[0] + 20, p2_int[1] - 20), cv2.FONT_HERSHEY_SIMPLEX, 1.5, colors[1], 5) center_x = (p1[0] + p2[0]) / 2.0 center_y = (p1[1] + p2[1]) / 2.0 dynamic_center = (int(center_x), int(center_y)) cv2.circle(image, dynamic_center, radius=18, color=(0, 255, 0), thickness=3) cv2.putText(image, "Center", (dynamic_center[0] + 30, dynamic_center[1]), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (0, 255, 0), 3) fx, fy = map(int, fixed_point) cv2.circle(image, (fx, fy), radius=20, color=(255, 255, 0), thickness=3) cv2.putText(image, "Ref", (fx + 30, fy), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (255, 255, 0), 3) dx_px = center_x - fixed_point[0] dy_px = center_y - fixed_point[1] dx_mm = dx_px * scale_x dy_mm = dy_px * scale_y cv2.arrowedLine(image, (fx, fy), dynamic_center, (0, 255, 255), 3, tipLength=0.05) cv2.putText(image, f"ΔX={dx_mm:+.1f}mm", (fx + 40, fy - 40), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 255), 3) cv2.putText(image, f"ΔY={dy_mm:+.1f}mm", (fx + 40, fy + 40), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 255), 3) results_info.append({ 'instance': i, 'center': (center_x, center_y), 'dx_px': dx_px, 'dy_px': dy_px, 'dx_mm': dx_mm, 'dy_mm': dy_mm }) return image, results_info if __name__ == "__main__": img = cv2.imread(IMAGE_PATH) if img is None: print(f"❌ 无法读取图像,检查路径: {IMAGE_PATH}") exit(1) model = YOLO(MODEL_PATH) results = model(img) for i, result in enumerate(results): if result.keypoints is not None: kpts = result.keypoints orig_shape = kpts.orig_shape kpts_xy = kpts.xy.cpu().numpy() kpts_conf = kpts.conf.cpu().numpy() if kpts.conf is not None else np.ones(kpts_xy.shape[:2]) img_with_kpts = img.copy() img_with_kpts, offset_results = draw_keypoints_and_offset( img_with_kpts, kpts_xy, kpts_conf, orig_shape, fixed_point=FIXED_REF_POINT, scale_x=SCALE_X, scale_y=SCALE_Y ) for info in offset_results: print(f" 📌 实例 {info['instance']}: " f"ΔX={info['dx_mm']:+.2f}mm, ΔY={info['dy_mm']:+.2f}mm") save_filename = f"offset_{os.path.basename(IMAGE_PATH)}" save_path = os.path.join(OUTPUT_DIR, save_filename) cv2.imwrite(save_path, img_with_kpts) print(f" 💾 结果已保存: {save_path}")