Files

140 lines
5.2 KiB
Python
Raw Permalink Normal View History

2025-09-01 14:14:18 +08:00
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()