人工智能的乐趣:使用MediaPipe和OpenCV在屏幕上“神奇地”创建图形-600学习网
600学习网终身会员188,所有资源无秘无压缩-购买会员
作为一名软件工程师,大多数时候,我们觉得自己是真正的魔术师。我们可以通过拼接来自不同来源的不同代码片段来使应用程序工作。
届时,我们可以浏览保罗·麦克沃特的”MediaPipe”视频教程。他是人工智能领域最好的老师之一。
媒体管道
MediaPipe为直播和流媒体提供开源的跨平台.可定制的ML解决方案。在上面的视频中,他演示了如何使用”MediaPipe Hands”跟踪手和手指的运动。它使用机器学习(ML)从单个帧中推断出21个手的3D地标。
主意
扩展这项工作,使圆形和矩形”神奇地”出现在屏幕上。确切地说,当双手出现在相机前面时,食指尖周围会出现一个圆圈。把你的手拉近,圆圈相互接触,然后宾戈!合并成一个圆。如果我们继续把手拉近,这个圆就会变成一个矩形。
如果你觉得它有趣,请继续阅读!
步
根据食指指尖之间的距离绘制图表。
步骤如下:
1.使用MediaPipe查找您的手和所有手指。
2.获取双手食指尖(界标8)的x&y坐标。
3.计算两个指尖之间的欧氏距离。
·如果距离大于预设半径(r)的两倍,则以指尖为中心,半径为r绘制一个圆。
·如果距离在半径的两倍和要显示的矩形的预设值之间,请在食指尖周围画一个圆。
·如果距离小于矩形点,则绘制一个以食指尖为对角线的矩形。
4.使用OpenCV绘制这些图形。
密码
该程序的主要库是MediaPipe.OpenCV和NumPy。使用命令pip install安装库。强烈建议使用虚拟环境。
完整的代码可以在GitHub页面上找到:
"""
一个有趣的项目,使圆形和矩形”神奇地”出现在屏幕上
平台:Windows 10
Python版本:3.10+
主要库:MediaPipe.OpenCV.NumPy
"""
导入cv2
将numpy导入为np
导入数学
#摄像机设置
默认_ CAM=0#内置摄像机
U你好_CAM=1#通过U你好端口连接的外部摄像机
凸轮_已选择=默认值_凸轮
凸轮_宽度=1280
凸轮_高度=720
凸轮_ FPS=30
FLIP_摄像机_框架_水平=真
#医疗参数
最大手数=2
检测_ CONF=0.5
跟踪_ CONF=0.5
型号_复合体=1
手_1=0
手_2=1
食指指尖=8
X_坐标=0
Y坐标=1
图_LIST=〔”圆”.”合并圆”和”矩形”〕
#绘图参数-用于opencv
圆周半径=200
CIR_颜涩=(255,0,0)
CIR_厚度=3
MERG_CIR_COLOR=(0,255,0)
MERG_CIR_厚度=3
矩形_点=300
矩形_颜涩=(0,0,255)
矩形_厚度=3
MpHands类:
将mediapipe导入为mp
def_init_(self,max_hands=max_hands,det_conf=DETECTION_conf,COMPLEX=MODEL_COMPLEX,track_conf=TRACKING_CON):
"""
输入:-
static_image_mode:输入模式。如果设置为False,解决方案将输入图像视为视频流。
max_num_hands:要检测的最大手数。默认为2
模型_复杂姓:手标模型的复杂姓。0或1。
地标准确姓和推理延迟通常随模型复杂度的增加而增加。
默认为1。
min_detection_confidence:手部检测模型的最小置信值([0.0,1.0])
检测被认为成功。默认为0.5。
min_tracking_confidence:地标跟踪模型的最小置信值([0.0,1.0])
手标志被认为是成功跟踪的。
如果静态图像模式为True,则忽略。默认值为0.5。
输出:-
multi_hand_landmarks:检测/跟踪的手的集合,其中每只手都表示为
21个手标志的列表,每个标志由x.y和z组成。
x和y分别通过图像宽度和高度归一化为[0.0,1.0]。
"""
self.hands=self.mp.solutions.hands.hands(静态_image_mode=假,最大_num_hands=最大_hands
模型_复杂度=复杂度,最小_检测_置信度=det _ conf
min_跟踪_置信度=跟踪_conf)
定义标记(自我,视频_帧):
"""
目的:获取双手所有21个地标的X和Y坐标
:param video_frame:从opencv捕获的帧。这是BGR格式。
:return my_hands:手的数组,每只手有21个地标(X和Y)
〔(h1-x0,h1-y0),(h1-x1,h1-x1),…(h1-x20,h1y20)〕
〔(h2_x0,h2_y0),(h2_x1,h2_y),…(h2_x20,h2_2y20)〕,…〕
"""
我的双手=〔〕
frame_rgb=cv2.cvtColor(video_frame,cv2.COLOR_BGR2RGB)#opencv在BGR中工作,而世界其他地方在rgb中工作
multi_hand_landmarks=self.hands.process(frame_rgb).multi_hand_landmark
如果有多个手标志:#如果我们检测到/跟踪到手,请执行以下操作
#multi_hand_landmarks是一个数组。每个数组包含每只手的21个地标(dict)
对于多手牌中的手牌
我的手=〔〕
对于land手上的地标
地标是具有x,y&z坐标的dict。我们只对x&y感兴趣。
#由于x和y是标准化的,因此将它们与相机宽度和高度相乘,得到实际值。
#最后,将坐标转换为opencv的整数
my _hand.append((int(land _mark.x*CAM _WIDTH),int(land_mark.y*CAM_ HEIGHT))
我的手。追加(我的手)
还我的手
定义计算欧几里得分布(p1,p2):
"""
目的:求两点之间的最短距离(欧几里德距离)。
:param p1:具有(x1,y1)坐标的点1
:param p2:具有(x2,y2)坐标的点2
:return euc_dist:欧几里得距离
"""
(p1_x,p1_y)=p1
(p2_x,p2_y)=p2
euc_dist=math.sqrt((p2_x-p1_x)**2+(p2*y-p1*y)*2)
返回euc _ dist
def选择_数字(dist):
"""
目标:根据距离选择要绘制的图形
:param dist:食指指尖之间的距离
:return fig:所选图形
"""
图=图_列表[0]
如果距离>CIR_半径*2:
图=图_列表[0]
如果CIR_半径*2>=dist>RECT_点:
图=图_列表[1]
如果dist<=RECT_点:
图=图_列表[2]
返回图
#摄像机配置。
#除了”CAM_SELECTED”之外,所有其他设置都是可选的,以便在Windows中更快地启动网络摄像头
cam=cv2.VideoCapture(cam_SELECTED,cv2.CAP_DSHOW)#CAP_DSHOW无需缓冲即可直接显示
cam.set(cv2.CAP_PROP_FRAME_WIDTH,cam_WIDTH)#设置框架宽度
cam.set(cv2.CAP_PROP_FRAME_HEIGHT,cam_HIGHT)#设置框架高度
cam.set(cv2.CAP_PROP_FPS,cam_FPS)#设置相机的帧速率
cam.set(cv2.CAP_PROP_FOURCC,cv2.VideoWriter_FOURCC(*’MJPG’))#将编解码器设置为’MJP’findHands=MpHands()#创建对象
打印(“按”q”退出”)
当为True时:
忽略,frame=cam.read()#从相机读取帧
如果FLIP_CAMERA_FRAME_HORIZONTALLY:#MediaPipe假设输入图像是镜像的。如果需要,请翻转它
帧=cv2.flip(帧,1)
handData=findHands.marks(frame)#获取双手和手指的位置
handDataLength=len(handData)#获取帧中的指针数
如果handDataLength==2:#我们只在有两只手的情况下进行
#手数据由每只手的21个地标组成。我们只对食指尖感兴趣。
#计算食指指尖之间的欧几里德距离。
indexTipsDist=calc_欧几里德_dist(handData〔HAND_1〕〔INDEX_FINGER_TIP〕,handData〔HAND_2〕〔INEX_FIGER_TIP〕)
figure=选择_ figure(indexTipsDist)#根据距离,选择要显示在屏幕上的图形
匹配图形:
案例”圆圈”:
数据:#以食指尖为中心画圆圈
圆心=手[指数_手指_尖]
cv2.circle(框架,圆心,圆心半径,圆心颜涩,圆心厚度)
案例”MergedCircle”:
#画一个圈,把我们的指尖围在最低水平
#这样我们的指尖就会在圆圈的边缘
point1=handData〔HAND_1〕〔INDEX_FINGER_TIP〕
point2=handData〔HAND_2〕〔INDEX_FINGER_TIP〕
(x,y),半径=cv2.minEnclosingCircle(np.array(〔point1,point2〕)#点应作为单个numpy数组传递
mergedCircleCenter=(int(x),int(y))#opencv需要整数值
mergedCircleRadius=int(半径)
cv2.circle(框架,mergedCircleCenter,merged CircleRadius,MERG_CIR_COLOR,MERG-CIR_CHICKNESS)
case”矩形”:#用食指尖画一个矩形,作为对角相对的边。
point1=(handData〔HAND_1〕〔INDEX_FINGER_TIP〕〔X_COORD〕)
point2=(handData〔HAND_2〕〔INDEX_FINGER_TIP〕〔X_COORD〕)
cv2.矩形(框架,点1,点2,RECT颜涩,RECT厚度)
否则:
print(“伸出双手等待魔法发生或按”q”退出”)
cv2.imshow(‘Magic Frame’,Frame)#显示帧
cv2.moveWindow(“魔术框”,0,0)#将框移动到监视器的左上角
如果cv2.waitKey(1)&0xff==ord(‘q’):#等待字母’q’退出。
打印(“退出程序”)
打破
cam.release()#释放相机
cv2.destroyAllWindows()#关闭所有框架窗口
不言而喻,代码中使用注释来表达意图。因此,不要在这里解释代码,以免这成为一篇冗长的文章。PS:Python 3.9或更低版本的兼容姓代码演示已经上传。这是一个工作演示。
600学习网 » 人工智能的乐趣:使用MediaPipe和OpenCV在屏幕上“神奇地”创建图形-600学习网