当前位置:   article > 正文

基于python语言dlib库和opencv库的视频眨眼检测_python眨眼识别

python眨眼识别

功能说明:

基于python编程语言,使用dlib 和opencv开发的视频眨眼检测。

环境:

*   python 3.6.8
*   opencv 3.4.2.16
*   dlib 19.7.0

原理:

1.使用opencv-python读取处理视频图像

2.使用线程机制处理人脸检测关键点

3.根据dlib算法检测到的关键点计算眼部特征,通过欧氏距离计算确定是睁眼还是闭眼

4.统计闭眼次数并在视频图片中绘制结果

原始代码:

  1. # 基于opencv-python和dlib库的视频眨眼检测
  2. # 导入工具包
  3. from scipy.spatial import distance as dist
  4. from collections import OrderedDict
  5. import numpy as np
  6. import argparse
  7. import time
  8. # pip install dlib==19.6.1 -i https://mirrors.aliyun.com/pypi/simple
  9. import dlib
  10. # pip install opencv-python==3.4.1
  11. import cv2
  12. # 关键点排序
  13. FACIAL_LANDMARKS_68_IDXS = OrderedDict([
  14. ("mouth", (48, 68)),
  15. ("right_eyebrow", (17, 22)),
  16. ("left_eyebrow", (22, 27)),
  17. ("right_eye", (36, 42)),
  18. ("left_eye", (42, 48)),
  19. ("nose", (27, 36)),
  20. ("jaw", (0, 17))
  21. ])
  22. # http://vision.fe.uni-lj.si/cvww2016/proceedings/papers/05.pdf
  23. def eye_aspect_ratio(eye):
  24. """
  25. 计算眼睛上下关键点欧式距离
  26. :param eye:眼睛关键点位置
  27. :return: 眼睛睁开程度
  28. """
  29. # 计算距离,竖直的
  30. A = dist.euclidean(eye[1], eye[5])
  31. B = dist.euclidean(eye[2], eye[4])
  32. # 计算距离,水平的
  33. C = dist.euclidean(eye[0], eye[3])
  34. # ear值
  35. ear = (A + B) / (2.0 * C)
  36. return ear
  37. # 输入参数
  38. ap = argparse.ArgumentParser()
  39. ap.add_argument("-p", "--shape-predictor", required=True,
  40. help="path to facial landmark predictor")
  41. ap.add_argument("-v", "--video", type=str, default="",
  42. help="path to input video file")
  43. args = vars(ap.parse_args())
  44. print(args)
  45. # 设置判断参数
  46. EYE_AR_THRESH = 0.3 # 低于该值则判断为眨眼
  47. EYE_AR_CONSEC_FRAMES = 3
  48. # 初始化计数器
  49. COUNTER = 0
  50. TOTAL = 0
  51. # 检测与定位工具
  52. print("[INFO] loading facial landmark predictor...")
  53. detector = dlib.get_frontal_face_detector()
  54. #predictor = dlib.shape_predictor(args["shape_predictor"])
  55. predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
  56. # 分别取两个眼睛区域
  57. (lStart, lEnd) = FACIAL_LANDMARKS_68_IDXS["left_eye"]
  58. (rStart, rEnd) = FACIAL_LANDMARKS_68_IDXS["right_eye"]
  59. # 读取视频
  60. print("[INFO] starting video stream thread...")
  61. #vs = cv2.VideoCapture(args["video"])
  62. vs = cv2.VideoCapture(0)
  63. #vs = FileVideoStream(args["video"]).start()
  64. time.sleep(1.0)
  65. def shape_to_np(shape, dtype="int"):
  66. # 创建68*2
  67. coords = np.zeros((shape.num_parts, 2), dtype=dtype)
  68. # 遍历每一个关键点
  69. # 得到坐标
  70. for i in range(0, shape.num_parts):
  71. coords[i] = (shape.part(i).x, shape.part(i).y)
  72. return coords
  73. # 遍历每一帧
  74. while True:
  75. # 预处理
  76. frame = vs.read()[1]
  77. if frame is None:
  78. break
  79. (h, w) = frame.shape[:2]
  80. width = 1200
  81. r = width / float(w)
  82. dim = (width, int(h * r))
  83. frame = cv2.resize(frame, dim, interpolation=cv2.INTER_AREA)
  84. gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  85. # 检测人脸
  86. rects = detector(gray, 0)
  87. # 遍历每一个检测到的人脸
  88. for rect in rects:
  89. # 获取坐标
  90. shape = predictor(gray, rect)
  91. shape = shape_to_np(shape)
  92. # 分别计算ear值
  93. leftEye = shape[lStart:lEnd]
  94. rightEye = shape[rStart:rEnd]
  95. leftEAR = eye_aspect_ratio(leftEye)
  96. rightEAR = eye_aspect_ratio(rightEye)
  97. # 算一个平均的
  98. ear = (leftEAR + rightEAR) / 2.0
  99. # 绘制眼睛区域
  100. leftEyeHull = cv2.convexHull(leftEye)
  101. rightEyeHull = cv2.convexHull(rightEye)
  102. cv2.drawContours(frame, [leftEyeHull], -1, (0, 255, 0), 1)
  103. cv2.drawContours(frame, [rightEyeHull], -1, (0, 255, 0), 1)
  104. # 检查是否满足阈值
  105. if ear < EYE_AR_THRESH:
  106. COUNTER += 1
  107. else:
  108. # 如果连续几帧都是闭眼的,总数算一次
  109. if COUNTER >= EYE_AR_CONSEC_FRAMES:
  110. TOTAL += 1
  111. # 重置
  112. COUNTER = 0
  113. # 显示
  114. cv2.putText(frame, "Blinks: {}".format(TOTAL), (10, 30),
  115. cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
  116. cv2.putText(frame, "EAR: {:.2f}".format(ear), (300, 30),
  117. cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
  118. cv2.imshow("Frame", frame)
  119. key = cv2.waitKey(10) & 0xFF
  120. if key == 27:
  121. break
  122. vs.release()
  123. cv2.destroyAllWindows()

运行该代码进行调用摄像头检测和读取本地视频检测的命令如下:

  1. python detect_blinks.py -p shape_predictor_68_face_landmarks.dat -v test.mp4
  2. python detect_blinks.py -p shape_predictor_68_face_landmarks.dat -v 0

原始代码需要借助于命令行参数才可以运行,后来经过修改后,可以直接在编译器中运行的,代码如下:

  1. # 视频眨眼检测
  2. # 导入工具包
  3. from scipy.spatial import distance as dist
  4. from collections import OrderedDict
  5. import numpy as np
  6. import argparse
  7. import time
  8. # pip install dlib==19.6.1 -i https://mirrors.aliyun.com/pypi/simple
  9. import dlib
  10. # pip install opencv-python==3.4.1
  11. import cv2
  12. # 关键点排序
  13. FACIAL_LANDMARKS_68_IDXS = OrderedDict([
  14. ("mouth", (48, 68)),
  15. ("right_eyebrow", (17, 22)),
  16. ("left_eyebrow", (22, 27)),
  17. ("right_eye", (36, 42)),
  18. ("left_eye", (42, 48)),
  19. ("nose", (27, 36)),
  20. ("jaw", (0, 17))
  21. ])
  22. # http://vision.fe.uni-lj.si/cvww2016/proceedings/papers/05.pdf
  23. def eye_aspect_ratio(eye):
  24. """
  25. 计算眼睛上下关键点欧式距离
  26. :param eye:眼睛关键点位置
  27. :return: 眼睛睁开程度
  28. """
  29. # 计算距离,竖直的
  30. A = dist.euclidean(eye[1], eye[5])
  31. B = dist.euclidean(eye[2], eye[4])
  32. # 计算距离,水平的
  33. C = dist.euclidean(eye[0], eye[3])
  34. # ear值
  35. ear = (A + B) / (2.0 * C)
  36. return ear
  37. # 设置判断参数
  38. EYE_AR_THRESH = 0.3 # 低于该值则判断为眨眼
  39. EYE_AR_CONSEC_FRAMES = 3
  40. # 初始化计数器
  41. COUNTER = 0
  42. TOTAL = 0
  43. # 检测与定位工具
  44. print("[INFO] loading facial landmark predictor...")
  45. detector = dlib.get_frontal_face_detector()
  46. predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
  47. # 分别取两个眼睛区域
  48. (lStart, lEnd) = FACIAL_LANDMARKS_68_IDXS["left_eye"]
  49. (rStart, rEnd) = FACIAL_LANDMARKS_68_IDXS["right_eye"]
  50. # 读取视频
  51. print("[INFO] starting video stream thread...")
  52. vs = cv2.VideoCapture(0)
  53. time.sleep(1.0)
  54. def shape_to_np(shape, dtype="int"):
  55. # 创建68*2
  56. coords = np.zeros((shape.num_parts, 2), dtype=dtype)
  57. # 遍历每一个关键点
  58. # 得到坐标
  59. for i in range(0, shape.num_parts):
  60. coords[i] = (shape.part(i).x, shape.part(i).y)
  61. return coords
  62. # 遍历每一帧
  63. while True:
  64. # 预处理
  65. frame = vs.read()[1]
  66. if frame is None:
  67. break
  68. (h, w) = frame.shape[:2]
  69. width = 1200
  70. r = width / float(w)
  71. dim = (width, int(h * r))
  72. frame = cv2.resize(frame, dim, interpolation=cv2.INTER_AREA)
  73. gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  74. # 检测人脸
  75. rects = detector(gray, 0)
  76. # 遍历每一个检测到的人脸
  77. for rect in rects:
  78. # 获取坐标
  79. shape = predictor(gray, rect)
  80. shape = shape_to_np(shape)
  81. # 分别计算ear值
  82. leftEye = shape[lStart:lEnd]
  83. rightEye = shape[rStart:rEnd]
  84. leftEAR = eye_aspect_ratio(leftEye)
  85. rightEAR = eye_aspect_ratio(rightEye)
  86. # 算一个平均的
  87. ear = (leftEAR + rightEAR) / 2.0
  88. # 绘制眼睛区域
  89. leftEyeHull = cv2.convexHull(leftEye)
  90. rightEyeHull = cv2.convexHull(rightEye)
  91. cv2.drawContours(frame, [leftEyeHull], -1, (0, 255, 0), 1)
  92. cv2.drawContours(frame, [rightEyeHull], -1, (0, 255, 0), 1)
  93. # 检查是否满足阈值
  94. if ear < EYE_AR_THRESH:
  95. COUNTER += 1
  96. else:
  97. # 如果连续几帧都是闭眼的,总数算一次
  98. if COUNTER >= EYE_AR_CONSEC_FRAMES:
  99. TOTAL += 1
  100. # 重置
  101. COUNTER = 0
  102. # 显示
  103. cv2.putText(frame, "Blinks: {}".format(TOTAL), (10, 30),
  104. cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
  105. cv2.putText(frame, "EAR: {:.2f}".format(ear), (300, 30),
  106. cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
  107. cv2.imshow("Frame", frame)
  108. key = cv2.waitKey(10) & 0xFF
  109. if key == 27:
  110. break
  111. vs.release()
  112. cv2.destroyAllWindows()

检测效果如下:

下载链接:https://mp.csdn.net/mp_download/manage/download/UpDetailed

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号