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数组遍历的简单实现方法小结
Apr 27 Python
使用python3.5仿微软记事本notepad
Jun 15 Python
PyQt5每天必学之事件与信号
Apr 20 Python
Python2.7 实现引入自己写的类方法
Apr 29 Python
python实现简易内存监控
Jun 21 Python
python中dir()与__dict__属性的区别浅析
Dec 10 Python
对json字符串与python字符串的不同之处详解
Dec 19 Python
python查询文件夹下excel的sheet名代码实例
Apr 02 Python
Python高级特性——详解多维数组切片(Slice)
Nov 26 Python
Flask和pyecharts实现动态数据可视化
Feb 26 Python
python实现引用其他路径包里面的模块
Mar 09 Python
如何在Windows中安装多个python解释器
Jun 16 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
为查询结果建立向后/向前按钮
2006/10/09 PHP
PHP+XML 制作简单的留言本 图文教程
2009/11/02 PHP
php 验证码实例代码
2010/06/01 PHP
注意!PHP 7中不要做的10件事
2016/09/18 PHP
PHP pthreads v3下worker和pool的使用方法示例
2020/02/21 PHP
javascript 鼠标滚轮事件
2009/04/09 Javascript
Whatever:hover 无需javascript让IE支持丰富伪类
2010/06/29 Javascript
jquery获取div距离窗口和父级dv的距离示例
2013/10/10 Javascript
jquery 设置style:display的方法
2015/01/29 Javascript
jQuery实现伸展与合拢panel的方法
2015/04/30 Javascript
jQuery编写设置和获取颜色的插件
2017/01/09 Javascript
JavaScript html5利用FileReader实现上传功能
2020/03/27 Javascript
微信小程序多张图片上传功能
2017/06/07 Javascript
JavaScript中附件预览功能实现详解(推荐)
2017/08/15 Javascript
基于jQuery实现无缝轮播与左右点击效果
2018/05/13 jQuery
vue.js编译时给生成的文件增加版本号
2018/09/17 Javascript
[00:35]DOTA2上海特级锦标赛 EG战队宣传片
2016/03/04 DOTA
Python线程中对join方法的运用的教程
2015/04/09 Python
django实现分页的方法
2015/05/26 Python
python 随机数使用方法,推导以及字符串,双色球小程序实例
2017/09/12 Python
Android分包MultiDex策略详解
2017/10/30 Python
Python 获得命令行参数的方法(推荐)
2018/01/24 Python
python根据url地址下载小文件的实例
2018/12/18 Python
专门出售各种儿童读物的网站:Put Me In The Story
2016/08/07 全球购物
美国婚戒购物网站:Anjays Designs
2017/06/28 全球购物
美国嘻哈文化生活方式品牌:GLD
2018/04/15 全球购物
写一个方法,输入一个文件名和一个字符串,统计这个字符串在这个文件中出现的次数
2016/04/13 面试题
应届毕业生应聘自荐信
2013/12/07 职场文书
优秀党员自我评价范文
2014/09/15 职场文书
终止或解除劳动合同及劳动关系的证明书
2014/10/06 职场文书
对照四风自我剖析材料
2014/10/07 职场文书
研究生个人学年总结
2015/02/14 职场文书
2015年社区文体活动总结
2015/03/25 职场文书
幼儿园老师工作总结2015
2015/05/22 职场文书
企业培训简报范文
2015/07/20 职场文书
HR必备:超全面的薪酬待遇管理方案!
2019/07/12 职场文书