Files
2025-09-01 14:14:18 +08:00

140 lines
5.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import cv2
import numpy as np
from ultralytics import YOLO
import time
import os
# ====================== 用户配置 ======================
MODEL_PATH = "/home/hx/yolo/ultralytics_yolo11-main/runs/train/point/exp_pose2/weights/best.pt"
IMAGE_PATH = "/home/hx/yolo/output_masks/3.png"
SAVE_RESULT = True
SAVE_PATH = "/home/hx/yolo/test_image/result_with_angle2.jpg"
SHOW_IMAGE = True
# 关键点颜色:红、绿、蓝(对应 kpt 1, 2, 3
KPT_COLORS = [
(0, 0, 255), # 红色 - kpt 1
(0, 255, 0), # 绿色 - kpt 2
(255, 0, 0), # 蓝色 - kpt 3
]
# ====================== 计算两向量夹角0~180°=======================
def calculate_angle_between_vectors(v1, v2):
"""
计算两个向量之间的夹角(单位:度),范围 0 ~ 180°
"""
v1 = np.array(v1)
v2 = np.array(v2)
if np.linalg.norm(v1) == 0 or np.linalg.norm(v2) == 0:
return 0.0
v1_u = v1 / np.linalg.norm(v1)
v2_u = v2 / np.linalg.norm(v2)
dot = np.clip(np.dot(v1_u, v2_u), -1.0, 1.0)
angle_rad = np.arccos(dot)
angle_deg = np.degrees(angle_rad)
return angle_deg
# ====================== 主程序 =======================
if __name__ == "__main__":
print("正在加载模型...")
try:
model = YOLO(MODEL_PATH)
print(f"✅ 模型加载完成: {MODEL_PATH}")
except Exception as e:
print(f"❌ 模型加载失败: {e}")
exit(1)
# 读取图像
img = cv2.imread(IMAGE_PATH)
if img is None:
raise FileNotFoundError(f"❌ 无法加载图像: {IMAGE_PATH}")
h, w = img.shape[:2]
print(f"✅ 图像加载成功: {IMAGE_PATH} ({w}x{h})")
# --- 推理 ---
results = model(img, conf=0.25, imgsz=1280)
result = results[0]
# 存储每个实例的关键点和置信度
instances = []
if result.keypoints is not None and result.boxes is not None:
kpts_list = result.keypoints.xy.cpu().numpy() # (N, K, 2)
confs = result.boxes.conf.cpu().numpy() # (N,)
bboxes = result.boxes.xyxy.cpu().numpy() # (N, 4)
# 组合:置信度 + 关键点 + 边框
for i in range(len(kpts_list)):
if len(kpts_list[i]) >= 2: # 至少有两个关键点
kpt1 = (int(kpts_list[i][0][0]), int(kpts_list[i][0][1]))
kpt2 = (int(kpts_list[i][1][0]), int(kpts_list[i][1][1]))
instances.append({
'conf': confs[i],
'kpt1': kpt1,
'kpt2': kpt2,
'bbox': bboxes[i]
})
# 按置信度降序排序
instances.sort(key=lambda x: x['conf'], reverse=True)
# 只保留置信度最高的两个实例
top_two = instances[:2]
if len(top_two) == 2:
inst1, inst2 = top_two
# 绘制第一个实例的关键点和连线
cv2.circle(img, inst1['kpt1'], 10, KPT_COLORS[0], -1)
cv2.circle(img, inst1['kpt2'], 10, KPT_COLORS[1], -1)
cv2.line(img, inst1['kpt1'], inst1['kpt2'], (255, 255, 0), 3) # 黄色线
cv2.putText(img, "1", (inst1['kpt1'][0]+10, inst1['kpt1'][1]-10),
cv2.FONT_HERSHEY_SIMPLEX, 1.0, KPT_COLORS[0], 2)
cv2.putText(img, "2", (inst1['kpt2'][0]+10, inst1['kpt2'][1]-10),
cv2.FONT_HERSHEY_SIMPLEX, 1.0, KPT_COLORS[1], 2)
# 绘制第二个实例的关键点和连线
cv2.circle(img, inst2['kpt1'], 10, KPT_COLORS[0], -1)
cv2.circle(img, inst2['kpt2'], 10, KPT_COLORS[1], -1)
cv2.line(img, inst2['kpt1'], inst2['kpt2'], (0, 255, 255), 3) # 青色线
cv2.putText(img, "1", (inst2['kpt1'][0]+10, inst2['kpt1'][1]-10),
cv2.FONT_HERSHEY_SIMPLEX, 1.0, KPT_COLORS[0], 2)
cv2.putText(img, "2", (inst2['kpt2'][0]+10, inst2['kpt2'][1]-10),
cv2.FONT_HERSHEY_SIMPLEX, 1.0, KPT_COLORS[1], 2)
# 构造两个向量kpt2 - kpt1
vec1 = np.array([inst1['kpt2'][0] - inst1['kpt1'][0],
inst1['kpt2'][1] - inst1['kpt1'][1]])
vec2 = np.array([inst2['kpt2'][0] - inst2['kpt1'][0],
inst2['kpt2'][1] - inst2['kpt1'][1]])
# 计算夹角
angle = calculate_angle_between_vectors(vec1, vec2)
print(f"✅ 置信度最高的两个实例其关键点1-2连线夹角: {angle:.1f}°")
# 在图像上显示角度
cv2.putText(img, f"Angle: {angle:.1f}°", (50, 50),
cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 255, 255), 3, lineType=cv2.LINE_AA)
else:
print(f"⚠️ 检测到 {len(top_two)} 个有效实例需要至少2个")
else:
print("⚠️ 未检测到关键点或边界框")
# --- 保存结果 ---
os.makedirs(os.path.dirname(SAVE_PATH), exist_ok=True)
if SAVE_RESULT:
cv2.imwrite(SAVE_PATH, img)
print(f"✅ 结果图像已保存至: {SAVE_PATH}")
# --- 显示图像 ---
if SHOW_IMAGE:
cv2.imshow("Keypoint Angle Between Two Best Instances", img)
print("👉 按任意键关闭窗口...")
cv2.waitKey(0)
cv2.destroyAllWindows()