一个不知名大学生,江湖人称菜狗
original author: jacky Li
Email : 3435673055@qq.com
Time of completion:2023.2.4
Last edited: 2023.2.4导读
本文将使用Python、OpenCV和MediaPipe搭建一个老人跌倒智能监测系统。
目录
背景介绍
老人监测系统是一种智能检测系统,可以检测老人是否躺在床上或是否跌倒在地。这是一个解决实际问题的程序,可用于在您外出工作或外出时监控家中的老人,以便在出现任何问题时通知您。
实现步骤
【1】导入必要的模块:
在 python 中导入 Numpy、MediaPipe 和 opencv
-
import cv2
-
import mediapipe
as mp
-
import numpy
as np
【2】定义一个计算角度的函数:
由于我们将根据我们使用 OpenCV 获得的角度和坐标来假设一个人是在行走还是跌倒在地上,因此,我们必须计算角度,最简单的方法是定义一个函数,然后调用它在程序中。
-
def
calculate_angle(
a,b,c):
-
a = np.array(a)
# First
-
b = np.array(b)
# Mid
-
c = np.array(c)
# End
-
-
radians = np.arctan2(c[
1]-b[
1], c[
0]-b[
0]) - np.arctan2(a[
1]-b[
1], a[
0]-b[
0])
-
angle = np.
abs(radians*
180.0/np.pi)
-
-
if angle >
180.0:
-
angle =
360-angle
-
-
return angle
【3】查找坐标:
我们还必须找到坐标,以便我们可以在条件下使用它们,也可以将它们与calculate_angle函数一起使用。
-
left_eye = [landmarks[mp_pose.PoseLandmark.LEFT_EYE.value].x,landmarks[mp_pose.PoseLandmark.LEFT_EYE.value].y]
-
left_hip= [landmarks[mp_pose.PoseLandmark.LEFT_HIP.value].x,landmarks[mp_pose.PoseLandmark.LEFT_HIP.value].y]
-
left_heel = [landmarks[mp_pose.PoseLandmark.LEFT_HEEL.value].x,landmarks[mp_pose.PoseLandmark.LEFT_HEEL.value].y]
-
right_eye = [landmarks[mp_pose.PoseLandmark.RIGHT_EYE.value].x,landmarks[mp_pose.PoseLandmark.RIGHT_EYE.value].y]
-
right_hip = [landmarks[mp_pose.PoseLandmark.RIGHT_HIP.value].x,landmarks[mp_pose.PoseLandmark.RIGHT_HIP.value].y]
-
right_heel = [landmarks[mp_pose.PoseLandmark.RIGHT_HEEL.value].x,landmarks[mp_pose.PoseLandmark.RIGHT_HEEL.value].y]
-
right_index = [landmarks[mp_pose.PoseLandmark.RIGHT_INDEX.value].x,landmarks[mp_pose.PoseLandmark.RIGHT_INDEX.value].y]
-
left_index = [landmarks[mp_pose.PoseLandmark.LEFT_INDEX.value].x,landmarks[mp_pose.PoseLandmark.LEFT_INDEX.value].y]
-
# Calculate angle
【4】如何知道主体(老人)是安全的还是跌倒的?
我们将借助从 cv2 和 mediapipe 获得的坐标以及使用上述定义的函数获得的角度来找到这一点。
由于我们正在获取眼睛臀部和脚踝的坐标,因此我们知道当一个人平躺(倒下)时,他的眼睛、臀部和脚踝之间的角度在 170 到 180 度的范围内。因此,我们可以简单地提出一个条件,当角度在 170 -180 度之间时,我们可以说一个人摔倒了。
-
if angle1 != angle2
and (angle1>
170
and angle2>
170):
-
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))):
-
stage=
"Hanging on !!"
-
else:
-
stage =
"fallen :("
-
-
elif angle1 != angle2
and (angle1<
140
or angle2<
140) :
-
stage =
"Trying to Walk"
-
elif angle1!=angle2
and ((angle1<
168
and angle1>
140)
and (angle2<
168
and angle2>
140)):
-
stage=
"Barely Walking"
-
else:
-
pass
现在你的脑海中可能会出现一个问题,即如何确定这个人是否真的摔倒了,或者他是否只是躺在床上,因为在这两种情况下,角度都在相同的范围内。
我们也会回答它,所以请继续阅读:)
【5】如何区分床和地板?
我们将再次使用从 OpenCV 获得的坐标,然后使用它来找到床的坐标,然后在检查跌倒条件时引入一个新条件,即当受试者的坐标与床坐标一致时,这意味着一个人在床上时自然是安全的。这种情况将排除跌倒的情况,程序将显示安全。只有当此条件变为假时,才会检查跌倒条件和其他步行和尝试步行条件。
-
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)):
-
-
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)):
-
stage =
"safe :)"
-
# 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 的代码片段示例如下:
-
root = Tk()
-
root.geometry(
"1920x1080+0+0")
-
root.state(
"zoomed")
-
root.config(bg=
"#3a3b3c")
-
root.title(
"Eldering Monitring")
-
-
def
path_select():
-
global video_path,cap
-
video_path = filedialog.askopenfilename()
-
cap = cv2.VideoCapture(video_path)
-
text = Label(root,text=
"Recorded Video ",bg=
"#3a3b3c",fg=
"#ffffff",font=(
"Calibri",
20))
-
text.place(x=
250,y=
150)
-
# For Live feed
-
def
video_live():
-
global video_path,cap
-
video_path =
0
-
cap = cv2.VideoCapture(video_path)
-
text = Label(root,text=
"Live Video Feed",bg=
"#3a3b3c",fg=
"#ffffff",font=(
"Calibri",
20))
-
text.place(x=
250,y=
150)
-
-
-
live_btn = Button(root, height =
1,text=
'LIVE', width=
8, fg=
'magenta', font=(
"Calibri",
14,
"bold"), command=
lambda:video_live())
-
live_btn.place(x=
1200,y=
20)
-
text = Label(root,text=
" For Live Video",bg=
"#3a3b3c",fg=
"#ffffff",font=(
"Calibri",
20))
-
text.place(x=
1000,y=
30)
-
-
browse_btn = Button(root, height =
1, width=
8 ,text=
'VIDEO',fg=
'magenta', font=(
"Calibri",
14,
"bold"), command=
lambda:path_select())
-
browse_btn.place(x=
1200,y=
90)
-
text = Label(root,text=
"To Browse Video",bg=
"#3a3b3c",fg=
"#ffffff",font=(
"Calibri",
20))
-
text.place(x=
1000,y=
90)
-
-
-
ttl = Label(root,text=
"ELDERING MONITERING ",bg=
"#4f4d4a",fg=
"#fffbbb",font=(
"Calibri",
40))
-
ttl.place(x=
100,y=
50)
-
-
Video_frame = Frame(root, height=
720, width=
1080, bg=
"#3a3b3c")
-
Video_Label = Label(root)
-
Video_frame.place(x=
15,y=
200)
-
Video_Label.place(x=
15,y=
200)
作者有言
如果需要代码,请私聊博主,博主看见回。
如果感觉博主讲的对您有用,请点个关注支持一下吧,将会对此类问题持续更新……
转载:https://blog.csdn.net/weixin_62075168/article/details/128885743