目前有幾個(gè)方案,在下面:
1.電極式眼動(dòng)追蹤:這種技術(shù)通過(guò)在眼球周圍放置電極來(lái)測(cè)量眼睛的運(yùn)動(dòng)。它可以提供非常高的準(zhǔn)確性和分辨率,但需要接觸眼球,因此不太適合長(zhǎng)時(shí)間使用或需要無(wú)接觸測(cè)量的應(yīng)用場(chǎng)景。2.紅外線眼動(dòng)追蹤:這種技術(shù)使用紅外線攝像機(jī)來(lái)觀察眼睛的位置和運(yùn)動(dòng)。由于它不需要接觸眼球,因此非常適合長(zhǎng)時(shí)間使用和需要無(wú)接觸測(cè)量的應(yīng)用場(chǎng)景。它的準(zhǔn)確性和分辨率通常比電極式眼動(dòng)追蹤低。3.磁共振眼動(dòng)追蹤:這種技術(shù)使用磁共振成像來(lái)測(cè)量眼球的位置和運(yùn)動(dòng)。它可以提供非常高的空間分辨率,但時(shí)間分辨率較低,因此不太適合研究快速眼動(dòng)的過(guò)程。4.可穿戴式眼動(dòng)追蹤:這種技術(shù)使用小型傳感器或攝像頭,可以放置在眼鏡或頭盔上,可以隨身攜帶,適用于移動(dòng)應(yīng)用場(chǎng)景。但是由于可穿戴設(shè)備的尺寸和重量限制,其準(zhǔn)確性和分辨率通常較低。5.視網(wǎng)膜追蹤:這種技術(shù)利用視網(wǎng)膜圖像來(lái)跟蹤眼球的位置和運(yùn)動(dòng)。它可以提供非常高的準(zhǔn)確性和分辨率,但只能在特定的實(shí)驗(yàn)條件下使用,例如黑暗環(huán)境下觀察單一的點(diǎn)光源。以我目前念的這個(gè)書(shū),我還是用視覺(jué)方案來(lái)實(shí)現(xiàn):
1.特征提取:選擇適當(dāng)?shù)奶卣鱽?lái)描述眼睛的形狀、顏色、紋理等信息。例如,可以使用Haar級(jí)聯(lián)檢測(cè)器來(lái)提取眼睛的輪廓特征,或者使用顏色分布模型來(lái)提取眼球的顏色特征。這步主要是傳統(tǒng)的2.目標(biāo)檢測(cè):使用機(jī)器學(xué)習(xí)或計(jì)算機(jī)視覺(jué)技術(shù)來(lái)檢測(cè)眼睛的位置和方向。因?yàn)橹苯幽繕?biāo)檢測(cè)是識(shí)別不準(zhǔn)的,現(xiàn)實(shí)太復(fù)雜了。可以使用級(jí)聯(lián)分類器或支持向量機(jī)(SVM)來(lái)識(shí)別眼睛的位置和方向,或者使用卷積神經(jīng)網(wǎng)絡(luò)(CNN)來(lái)分類眼動(dòng)類型。3.跟蹤和估計(jì):根據(jù)檢測(cè)結(jié)果,使用跟蹤和估計(jì)算法來(lái)跟蹤眼睛的位置和運(yùn)動(dòng)軌跡。在捕捉的基礎(chǔ)上開(kāi)始進(jìn)行跟蹤,持續(xù)的來(lái)捕獲。使用卡爾曼濾波器或粒子濾波器來(lái)估計(jì)眼睛的位置和速度,或者使用光流算法來(lái)估計(jì)眼球的運(yùn)動(dòng)軌跡。4.數(shù)據(jù)分析:根據(jù)眼動(dòng)追蹤的結(jié)果,進(jìn)行數(shù)據(jù)分析和可視化。可以計(jì)算注視點(diǎn)的位置、持續(xù)時(shí)間和注視次數(shù)等統(tǒng)計(jì)信息,或者使用熱力圖和軌跡圖來(lái)可視化眼動(dòng)數(shù)據(jù)。這個(gè)也是這次要寫的一個(gè)點(diǎn)。我們?cè)谶@里主要是直接給出ROI的區(qū)域減少算力。
在預(yù)處理步驟中,使用了高斯平滑和邊緣檢測(cè)來(lái)增強(qiáng)圖像特征
在特征提取步驟中,使用了霍夫圓變換來(lái)檢測(cè)圓形區(qū)域
在目標(biāo)檢測(cè)步驟中,找到最大的圓形區(qū)域作為眼球,并在圖像中標(biāo)記出來(lái)
太簡(jiǎn)單了家人們!
但是這個(gè)程序太簡(jiǎn)單了,就是一個(gè)找特征啥的,有點(diǎn)傻。這次換個(gè)庫(kù):
Dlib是一個(gè)C++編寫的機(jī)器學(xué)習(xí)庫(kù),提供了用于人臉檢測(cè)、關(guān)鍵點(diǎn)檢測(cè)、姿態(tài)估計(jì)等任務(wù)的算法,其中也包括用于眼動(dòng)追蹤的算法。Dlib同樣也提供了Python接口,可以在Python中使用Dlib的算法實(shí)現(xiàn)眼動(dòng)追蹤。dlib提供一個(gè)方法可將人臉圖片數(shù)據(jù)映射到128維度的空間向量,如果兩張圖片來(lái)源于同一個(gè)人,那么兩個(gè)圖片所映射的空間向量距離就很近,否則就會(huì)很遠(yuǎn)。因此,可以通過(guò)提取圖片并映射到128維空間向量再度量它們的歐氏距離(Euclidean distance)是否足夠小來(lái)判定是否為同一個(gè)人。我不要人我就要眼睛。
上次覺(jué)得CMake礙眼,卸載了
稍等不知道多久,反正我吃了個(gè)橘子
python.exe -m pip install --upgrade pip
更新一下
安裝成功了
這個(gè)就是里面的dat文件,68個(gè)關(guān)鍵點(diǎn)
先找臉,再找眼,合理!
簡(jiǎn)單的轉(zhuǎn)下顏色,然后直接找
dlib 庫(kù)提供了兩個(gè)用于人臉檢測(cè)的功能。
第一個(gè)是HOG+線性SVM人臉檢測(cè)器,另一個(gè)是深度學(xué)習(xí)MMOD CNN人臉檢測(cè)器。
反正就是找一下面部的區(qū)域:
這些代碼是再找眼部的位置
在范圍之內(nèi)就可以了
有極值坐標(biāo)嘎嘎算
接著進(jìn)一步給出瞳孔的坐標(biāo)
2.0~8.0mm之間瞳孔大小是指虹膜中央的一圓孔的直徑,受光線、年齡、人種、屈光狀態(tài)、目標(biāo)遠(yuǎn)近和情緒等因素影響,正常范圍在2.0~8.0mm之間。瞳孔在強(qiáng)光下縮小,在黑暗下擴(kuò)大,這是人體的正常生理反應(yīng)。瞳孔大小不一致或?qū)夥磻?yīng)異常可能是腦部或眼部疾病的征兆。
我考你,你遇到這種情況怎么寫?
先給外圈的大圓套上
再處理瞳孔
多數(shù)情況下,我們是要實(shí)時(shí)的檢測(cè)的:
來(lái)一段從攝像頭捕獲的代碼
祖?zhèn)鞔a不能丟
更實(shí)用性的是兩個(gè)攝像頭來(lái)捕捉眼動(dòng):
這個(gè)寫的比較呆逼,不過(guò)我在后面會(huì)有進(jìn)行封裝
現(xiàn)在是彈出兩個(gè)框來(lái)輸出圖像,趕緊不好看捏!我們來(lái)讓他并排排列!
使用OpenCV中的cv2.hconcat()函數(shù)將兩個(gè)視頻幀水平合并在一起,并使用cv2.imshow()函數(shù)將合并后的視頻幀顯示出來(lái)。
就很簡(jiǎn)單,其實(shí)這里就變成一個(gè)合并橫向排列的視頻組,但是在處理流程上面有問(wèn)題,應(yīng)該先單一處理,最后合并結(jié)果。
封裝好啦!(有點(diǎn)傻逼哦~)
繼續(xù)封裝,注意視頻流
工程問(wèn)題的話,上面的代碼還是太慢了,讓我來(lái)加一點(diǎn)多線程的魔法!
設(shè)計(jì)兩個(gè)線程分別處理左右眼視頻幀的讀取和合并:
隊(duì)列無(wú)疑是最合適的數(shù)據(jù)結(jié)構(gòu)
合并函數(shù)也是如此,因?yàn)閳D像這種處理的方式就適合隊(duì)列
這個(gè)是提前設(shè)置好的
標(biāo)準(zhǔn)的流程
這個(gè)就是線程的啟動(dòng)了,然后一個(gè)循環(huán)不停的合并
也可以加一個(gè)日志的功能,直接寫到最上面就行
現(xiàn)在的程序一點(diǎn)也不裝逼,如果可以加一些文字什么的,就更好啦!
要把視頻流封裝成一個(gè)類,然后里面也是多線程處理
在下面調(diào)用的時(shí)候,就是實(shí)例化代碼
這里就顯示一個(gè)左眼的FPS信息疊加
代碼中,putText函數(shù)用于將幀率信息添加到視頻幀的左上角。其中,cv2.FONT_HERSHEY_SIMPLEX指定了字體類型,1指定了字體大小,(255, 255, 255)指定了字體顏色,2指定了字體線寬。
一方面顯示是可視化,另一方面我們需要保存具體的眼動(dòng)數(shù)據(jù)來(lái)后處理。可以在程序中添加一個(gè)函數(shù)來(lái)提取圓形框的坐標(biāo)信息,并將它們保存到一個(gè)文件中。
這個(gè)是簡(jiǎn)單版本
eye_data 是一個(gè)包含眼動(dòng)信息的列表,每個(gè)元素都是一個(gè)二元組,表示眼睛的坐標(biāo)。在循環(huán)中,將每個(gè)元素寫入文件中,每個(gè)坐標(biāo)之間用逗號(hào)分隔,每行結(jié)束后添加一個(gè)換行符。
假設(shè)圓形框的半徑為 r,圓心坐標(biāo)為 (x, y),那么可以使用 OpenCV 中的 circle 函數(shù)來(lái)繪制圓形框。在繪制圓形框時(shí),同時(shí)將圓心坐標(biāo)和半徑信息保存到一個(gè)列表中:在每次繪制圓形框時(shí),將圓心坐標(biāo)和半徑信息添加到 eye_data 列表中。最后,可以將 eye_data 中的信息保存到一個(gè)文本文件中:
現(xiàn)在就是一個(gè)較為完善的函數(shù)了
再讓我封裝一下:
在視頻幀上繪制眼球圓形框,并返回圓形框的坐標(biāo)信息
這個(gè)是信息保存的函數(shù)
目前實(shí)現(xiàn)的功能挺多的了,現(xiàn)在來(lái)寫一個(gè)GUI吧!
就兩個(gè)線程就行
初始化是捕獲線程,在run函數(shù)里面進(jìn)行了顏色的轉(zhuǎn)換
使用定時(shí)器來(lái)更新幀率信息
這些都簡(jiǎn)單
都比較簡(jiǎn)單吧?
完整代碼我放在Github上面了。
我們拿到了保存的數(shù)據(jù),想重新把他們展示出來(lái)。假設(shè)眼動(dòng)數(shù)據(jù)文件是一個(gè)文本文件,每行包含兩個(gè)數(shù)字,分別代表左右眼的坐標(biāo)。
使用matplotlib庫(kù)中的plot函數(shù)來(lái)繪制左右眼的坐標(biāo)。下面是一個(gè)簡(jiǎn)單的示例代碼,繪制左眼的x坐標(biāo)和y坐標(biāo):
來(lái)封裝一下
好啦!
再實(shí)現(xiàn)一個(gè)功能吧!
在播放的時(shí)候點(diǎn)按鼠標(biāo)就可以捕捉當(dāng)前播放的數(shù)據(jù)而且在圖片上面標(biāo)注時(shí)間戳。
程序應(yīng)該這樣寫:
1.讀取眼動(dòng)數(shù)據(jù)文本文件,將數(shù)據(jù)存儲(chǔ)到一個(gè)列表中。2打開(kāi)視頻文件,并讀取第一幀。3.在窗口上顯示第一幀圖像。4.進(jìn)入循環(huán),依次讀取眼動(dòng)數(shù)據(jù)列表中的每個(gè)數(shù)據(jù)。5.當(dāng)用戶按下鼠標(biāo)時(shí),記錄當(dāng)前的時(shí)間戳,并在圖像上繪制一個(gè)圓形或者其他標(biāo)記,標(biāo)記當(dāng)前時(shí)間戳。6.在窗口上顯示標(biāo)記后的圖像。
讀取
后面的功能分開(kāi)寫不好,這里合在一起寫。
先讀取視頻幀,然后就是獲取幀率,創(chuàng)建一個(gè)窗口
能看懂吧?
這個(gè)就是繪制標(biāo)記
許久不用Python,然后壞了,各種運(yùn)行出錯(cuò),VSCode都撲街了,哭死,不知道咋辦了。
解決不了
重新安裝就好啦!
嚶嚶嚶,沒(méi)看上
c:/Users/yunswj/AppData/Local/Programs/Python/Python310/python.exe -m
pip install ipykernel -U --user --force-reinstall
pip install opencv-python
https://cmake.org/download/
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():
# 創(chuàng)建兩個(gè)VideoStream對(duì)象,用于捕獲左右眼視頻流
left_cam = VideoStream(0)
right_cam = VideoStream(1)
# 開(kāi)始捕獲視頻流
left_cam.start()
right_cam.start()
# 創(chuàng)建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()
# 關(guān)閉OpenCV窗口
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
審核編輯 :李倩
-
傳感器
+關(guān)注
關(guān)注
2553文章
51503瀏覽量
757139 -
檢測(cè)器
+關(guān)注
關(guān)注
1文章
871瀏覽量
47805 -
機(jī)器學(xué)習(xí)
+關(guān)注
關(guān)注
66文章
8453瀏覽量
133143 -
眼動(dòng)追蹤
+關(guān)注
關(guān)注
0文章
18瀏覽量
6766
原文標(biāo)題:開(kāi)發(fā)一個(gè)完整的眼動(dòng)追蹤應(yīng)用-Python版
文章出處:【微信號(hào):TT1827652464,微信公眾號(hào):云深之無(wú)跡】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論