您的位置:首页 > 新闻 > 热点要闻 > seo百科大全_推广普通话文字内容_黑五类广告推广_创建网站的流程是什么

seo百科大全_推广普通话文字内容_黑五类广告推广_创建网站的流程是什么

2025/5/13 12:05:11 来源:https://blog.csdn.net/zhoujinwang/article/details/146053977  浏览:    关键词:seo百科大全_推广普通话文字内容_黑五类广告推广_创建网站的流程是什么
seo百科大全_推广普通话文字内容_黑五类广告推广_创建网站的流程是什么

基于手势识别的虚拟拖拽系统

github

项目简介

这是一个基于计算机视觉的虚拟拖拽系统,通过 MediaPipe 手势识别技术,实现了对虚拟图形的直观操控。用户可以通过自然的手势来拖拽、缩放和旋转屏幕上的虚拟图形,就像在现实世界中操作物体一样。
在这里插入图片描述

核心功能

1. 多形状支持

  • 矩形:可旋转的基础图形,支持任意角度旋转
  • 圆形:完美圆形,支持无级缩放
  • 三角形:使用面积法实现精确的碰撞检测

2. 手势控制

  • 拖拽:使用食指和中指进行精确定位和移动
  • 缩放:通过大拇指和食指的捏合动作自然地调整大小
  • 旋转:在拖拽过程中旋转手指即可旋转图形
  • 复位:握拳手势可以将所有图形恢复到初始状态

3. 视觉反馈

  • 实时状态显示(拖拽/缩放/空闲)
  • FPS 计数器
  • 操作指引
  • 图形轨迹特效

技术实现

1. 手势识别系统

使用 MediaPipe 框架进行实时手部关键点检测,通过分析关键点的相对位置来识别不同的手势:

def _process_landmarks(self, hand_landmarks, resize_w: int, resize_h: int):# 获取手指关键点wrist = (landmark_list[0][1], landmark_list[0][2])          # 手腕thumb_tip = (landmark_list[4][1], landmark_list[4][2])      # 大拇指尖index_tip = (landmark_list[8][1], landmark_list[8][2])      # 食指尖middle_tip = (landmark_list[12][1], landmark_list[12][2])   # 中指尖palm_center = (landmark_list[9][1], landmark_list[9][2])    # 手掌中心# 计算手势参数drag_distance = math.hypot(middle_tip[0] - index_tip[0], middle_tip[1] - index_tip[1])scale_distance = math.hypot(index_tip[0] - thumb_tip[0], index_tip[1] - thumb_tip[1])angle = math.degrees(math.atan2(middle_tip[1] - index_tip[1], middle_tip[0] - index_tip[0]))

2. 碰撞检测系统

为不同形状实现了专门的碰撞检测算法:

  1. 圆形:使用点到圆心距离判定
if self.shape_type == ShapeType.CIRCLE:return math.hypot(point_x - self.x, point_y - self.y) <= self.size * self.scale / 2
  1. 矩形:考虑旋转角度的矩形碰撞检测
elif self.shape_type == ShapeType.RECTANGLE:# 计算旋转后的矩形顶点half_size = int(self.size * self.scale / 2)points = np.array([[-half_size, -half_size],[half_size, -half_size],[half_size, half_size],[-half_size, half_size]], dtype=np.float32)# 应用旋转变换angle = math.radians(self.rotation)rotation_matrix = np.array([[math.cos(angle), -math.sin(angle)],[math.sin(angle), math.cos(angle)]])points = np.dot(points, rotation_matrix)
  1. 三角形:使用面积法进行精确判定
elif self.shape_type == ShapeType.TRIANGLE:half_size = int(self.size * self.scale / 2)# 三角形的三个顶点top = (self.x, self.y - half_size)bottom_left = (self.x - half_size, self.y + half_size)bottom_right = (self.x + half_size, self.y + half_size)# 使用面积法判断点是否在三角形内def area(x1, y1, x2, y2, x3, y3):return abs((x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2.0)# 计算三角形总面积和子三角形面积A = area(top[0], top[1], bottom_left[0], bottom_left[1], bottom_right[0], bottom_right[1])A1 = area(point_x, point_y, bottom_left[0], bottom_left[1], bottom_right[0], bottom_right[1])A2 = area(top[0], top[1], point_x, point_y, bottom_right[0], bottom_right[1])A3 = area(top[0], top[1], bottom_left[0], bottom_left[1], point_x, point_y)

3. 图形变换系统

  1. 位置更新与轨迹记录
def update_position(self, x: int, y: int):self.trail.append((self.x, self.y))if len(self.trail) > Config.TRAIL_LENGTH:self.trail.pop(0)self.x = xself.y = y
  1. 旋转控制
def update_rotation(self, angle: float):self.rotation += angle * Config.ROTATION_SCALEself.rotation = self.rotation % 360
  1. 缩放控制
def update_scale(self, scale_factor: float):new_scale = self.scale + scale_factor * Config.SCALE_FACTORself.scale = max(Config.MIN_SCALE, min(Config.MAX_SCALE, new_scale))

4. 状态管理系统

使用 ShapeManager 类统一管理所有图形状态:

class ShapeManager:def __init__(self):self.shapes: List[Shape] = []self.active_index: int = -1self.drag_active: bool = Falseself.last_distance: float = 0self.last_angle: float = 0self.offset_x: float = 0self.offset_y: float = 0

关键状态处理:

  1. 拖拽状态
if drag_distance < self.config.DRAG_DISTANCE_THRESHOLD:shapeManager.drag_active = TrueshapeManager.set_offset(drag_center[0], drag_center[1])
  1. 缩放状态
if scale_distance < Config.SCALE_THRESHOLD:scaling_mode = TrueshapeManager.last_distance = scale_distance
  1. 复位状态
if is_fist:shapeManager.reset_all_shapes()scaling_mode = False

5. 视觉反馈系统

  1. 图形绘制
def draw(self, image: np.ndarray, is_active: bool = False) -> np.ndarray:overlay = image.copy()color = (255, 0, 255) if is_active else self.color# 绘制轨迹if len(self.trail) > 1:for i in range(len(self.trail) - 1):alpha = (i + 1) / len(self.trail) * 0.5cv2.line(overlay, self.trail[i], self.trail[i + 1], color, 2)image = cv2.addWeighted(overlay, alpha, image, 1 - alpha, 0)
  1. 状态显示
# 显示状态
mode_text = "Scaling" if scaling_mode else "Dragging" if shapeManager.drag_active else "None"
cv2.putText(self.image, f"Mode: {mode_text}", (10, 30),cv2.FONT_HERSHEY_PLAIN, 2, (0, 255, 0), 2)# 显示FPS
cv2.putText(self.image, f"FPS: {int(fps)}", (10, 70),cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 0), 3)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com