飞道的博客

Opencv项目实战:16 虚拟拖拽系统

478人阅读  评论(0)

0、项目介绍

这次使用cvzone模块,制作一个虚拟拖拽系统,我们根据索引可以知道食指与中指的索引为8和12,当两指间合并时可以对虚拟方块进行拖拽,张开时解除拖拽,方块停在此处。虽然目前仍然存在一定的bug,即当两个虚拟方块重合较多时,会使其中的一个方块消失,但我们又能利用这一点可以制作计算机视觉方面的游戏,比如贪吃蛇等。

1、效果展示

2、项目搭建

本次项目依赖于视觉方面优秀的第三方库:

pip install cvzone

pip install mediapipe

除此之外,只需要一个.py文件就能完成本次项目。

更新cvzone的方法:

打开pycharm中的设置,找到cvzone:

 

3、项目代码展示与讲解

block.py


  
  1. import cv2
  2. from cvzone.HandTrackingModule import HandDetector
  3. import cvzone
  4. import numpy as np
  5. cap = cv2.VideoCapture( 1)
  6. cap. set( 3, 1280)
  7. cap. set( 4, 720)
  8. detector = HandDetector(detectionCon= 0.8)
  9. colorR = ( 0, 0, 255)
  10. cx, cy, w, h = 100, 100, 200, 200
  11. class Moveblock():
  12. def __init__( self,posCenter,size=(200,200)):
  13. self.posCenter=posCenter
  14. self.size=size
  15. def update( self,cursor):
  16. cx,cy=self.posCenter
  17. w,h=self.size
  18. if cx - w // 2 < cursor[ 0] < cx + w // 2 and \
  19. cy - h // 2 < cursor[ 1] < cy + h // 2:
  20. self.posCenter = cursor[: 2]
  21. rectList=[]
  22. for i in range( 5):
  23. rectList.append(Moveblock((i* 250+ 150, 150)))
  24. while True:
  25. succes,img=cap.read()
  26. img = cv2.flip(img, 1)
  27. lmList ,img = detector.findHands(img)
  28. # print(lmList)
  29. if lmList:
  30. lmList1 = lmList[ 0][ "lmList"]
  31. length, info, img = detector.findDistance(lmList1[ 8][: 2],lmList1[ 12][: 2],img,draw= False)
  32. print(length)
  33. if length< 60:
  34. # lmList1 = lmList[0]["lmList"]
  35. cursor = lmList1[ 8]
  36. # print(cursor)
  37. for rect in rectList:
  38. rect.update(cursor)
  39. #实体框
  40. # for rect in rectList:
  41. # cx, cy = rect.posCenter
  42. # w, h = rect.size
  43. # cv2.rectangle(img,(cx-w//2,cy-h//2),(cx+w//2,cy+h//2),colorR,cv2.FILLED)
  44. #
  45. # cvzone.cornerRect(img,(cx-w//2,cy-h//2, w, h),20,rt=0)
  46. #半透明
  47. imgNew=np.zeros_like(img,np.uint8)
  48. for rect in rectList:
  49. cx, cy = rect.posCenter
  50. w, h = rect.size
  51. cv2.rectangle(imgNew,(cx-w// 2,cy-h// 2),(cx+w// 2,cy+h// 2),colorR,cv2.FILLED)
  52. cvzone.cornerRect(imgNew,(cx-w// 2,cy-h// 2, w, h), 20,rt= 0)
  53. out = img.copy()
  54. alpha= 0.3
  55. mask=imgNew.astype( bool)
  56. out[mask]=cv2.addWeighted(img,alpha,imgNew, 1-alpha, 0)[mask]
  57. cv2.imshow( "Image", out)
  58. k=cv2.waitKey( 1)
  59. if k== 27: break

本次依旧还是我来讲解,本次项目实现的思路吧。

  • 首先,配置摄像头这些讲过很多次了,相信大家应该也是“a piece of cake”,在cvzone包中有名为HandTrackingModule的模块,它其中其实是一个类,名为HandDetector,提高置信度,让检测到我们的手更准确。
  • 其次,cv2.flip(img,1),表示的是水平翻转图像,为什么有这一步呢?比如打开手机的前置摄像头,从我们的视线上来看,图像是保持对称的,而当我们面临摄像头时,它是相反的,即我的手向右移动,而窗口中却向左移。HandDetector下右findHands,draw参数的布尔值会返回不同的值,需要注意,你是否想要这个手势检测的边界框。在findDistance中,本来cvzone没有draw参数,我是自己添加的,当你要修改的时候,会弹出一个框是否让要修改,不怕我已经修改好了,大家把下面的复制覆盖原来的函数就好了,还有一点就是我的cvzone是最新版本的,在1.4.1及其以前有所不同,具体还是要看看里面的函数,但对于本项目,如果你只想使用,大家最好更新至1.5.6。

  
  1. def findDistance( self, p1, p2, img=None,draw=True):
  2. """
  3. Find the distance between two landmarks based on their
  4. index numbers.
  5. :param p1: Point1
  6. :param p2: Point2
  7. :param img: Image to draw on.
  8. :param draw: Flag to draw the output on the image.
  9. :return: Distance between the points
  10. Image with output drawn
  11. Line information
  12. """
  13. x1, y1 = p1
  14. x2, y2 = p2
  15. cx, cy = (x1 + x2) // 2, (y1 + y2) // 2
  16. length = math.hypot(x2 - x1, y2 - y1)
  17. info = (x1, y1, x2, y2, cx, cy)
  18. if img is not None:
  19. if draw:
  20. cv2.circle(img, (x1, y1), 15, ( 255, 0, 255), cv2.FILLED)
  21. cv2.circle(img, (x2, y2), 15, ( 255, 0, 255), cv2.FILLED)
  22. cv2.line(img, (x1, y1), (x2, y2), ( 255, 0, 255), 3)
  23. cv2.circle(img, (cx, cy), 15, ( 255, 0, 255), cv2.FILLED)
  24. return length, info, img
  25. else:
  26. return length, info
  • 然后,得到了两指尖的距离,打印出来显示一个合适的范围,摄像头距离会有所影响。接着建立类Moveblock用来创建我们的方块,其中被我注释掉的一部分,就是实心的方块,但我觉得添加一个半透明的方块可能更有意思。
  • 最后,显示窗口,展示我们的项目。

4、项目资源

GitHub:Opencv-project-training/Opencv project training/16 Virtual drag block at main · Auorui/Opencv-project-training · GitHub

5、项目总结

本次的项目还是有点小缺点,当两个方块重合太多时,会让另外的虚拟方块消失,目前还没有解决,但利用这个bug,也还是可以做一些其他项目,比如碰到另外的物体,被触的物体消失,这个想法我觉得运用还是挺多的。


转载:https://blog.csdn.net/m0_62919535/article/details/127896093
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场