使用OpenCV和MediaPipe库——增强现实殊效(在手腕添加假造手表) ...

打印 上一主题 下一主题

主题 971|帖子 971|积分 2913


目录
代码实现思绪
整体代码
配套资源阐明
关键实现细节
效果优化
效果展示


代码实现思绪


  • 初始化

    • 使用MediaPipe库来处置惩罚人体姿势估计,特殊是手部位置。
    • 加载了一张带被抠图的手表图像(watch.png)作为要叠加到视频帧上的对象。

  • 打开摄像头并开始捕捉视频流

    • 使用OpenCV的VideoCapture类打开默认摄像头(设备ID为0),然后进入一个循环不停读取视频帧。

  • 姿势检测

    • 每一帧首先被转换为RGB格式,因为MediaPipe需要RGB输入。
    • 利用mp_pose.Pose举行人体姿势猜测,并将结果生存在results变量中。

  • 坐标变更和手表图像处置惩罚

    • 从姿势猜测结果中获取左手腕的关键点坐标,并将其归一化坐标转换为实际像素坐标。
    • 根据手腕的位置调解手表图像的巨细,并盘算出它应该放置的具体位置,确保手表中央与手腕关键点对齐。
    • 分离手表图像的Alpha通道(即透明度信息),用于后续的图像混合操作。

  • 图像混合

    • 将手表图像按照盘算好的位置叠加到视频帧上。这个过程涉及到利用Alpha通道对手表图像和原始视频帧举行加权混合,以保证手表图像可以大概正确表现其透明部分。

  • 绘制关键点(可选)

    • 在视频帧上绘制出所有检测到的人体关键点和它们之间的连线,资助可视化检测结果。

  • 展示结果

    • 表现最终合成后的图像。假如用户按下键盘上的“q”键,则退出循环并关闭所有窗口,克制视频捕捉。

  • 资源释放

    • 循环结束后,释放摄像头资源并关闭所有OpenCV创建的窗口。




整体代码

  1. import cv2
  2. import mediapipe as mp
  3. import numpy as np  #  numpy 用于图像混合
  4. # 初始化 MediaPipe 组件
  5. mp_drawing = mp.solutions.drawing_utils
  6. mp_pose = mp.solutions.pose
  7. # 加载带透明通道的手表图片 (PNG格式)
  8. watch_img = cv2.imread("watch.png", cv2.IMREAD_UNCHANGED)  # 确保图片路径正确
  9. if watch_img is None:
  10.     raise FileNotFoundError("手表图片未找到,请检查 watch.png 文件路径")
  11. # 打开摄像头
  12. cap = cv2.VideoCapture(0)
  13. # 初始化姿势检测
  14. with mp_pose.Pose(
  15.         min_detection_confidence=0.7,
  16.         min_tracking_confidence=0.7
  17. ) as pose:
  18.     while cap.isOpened():
  19.         success, frame = cap.read()
  20.         if not success:
  21.             break
  22.         # 转换为 RGB 格式并进行姿势检测
  23.         image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
  24.         results = pose.process(image)
  25.         # 转换回 BGR 用于显示
  26.         image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
  27.         if results.pose_landmarks:
  28.             # ============== 关键点获取 ==============
  29.             # 获取左手腕关键点
  30.             LEFT_WRIST = mp_pose.PoseLandmark.LEFT_WRIST
  31.             wrist_landmark = results.pose_landmarks.landmark[LEFT_WRIST]
  32.             # 获取图像尺寸
  33.             h, w, _ = image.shape
  34.             # 将归一化坐标转换为像素坐标
  35.             wrist_x = int(wrist_landmark.x * w)
  36.             wrist_y = int(wrist_landmark.y * h)
  37.             # ============== 手表处理 ==============
  38.             # 调整手表大小(原图尺寸的 1/4)
  39.             scale_factor = 0.25
  40.             watch_h, watch_w = int(watch_img.shape[0] * scale_factor), int(watch_img.shape[1] * scale_factor)
  41.             resized_watch = cv2.resize(watch_img, (watch_w, watch_h))
  42.             # 计算叠加位置(使手表中心对准手腕)
  43.             y_start = wrist_y - watch_h // 2
  44.             y_end = y_start + watch_h
  45.             x_start = wrist_x - watch_w // 2
  46.             x_end = x_start + watch_w
  47.             # 确保不会超出画面边界
  48.             if y_start >= 0 and y_end <= h and x_start >= 0 and x_end <= w:
  49.                 # 分离 Alpha 通道
  50.                 alpha = resized_watch[:, :, 3] / 255.0
  51.                 inverse_alpha = 1 - alpha
  52.                 # 按通道混合图像
  53.                 for c in range(3):
  54.                     image[y_start:y_end, x_start:x_end, c] = \
  55.                         resized_watch[:, :, c] * alpha + \
  56.                         image[y_start:y_end, x_start:x_end, c] * inverse_alpha
  57.             # ============== 绘制关键点(可选) ==============
  58.             mp_drawing.draw_landmarks(
  59.                 image,
  60.                 results.pose_landmarks,
  61.                 mp_pose.POSE_CONNECTIONS,
  62.                 landmark_drawing_spec=mp_drawing.DrawingSpec(color=(120, 220, 160), thickness=2),
  63.                 connection_drawing_spec=mp_drawing.DrawingSpec(color=(120, 160, 220), thickness=2)
  64.             )
  65.             # 显示画面
  66.             cv2.imshow('AR Watch Demo', image)
  67.             if cv2.waitKey(1) & 0xFF == ord('q'):
  68.                 break
  69. cap.release()
  70. cv2.destroyAllWindows()
复制代码


配套资源阐明


  • 手表图片要求

    • 格式:PNG(带透明通道)
    • 推荐尺寸:500x500 像素左右
    • 示例图片(可通过搜索引擎查找 "watch png transparent")

  • 文件布局
    1. your_project_folder/
    2. ├── ar_watch_demo.py  # 代码文件
    3. └── watch.png         # 手表素材
    复制代码

关键实现细节


  • 坐标转换
    1. wrist_x = int(wrist_landmark.x * w)  # 将归一化坐标转换为实际像素坐标
    2. wrist_y = int(wrist_landmark.y * h)
    复制代码

  • 透明图像混合
    1. alpha = resized_watch[:, :, 3] / 255.0  # 提取 Alpha 通道并归一化
    2. for c in range(3):  # 对 RGB 通道分别混合
    3.     image[y1:y2, x1:x2, c] = \
    4.         resized_watch[:, :, c] * alpha + \
    5.         image[y1:y2, x1:x2, c] * (1 - alpha)
    复制代码

  • 边界保护
    1. if y_start >= 0 and y_end <= h and x_start >=0 and x_end <= w:
    2.     # 仅当手表完全在画面内时才进行叠加
    复制代码
      
    效果优化
  • 动态巨细调解
    1. # 根据手腕到摄像头的距离动态调整大小(需计算深度信息)
    2. scale_factor = 0.2 + 0.1 * (wrist_landmark.z * 10)  # z 值为估计的深度
    复制代码

  • 旋转适配
    1. # 获取前臂方向(手腕-手肘向量)
    2. LEFT_ELBOW = mp_pose.PoseLandmark.LEFT_ELBOW
    3. elbow_landmark = results.pose_landmarks.landmark[LEFT_ELBOW]
    4. angle = np.arctan2(wrist_y - elbow_y, wrist_x - elbow_x)
    5. rotated_watch = cv2.warpAffine(resized_watch, ...)  # 应用旋转矩阵
    复制代码

  • 性能优化
    1. cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)  # 降低分辨率到 640x480
    2. cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
    复制代码
      

效果展示








免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

熊熊出没

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表