之前写过两篇呢 今天来个完整的

目前有几个方案

1.电极式眼动追踪:这种技术通过在眼球周围放置电极来测量眼睛的运动。它可以提供非常高的准确性和分辨率,但需要接触眼球,因此不太适合长时间使用或需要无接触测量的应用场景。

2.红外线眼动追踪:这种技术使用红外线摄像机来观察眼睛的位置和运动。由于它不需要接触眼球,因此非常适合长时间使用和需要无接触测量的应用场景。它的准确性和分辨率通常比电极式眼动追踪低。

3.磁共振眼动追踪:这种技术使用磁共振成像来测量眼球的位置和运动。它可以提供非常高的空间分辨率,但时间分辨率较低,因此不太适合研究快速眼动的过程。

4.可穿戴式眼动追踪:这种技术使用小型传感器或摄像头,可以放置在眼镜或头盔上,可以随身携带,适用于移动应用场景。但是由于可穿戴设备的尺寸和重量限制,其准确性和分辨率通常较低。

5.视网膜追踪:这种技术利用视网膜图像来跟踪眼球的位置和运动。它可以提供非常高的准确性和分辨率,但只能在特定的实验条件下使用,例如黑暗环境下观察单一的点光源。

以我目前念的这个书,我还是用视觉方案来实现:

1.特征提取:选择适当的特征来描述眼睛的形状、颜色、纹理等信息。

例如,可以使用Haar级联检测器来提取眼睛的轮廓特征,或者使用颜色分布模型来提取眼球的颜色特征。这步主要是传统的

2.目标检测:使用机器学习或计算机视觉技术来检测眼睛的位置和方向。

因为直接目标检测是识别不准的,现实太复杂了。可以使用级联分类器或支持向量机(SVM)来识别眼睛的位置和方向,或者使用卷积神经网络(CNN)来分类眼动类型。

3.跟踪和估计:根据检测结果,使用跟踪和估计算法来跟踪眼睛的位置和运动轨迹。在捕捉的基础上开始进行跟踪,持续的来捕获。使用卡尔曼滤波器或粒子滤波器来估计眼睛的位置和速度,或者使用光流算法来估计眼球的运动轨迹。

4.数据分析:根据眼动追踪的结果,进行数据分析和可视化。可以计算注视点的位置、持续时间和注视次数等统计信息,或者使用热力图和轨迹图来可视化眼动数据。这个也是这次要写的一个点。

我们在这里主要是直接给出ROI的区域减少算力。

眼动追踪py_视频流

眼动追踪py_ide_02

眼动追踪py_视频流_03

太简单了家人们!

但是这个程序太简单了,就是一个找特征啥的,有点傻。这次换个库:

Dlib是一个C++编写的机器学习库,提供了用于人脸检测、关键点检测、姿态估计等任务的算法,其中也包括用于眼动追踪的算法。Dlib同样也提供了Python接口,可以在Python中使用Dlib的算法实现眼动追踪。

dlib提供一个方法可将人脸图片数据映射到128维度的空间向量,如果两张图片来源于同一个人,那么两个图片所映射的空间向量距离就很近,否则就会很远。因此,可以通过提取图片并映射到128维空间向量再度量它们的欧氏距离(Euclidean distance)是否足够小来判定是否为同一个人。我不要人我就要眼睛。

 

眼动追踪py_视频流_04

python.exe -m pip install --upgrade pip
  • 1.

更新一下

眼动追踪py_人工智能_05

眼动追踪py_ide_06

 

眼动追踪py_视频流_07

 

眼动追踪py_ide_08

眼动追踪py_数据_09

2.0~8.0mm之间

瞳孔大小是指虹膜中央的一圆孔的直径,受光线、年龄、人种、屈光状态、目标远近和情绪等因素影响,正常范围在2.0~8.0mm之间。瞳孔在强光下缩小,在黑暗下扩大,这是人体的正常生理反应。瞳孔大小不一致或对光反应异常可能是脑部或眼部疾病的征兆。

眼动追踪py_ide_10

 

眼动追踪py_人工智能_11

多数情况下,我们是要实时的检测的: 

眼动追踪py_视频流_12

眼动追踪py_ide_13

 

眼动追踪py_ide_14

 

眼动追踪py_数据_15

这个写的比较呆逼,不过我在后面会有进行封装

现在是弹出两个框来输出图像,赶紧不好看捏!我们来让他并排排列!

使用OpenCV中的cv2.hconcat()函数将两个视频帧水平合并在一起,并使用cv2.imshow()函数将合并后的视频帧显示出来。

眼动追踪py_人工智能_16

就很简单,其实这里就变成一个合并横向排列的视频组,但是在处理流程上面有问题,应该先单一处理,最后合并结果。 

眼动追踪py_ide_17

眼动追踪py_ide_18

工程问题的话,上面的代码还是太慢了,让我来加一点多线程的魔法!

设计两个线程分别处理左右眼视频帧的读取和合并:

眼动追踪py_人工智能_19

眼动追踪py_ide_20

 

眼动追踪py_ide_21

眼动追踪py_数据_22

 这个就是线程的启动了,然后一个循环不停的合并

眼动追踪py_视频流_23

也可以加一个日志的功能,直接写到最上面就行

现在的程序一点也不装逼,如果可以加一些文字什么的,就更好啦!

眼动追踪py_人工智能_24

要把视频流封装成一个类,然后里面也是多线程处理

眼动追踪py_人工智能_25

 

眼动追踪py_视频流_26

代码中,putText函数用于将帧率信息添加到视频帧的左上角。其中,cv2.FONT_HERSHEY_SIMPLEX指定了字体类型,1指定了字体大小,(255, 255, 255)指定了字体颜色,2指定了字体线宽。

一方面显示是可视化,另一方面我们需要保存具体的眼动数据来后处理。可以在程序中添加一个函数来提取圆形框的坐标信息,并将它们保存到一个文件中。

眼动追踪py_数据_27

eye_data 是一个包含眼动信息的列表,每个元素都是一个二元组,表示眼睛的坐标。在循环中,将每个元素写入文件中,每个坐标之间用逗号分隔,每行结束后添加一个换行符。

假设圆形框的半径为 r,圆心坐标为 (x, y),那么可以使用 OpenCV 中的 circle 函数来绘制圆形框。在绘制圆形框时,同时将圆心坐标和半径信息保存到一个列表中:

眼动追踪py_人工智能_28

在每次绘制圆形框时,将圆心坐标和半径信息添加到 eye_data 列表中。最后,可以将 eye_data 中的信息保存到一个文本文件中:  

眼动追踪py_数据_29

现在就是一个较为完善的函数了

再让我封装一下:

眼动追踪py_视频流_30

 在视频帧上绘制眼球圆形框,并返回圆形框的坐标信息

眼动追踪py_数据_31

眼动追踪py_人工智能_32

眼动追踪py_人工智能_33

 

眼动追踪py_数据_34

眼动追踪py_人工智能_35

 完整代码我放在Github上面了。

我们拿到了保存的数据,想重新把他们展示出来。假设眼动数据文件是一个文本文件,每行包含两个数字,分别代表左右眼的坐标。

眼动追踪py_数据_36

眼动追踪py_人工智能_37

眼动追踪py_视频流_38

再实现一个功能吧!

在播放的时候点按鼠标就可以捕捉当前播放的数据而且在图片上面标注时间戳。

程序应该这样写:

1.读取眼动数据文本文件,将数据存储到一个列表中。

2打开视频文件,并读取第一帧。

3.在窗口上显示第一帧图像。

4.进入循环,依次读取眼动数据列表中的每个数据。

5.当用户按下鼠标时,记录当前的时间戳,并在图像上绘制一个圆形或者其他标记,标记当前时间戳。

6.在窗口上显示标记后的图像。

眼动追踪py_ide_39

后面的功能分开写不好,这里合在一起写。

眼动追踪py_人工智能_40

眼动追踪py_数据_41

 

眼动追踪py_ide_42

眼动追踪py_数据_43

 

眼动追踪py_人工智能_44

c:/Users/yunswj/AppData/Local/Programs/Python/Python310/python.exe -m 
pip install ipykernel -U --user --force-reinstall
  • 1.
  • 2.
pip install opencv-python
  • 1.
https://cmake.org/download/
  • 1.
import cv2
import threading
class VideoStream:
    def __init__(self, src=0, width=640, height=480, fps=30):
        self.stream = cv2.VideoCapture(src)
        self.stream.set(cv2.CAP_PROP_FRAME_WIDTH, width)
        self.stream.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
        self.stream.set(cv2.CAP_PROP_FPS, fps)
        self.width = int(self.stream.get(cv2.CAP_PROP_FRAME_WIDTH))
        self.height = int(self.stream.get(cv2.CAP_PROP_FRAME_HEIGHT))
        self.fps = int(self.stream.get(cv2.CAP_PROP_FPS))
        self.status = False
        self.frame = None
    def start(self):
        if self.status:
            return None
        self.status = True
        threading.Thread(target=self.update, args=()).start()
    def update(self):
        while self.status:
            _, self.frame = self.stream.read()
    def read(self):
        return self.frame
    def stop(self):
        self.status = False
def main():
    # 创建两个VideoStream对象,用于捕获左右眼视频流
    left_cam = VideoStream(0)
    right_cam = VideoStream(1)
    # 开始捕获视频流
    left_cam.start()
    right_cam.start()
    # 创建OpenCV窗口用于显示视频流
    cv2.namedWindow("Video Stream", cv2.WINDOW_NORMAL)
    while True:
        # 读取左右眼视频流
        left_frame = left_cam.read()
        right_frame = right_cam.read()
        # 在视频流上添加帧率信息
        left_fps_text = f"FPS: {left_cam.fps}"
        right_fps_text = f"FPS: {right_cam.fps}"
        cv2.putText(
            left_frame,
            left_fps_text,
            (10, 30),
            cv2.FONT_HERSHEY_SIMPLEX,
            1,
            (255, 255, 255),
            2,
        )
        cv2.putText(
            right_frame,
            right_fps_text,
            (10, 30),
            cv2.FONT_HERSHEY_SIMPLEX,
            1,
            (255, 255, 255),
            2,
        )
        # 合并左右眼视频流并显示
        merged_frame = cv2.hconcat([left_frame, right_frame])
        cv2.imshow("Video Stream", merged_frame)
        # 按'q'键退出
        if cv2.waitKey(1) & 0xFF == ord("q"):
            break
    # 停止视频流捕获
    left_cam.stop()
    right_cam.stop()
    # 关闭OpenCV窗口
    cv2.destroyAllWindows()
if __name__ == "__main__":
    main()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.