Python+OpenCV实现实时眼动追踪的示例代码


Posted in Python onNovember 11, 2019

使用Python+OpenCV实现实时眼动追踪,不需要高端硬件简单摄像头即可实现,效果图如下所示。

Python+OpenCV实现实时眼动追踪的示例代码 

项目演示参见:https://www.bilibili.com/video/av75181965/

项目主程序如下:

import sys
import cv2
import numpy as np
import process
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.uic import loadUi
from PyQt5.QtGui import QPixmap, QImage
 
 
class Window(QMainWindow):
  def __init__(self):
    super(Window, self).__init__()
    loadUi('GUImain.ui', self)
    with open("style.css", "r") as css:
      self.setStyleSheet(css.read())
    self.face_decector, self.eye_detector, self.detector = process.init_cv()
    self.startButton.clicked.connect(self.start_webcam)
    self.stopButton.clicked.connect(self.stop_webcam)
    self.camera_is_running = False
    self.previous_right_keypoints = None
    self.previous_left_keypoints = None
    self.previous_right_blob_area = None
    self.previous_left_blob_area = None
 
  def start_webcam(self):
    if not self.camera_is_running:
      self.capture = cv2.VideoCapture(cv2.CAP_DSHOW) # VideoCapture(0) sometimes drops error #-1072875772
      if self.capture is None:
        self.capture = cv2.VideoCapture(0)
      self.camera_is_running = True
      self.timer = QTimer(self)
      self.timer.timeout.connect(self.update_frame)
      self.timer.start(2)
 
  def stop_webcam(self):
    if self.camera_is_running:
      self.capture.release()
      self.timer.stop()
      self.camera_is_running = not self.camera_is_running
 
  def update_frame(self): # logic of the main loop
 
    _, base_image = self.capture.read()
    self.display_image(base_image)
 
    processed_image = cv2.cvtColor(base_image, cv2.COLOR_RGB2GRAY)
 
    face_frame, face_frame_gray, left_eye_estimated_position, right_eye_estimated_position, _, _ = process.detect_face(
      base_image, processed_image, self.face_decector)
 
    if face_frame is not None:
      left_eye_frame, right_eye_frame, left_eye_frame_gray, right_eye_frame_gray = process.detect_eyes(face_frame,
                                                       face_frame_gray,
                                                       left_eye_estimated_position,
                                                       right_eye_estimated_position,
                                                       self.eye_detector)
 
      if right_eye_frame is not None:
        if self.rightEyeCheckbox.isChecked():
          right_eye_threshold = self.rightEyeThreshold.value()
          right_keypoints, self.previous_right_keypoints, self.previous_right_blob_area = self.get_keypoints(
            right_eye_frame, right_eye_frame_gray, right_eye_threshold,
            previous_area=self.previous_right_blob_area,
            previous_keypoint=self.previous_right_keypoints)
          process.draw_blobs(right_eye_frame, right_keypoints)
 
        right_eye_frame = np.require(right_eye_frame, np.uint8, 'C')
        self.display_image(right_eye_frame, window='right')
 
      if left_eye_frame is not None:
        if self.leftEyeCheckbox.isChecked():
          left_eye_threshold = self.leftEyeThreshold.value()
          left_keypoints, self.previous_left_keypoints, self.previous_left_blob_area = self.get_keypoints(
            left_eye_frame, left_eye_frame_gray, left_eye_threshold,
            previous_area=self.previous_left_blob_area,
            previous_keypoint=self.previous_left_keypoints)
          process.draw_blobs(left_eye_frame, left_keypoints)
 
        left_eye_frame = np.require(left_eye_frame, np.uint8, 'C')
        self.display_image(left_eye_frame, window='left')
 
    if self.pupilsCheckbox.isChecked(): # draws keypoints on pupils on main window
      self.display_image(base_image)
 
  def get_keypoints(self, frame, frame_gray, threshold, previous_keypoint, previous_area):
 
    keypoints = process.process_eye(frame_gray, threshold, self.detector,
                    prevArea=previous_area)
    if keypoints:
      previous_keypoint = keypoints
      previous_area = keypoints[0].size
    else:
      keypoints = previous_keypoint
    return keypoints, previous_keypoint, previous_area
 
  def display_image(self, img, window='main'):
    # Makes OpenCV images displayable on PyQT, displays them
    qformat = QImage.Format_Indexed8
    if len(img.shape) == 3:
      if img.shape[2] == 4: # RGBA
        qformat = QImage.Format_RGBA8888
      else: # RGB
        qformat = QImage.Format_RGB888
 
    out_image = QImage(img, img.shape[1], img.shape[0], img.strides[0], qformat) # BGR to RGB
    out_image = out_image.rgbSwapped()
    if window == 'main': # main window
      self.baseImage.setPixmap(QPixmap.fromImage(out_image))
      self.baseImage.setScaledContents(True)
    if window == 'left': # left eye window
      self.leftEyeBox.setPixmap(QPixmap.fromImage(out_image))
      self.leftEyeBox.setScaledContents(True)
    if window == 'right': # right eye window
      self.rightEyeBox.setPixmap(QPixmap.fromImage(out_image))
      self.rightEyeBox.setScaledContents(True)
 
 
if __name__ == "__main__":
  app = QApplication(sys.argv)
  window = Window()
  window.setWindowTitle("GUI")
  window.show()
  sys.exit(app.exec_())

人眼检测程序如下:

import os
import cv2
import numpy as np
 
 
def init_cv():
  """loads all of cv2 tools"""
  face_detector = cv2.CascadeClassifier(
    os.path.join("Classifiers", "haar", "haarcascade_frontalface_default.xml"))
  eye_detector = cv2.CascadeClassifier(os.path.join("Classifiers", "haar", 'haarcascade_eye.xml'))
  detector_params = cv2.SimpleBlobDetector_Params()
  detector_params.filterByArea = True
  detector_params.maxArea = 1500
  detector = cv2.SimpleBlobDetector_create(detector_params)
 
  return face_detector, eye_detector, detector
 
 
def detect_face(img, img_gray, cascade):
  """
  Detects all faces, if multiple found, works with the biggest. Returns the following parameters:
  1. The face frame
  2. A gray version of the face frame
  2. Estimated left eye coordinates range
  3. Estimated right eye coordinates range
  5. X of the face frame
  6. Y of the face frame
  """
  coords = cascade.detectMultiScale(img, 1.3, 5)
 
  if len(coords) > 1:
    biggest = (0, 0, 0, 0)
    for i in coords:
      if i[3] > biggest[3]:
        biggest = i
    biggest = np.array([i], np.int32)
  elif len(coords) == 1:
    biggest = coords
  else:
    return None, None, None, None, None, None
  for (x, y, w, h) in biggest:
    frame = img[y:y + h, x:x + w]
    frame_gray = img_gray[y:y + h, x:x + w]
    lest = (int(w * 0.1), int(w * 0.45))
    rest = (int(w * 0.55), int(w * 0.9))
    X = x
    Y = y
 
  return frame, frame_gray, lest, rest, X, Y
 
 
def detect_eyes(img, img_gray, lest, rest, cascade):
  """
  :param img: image frame
  :param img_gray: gray image frame
  :param lest: left eye estimated position, needed to filter out nostril, know what eye is found
  :param rest: right eye estimated position
  :param cascade: Hhaar cascade
  :return: colored and grayscale versions of eye frames
  """
  leftEye = None
  rightEye = None
  leftEyeG = None
  rightEyeG = None
  coords = cascade.detectMultiScale(img_gray, 1.3, 5)
 
  if coords is None or len(coords) == 0:
    pass
  else:
    for (x, y, w, h) in coords:
      eyecenter = int(float(x) + (float(w) / float(2)))
      if lest[0] < eyecenter and eyecenter < lest[1]:
        leftEye = img[y:y + h, x:x + w]
        leftEyeG = img_gray[y:y + h, x:x + w]
        leftEye, leftEyeG = cut_eyebrows(leftEye, leftEyeG)
      elif rest[0] < eyecenter and eyecenter < rest[1]:
        rightEye = img[y:y + h, x:x + w]
        rightEyeG = img_gray[y:y + h, x:x + w]
        rightEye, rightEye = cut_eyebrows(rightEye, rightEyeG)
      else:
        pass # nostril
  return leftEye, rightEye, leftEyeG, rightEyeG
 
 
def process_eye(img, threshold, detector, prevArea=None):
  """
  :param img: eye frame
  :param threshold: threshold value for threshold function
  :param detector: blob detector
  :param prevArea: area of the previous keypoint(used for filtering)
  :return: keypoints
  """
  _, img = cv2.threshold(img, threshold, 255, cv2.THRESH_BINARY)
  img = cv2.erode(img, None, iterations=2)
  img = cv2.dilate(img, None, iterations=4)
  img = cv2.medianBlur(img, 5)
  keypoints = detector.detect(img)
  if keypoints and prevArea and len(keypoints) > 1:
    tmp = 1000
    for keypoint in keypoints: # filter out odd blobs
      if abs(keypoint.size - prevArea) < tmp:
        ans = keypoint
        tmp = abs(keypoint.size - prevArea)
    keypoints = np.array(ans)
 
  return keypoints
 
def cut_eyebrows(img, imgG):
  height, width = img.shape[:2]
  img = img[15:height, 0:width] # cut eyebrows out (15 px)
  imgG = imgG[15:height, 0:width]
 
  return img, imgG
 
 
def draw_blobs(img, keypoints):
  """Draws blobs"""
  cv2.drawKeypoints(img, keypoints, img, (0, 0, 255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
介绍Python中的fabs()方法的使用
May 14 Python
Python中 Lambda表达式全面解析
Nov 28 Python
python matplotlib 注释文本箭头简单代码示例
Jan 08 Python
解决python报错MemoryError的问题
Jun 26 Python
Python实现的线性回归算法示例【附csv文件下载】
Dec 29 Python
Python字典的基本用法实例分析【创建、增加、获取、修改、删除】
Mar 05 Python
python 字符串追加实例
Jul 20 Python
python3实现单目标粒子群算法
Nov 14 Python
python redis 批量设置过期key过程解析
Nov 26 Python
最小二乘法及其python实现详解
Feb 24 Python
Django 解决阿里云部署同步数据库报错的问题
May 14 Python
一文带你掌握Pyecharts地理数据可视化的方法
Feb 06 Python
python的pyecharts绘制各种图表详细(附代码)
Nov 11 #Python
python OpenCV GrabCut使用实例解析
Nov 11 #Python
Python上下文管理器用法及实例解析
Nov 11 #Python
Django 请求Request的具体使用方法
Nov 11 #Python
浅谈Python类中的self到底是干啥的
Nov 11 #Python
python 调试冷知识(小结)
Nov 11 #Python
通过 Django Pagination 实现简单分页功能
Nov 11 #Python
You might like
支持oicq头像的留言簿(二)
2006/10/09 PHP
PHP中对用户身份认证实现两种方法
2011/06/04 PHP
一些需要禁用的PHP危险函数(disable_functions)
2012/02/23 PHP
PHP统计nginx访问日志中的搜索引擎抓取404链接页面路径
2014/06/30 PHP
php利用cookie实现自动登录的方法
2014/12/10 PHP
php使用Jpgraph创建柱状图展示年度收支表效果示例
2017/02/15 PHP
Laravel 5.5 的自定义验证对象/类示例代码详解
2017/08/29 PHP
Laravel框架运行出错提示RuntimeException No application encryption key has been specified.解决方法
2019/04/02 PHP
PHP常用字符串函数用法实例总结
2020/06/04 PHP
JS input文本框禁用右键和复制粘贴功能的代码
2010/04/15 Javascript
js 分页全选或反选标识实现代码
2011/08/09 Javascript
js数组中如何随机取出一个值
2014/06/13 Javascript
深入探讨前端框架react
2015/12/09 Javascript
JavaScript Array对象详解
2016/03/01 Javascript
jQuery Mobile漏洞会有跨站脚本攻击风险
2017/02/12 Javascript
基于require.js的使用(实例讲解)
2017/09/07 Javascript
浅谈Node异步编程的机制
2017/10/18 Javascript
小程序视频列表中视频的播放与停止的示例代码
2018/07/20 Javascript
NodeJs项目中关闭ESLint的方法
2018/08/09 NodeJs
详解create-react-app 2.0版本如何启用装饰器语法
2018/10/23 Javascript
解决vue下载后台传过来的乱码流的问题
2020/12/05 Vue.js
python实现中文输出的两种方法
2015/05/09 Python
浅谈python新手中常见的疑惑及解答
2016/06/14 Python
Python逐行读取文件中内容的简单方法
2019/02/26 Python
Django用户认证系统 User对象解析
2019/08/02 Python
基于Python和PyYAML读取yaml配置文件数据
2020/01/13 Python
使用python创建Excel工作簿及工作表过程图解
2020/05/27 Python
SpringBoot首页设置解析(推荐)
2021/02/11 Python
师德学习感言
2014/01/31 职场文书
三年级数学教学反思
2014/01/31 职场文书
感恩老师的演讲稿
2014/05/06 职场文书
社区活动总结
2015/02/04 职场文书
博士生专家推荐信
2015/03/25 职场文书
酒店人事专员岗位职责
2015/04/07 职场文书
利用正则表达式匹配浮点型数据
2022/05/30 Java/Android
Python Matplotlib绘制动画的代码详解
2022/05/30 Python