小言_互联网的博客

实战 | 用Python 和 OpenCV搭建老人跌倒智能监测系统 (步骤 + 源码)

391人阅读  评论(0)

一个不知名大学生,江湖人称菜狗
original author: jacky Li
Email : 3435673055@qq.com

 Time of completion:2023.2.4
Last edited: 2023.2.4

导读

本文将使用Python、OpenCV和MediaPipe搭建一个老人跌倒智能监测系统。

目录

背景介绍

实现步骤

【1】导入必要的模块:

【2】定义一个计算角度的函数:

【3】查找坐标:

【4】如何知道主体(老人)是安全的还是跌倒的?

【5】如何区分床和地板?

【6】让我们在屏幕上打印结果:

【7】添加图形用户界面:

作者有言


背景介绍

    老人监测系统是一种智能检测系统,可以检测老人是否躺在床上或是否跌倒在地。这是一个解决实际问题的程序,可用于在您外出工作或外出时监控家中的老人,以便在出现任何问题时通知您。

实现步骤

【1】导入必要的模块:

    在 python 中导入 Numpy、MediaPipe 和 opencv


  
  1. import cv2
  2. import mediapipe as mp
  3. import numpy as np

【2】定义一个计算角度的函数:

    由于我们将根据我们使用 OpenCV 获得的角度和坐标来假设一个人是在行走还是跌倒在地上,因此,我们必须计算角度,最简单的方法是定义一个函数,然后调用它在程序中。


  
  1. def calculate_angle( a,b,c):
  2. a = np.array(a) # First
  3. b = np.array(b) # Mid
  4. c = np.array(c) # End
  5. radians = np.arctan2(c[ 1]-b[ 1], c[ 0]-b[ 0]) - np.arctan2(a[ 1]-b[ 1], a[ 0]-b[ 0])
  6. angle = np. abs(radians* 180.0/np.pi)
  7. if angle > 180.0:
  8. angle = 360-angle
  9. return angle

【3】查找坐标:

    我们还必须找到坐标,以便我们可以在条件下使用它们,也可以将它们与calculate_angle函数一起使用。


  
  1. left_eye = [landmarks[mp_pose.PoseLandmark.LEFT_EYE.value].x,landmarks[mp_pose.PoseLandmark.LEFT_EYE.value].y]
  2. left_hip= [landmarks[mp_pose.PoseLandmark.LEFT_HIP.value].x,landmarks[mp_pose.PoseLandmark.LEFT_HIP.value].y]
  3. left_heel = [landmarks[mp_pose.PoseLandmark.LEFT_HEEL.value].x,landmarks[mp_pose.PoseLandmark.LEFT_HEEL.value].y]
  4. right_eye = [landmarks[mp_pose.PoseLandmark.RIGHT_EYE.value].x,landmarks[mp_pose.PoseLandmark.RIGHT_EYE.value].y]
  5. right_hip = [landmarks[mp_pose.PoseLandmark.RIGHT_HIP.value].x,landmarks[mp_pose.PoseLandmark.RIGHT_HIP.value].y]
  6. right_heel = [landmarks[mp_pose.PoseLandmark.RIGHT_HEEL.value].x,landmarks[mp_pose.PoseLandmark.RIGHT_HEEL.value].y]
  7. right_index = [landmarks[mp_pose.PoseLandmark.RIGHT_INDEX.value].x,landmarks[mp_pose.PoseLandmark.RIGHT_INDEX.value].y]
  8. left_index = [landmarks[mp_pose.PoseLandmark.LEFT_INDEX.value].x,landmarks[mp_pose.PoseLandmark.LEFT_INDEX.value].y]
  9. # Calculate angle

【4】如何知道主体(老人)是安全的还是跌倒的?

    我们将借助从 cv2 和 mediapipe 获得的坐标以及使用上述定义的函数获得的角度来找到这一点。

    由于我们正在获取眼睛臀部和脚踝的坐标,因此我们知道当一个人平躺(倒下)时,他的眼睛、臀部和脚踝之间的角度在 170 到 180 度的范围内。因此,我们可以简单地提出一个条件,当角度在 170 -180 度之间时,我们可以说一个人摔倒了。


  
  1. if angle1 != angle2 and (angle1> 170 and angle2> 170):
  2. if (((right_index[ 0]< 0.70 and right_index[ 0]> 0.20) and (right_index[ 1]< 0.56 and right_index[ 1]> 0.15)) or ((left_index[ 0]< 0.55 and left_index[ 0]> 0.18) and (left_index[ 1]< 0.56 and left_index[ 1]> 0.15))):
  3. stage= "Hanging on !!"
  4. else:
  5. stage = "fallen :("
  6. elif angle1 != angle2 and (angle1< 140 or angle2< 140) :
  7. stage = "Trying to Walk"
  8. elif angle1!=angle2 and ((angle1< 168 and angle1> 140) and (angle2< 168 and angle2> 140)):
  9. stage= "Barely Walking"
  10. else:
  11. pass

 现在你的脑海中可能会出现一个问题,即如何确定这个人是否真的摔倒了,或者他是否只是躺在床上,因为在这两种情况下,角度都在相同的范围内。

我们也会回答它,所以请继续阅读:)

【5】如何区分床和地板?

    我们将再次使用从 OpenCV 获得的坐标,然后使用它来找到床的坐标,然后在检查跌倒条件时引入一个新条件,即当受试者的坐标与床坐标一致时,这意味着一个人在床上时自然是安全的。这种情况将排除跌倒的情况,程序将显示安全。只有当此条件变为假时,才会检查跌倒条件和其他步行和尝试步行条件。


  
  1. if ((left_eye[ 0]>= 0.41 and left_eye[ 0]<= 0.43) and (left_hip[ 0]>= 0.44 and left_hip[ 0]<= 0.46) and (left_heel[ 0]>= 0.41 and left_heel[ 0]<= 0.43) or (right_eye[ 0]>= 0.41 and right_eye[ 0]<= 0.43) and (right_hip[ 0]<= 0.43 and right_hip[ 0]>= 0.41) and (right_heel[ 0]>= 0.37 and right_heel[ 0]<= 0.39)):
  2. if ((left_eye[ 1]>= 0.24 and left_eye[ 1]<= 0.33) and (left_hip[ 1]<= 0.35 and left_hip[ 1]>= 0.45) and (left_heel[ 1]<= 0.74 and left_heel[ 1]>= 0.72) or (right_eye[ 1]<= 0.30 and right_eye[ 1]>= 0.24) and (right_hip[ 1]<= 0.50 and right_hip[ 1]>= 0.32) and (right_heel[ 1]>= 0.71 and right_heel[ 0]<= 0.73)):
  3. stage = "safe :)"
  4. # Curl counter logic

因此,通过引入带有床坐标的单一条件,我们也解决了上述问题。

【6】让我们在屏幕上打印结果:

    现在打印摔倒和安全等的结果;我们可以很容易地使用 cv2 中的 putText 函数来显示保存在变量 stage 中的文本。

    该函数的示例用法如下所示:

cv2.putText(image, ‘Condition: ‘, (15,12), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,0), 1, cv2.LINE_AA)

【7】添加图形用户界面:

    我们还可以添加一点 GUI 来进一步增加整个程序的外观并使其更加用户友好。实现最简单 GUI 的代码片段示例如下:


  
  1. root = Tk()
  2. root.geometry( "1920x1080+0+0")
  3. root.state( "zoomed")
  4. root.config(bg= "#3a3b3c")
  5. root.title( "Eldering Monitring")
  6. def path_select():
  7. global video_path,cap
  8. video_path = filedialog.askopenfilename()
  9. cap = cv2.VideoCapture(video_path)
  10. text = Label(root,text= "Recorded Video ",bg= "#3a3b3c",fg= "#ffffff",font=( "Calibri", 20))
  11. text.place(x= 250,y= 150)
  12. # For Live feed
  13. def video_live():
  14. global video_path,cap
  15. video_path = 0
  16. cap = cv2.VideoCapture(video_path)
  17. text = Label(root,text= "Live Video Feed",bg= "#3a3b3c",fg= "#ffffff",font=( "Calibri", 20))
  18. text.place(x= 250,y= 150)
  19. live_btn = Button(root, height = 1,text= 'LIVE', width= 8, fg= 'magenta', font=( "Calibri", 14, "bold"), command= lambda:video_live())
  20. live_btn.place(x= 1200,y= 20)
  21. text = Label(root,text= " For Live Video",bg= "#3a3b3c",fg= "#ffffff",font=( "Calibri", 20))
  22. text.place(x= 1000,y= 30)
  23. browse_btn = Button(root, height = 1, width= 8 ,text= 'VIDEO',fg= 'magenta', font=( "Calibri", 14, "bold"), command= lambda:path_select())
  24. browse_btn.place(x= 1200,y= 90)
  25. text = Label(root,text= "To Browse Video",bg= "#3a3b3c",fg= "#ffffff",font=( "Calibri", 20))
  26. text.place(x= 1000,y= 90)
  27. ttl = Label(root,text= "ELDERING MONITERING ",bg= "#4f4d4a",fg= "#fffbbb",font=( "Calibri", 40))
  28. ttl.place(x= 100,y= 50)
  29. Video_frame = Frame(root, height= 720, width= 1080, bg= "#3a3b3c")
  30. Video_Label = Label(root)
  31. Video_frame.place(x= 15,y= 200)
  32. Video_Label.place(x= 15,y= 200)

作者有言

如果需要代码,请私聊博主,博主看见回。
如果感觉博主讲的对您有用,请点个关注支持一下吧,将会对此类问题持续更新……


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