https://ieeexplore.ieee.org/document/8242842
Matlab-GUI编程:简单计算器的实现
https://ww2.mathworks.cn/help/supportpkg/usbwebcams/ug/webcam.html? searchHighlight=webcam&s_tid=doc_srchtitle
https://ww2.mathworks.cn/help/vision/examples/face-detection-and-tracking-using-the-klt-algorithm.html?searchHighlight=klt&s_tid=doc_srchtitle
https://ww2.mathworks.cn/help/
更新device.String为可用webcam设备列表
OpeningFcn函数下实现:
% 更新device.String
handles.device.String=webcamlist;
% 更新handles
guidata(hObject, handles);
①device:单击菜单返回可用网络摄像头设备列表,并选择设备。(关于webcam使用请参考matlab帮助文档)
%% device_Callback中实现如下:
% handles下添加webcam对象,设备由device.String指定
handles.cam = webcam(hObject.String{hObject.Value});
% 更新handles
guidata(hObject, handles);
% 对下拉菜单resolution的String更新当前设备支持分辨率列表
handles.resolution.String=handles.cam.AvailableResolutions;
②resolution:单击选择当前设备的拍摄分辨率
resolution_Callback中实现如下:
% 指定当前设备的拍摄分辨率
handles.cam.Resolution=hObject.String{hObject.Value};
③preview:显示视频流,并使用级联分类器捕捉人脸,人眼并标注。
该部分内容主要函数有:matlab视觉工具箱中经典人脸检测算法之级联分类器:vision.CascadeObjectDetector
图像滤波:imfilter
包围盒标注:insertObjectAnnotation 或者 insertShape
需要注意的是preview的回调函数同时也是本系统的Main函数,之后操作多数在该回调里执行,通过读取其他组件信息,控制下一步行动
% preview_Callback中实现如下:
handles.win.String='The Cam has been conformed! Showing now.';
% 定义人脸检测器
faceDetector = vision.CascadeObjectDetector;
% EyePairSmallDetector = vision.CascadeObjectDetector('EyePairSmall');
% 定义左眼检测器并指定在ROI下检测
EyePairSmallDetector = vision.CascadeObjectDetector('LeftEyeCART');
EyePairSmallDetector.UseROI=true;
% 选定1号坐标窗口
axes(handles.axes1);
% 高斯滤波卷积核
h3_5=fspecial('gaussian',3,0.5);
%网络摄像头运行正常(显示视频流)
while isempty(handles.cam)==0
if handles.exit.Value==1
break;
end
% 获取当前捕捉画面
shot=snapshot(handles.cam);
% 对画面高斯滤波
shot=imfilter(shot,h3_5);
% 在未使用klt追踪前,正常拍摄并捕捉人眼
if handles.klt.Value==0
% 定位人脸区域,并获取包围盒
[~,facebbox,~]=shotfacetrack(shot,faceDetector,[120 120],1);
% 如果检测到人脸
if isempty(facebbox)==0
% 标记人脸区域
detectedshot = insertObjectAnnotation(shot,'rectangle',facebbox,'Face','LineWidth',2);
% 定位人眼区域,并返回包围盒
eyesbbox=EyePairSmallDetector(shot,facebbox(1,:));
% 如果检测到人眼
if isempty(eyesbbox)==0
% 标记人眼区域
detectedshot = insertObjectAnnotation(detectedshot,'rectangle',eyesbbox(1,:),'Eyes','LineWidth',2,'Color','blue');
end
% 显示和刷新
imshow(detectedshot);
drawnow;
end
else
break;
end
end
④ klt:光流追踪人眼
该部分内容采用KLT算法实现对人眼区域的稳定追踪(关于KLT实现可参考另一篇博客:https://blog.csdn.net/Ephemeroptera/article/details/84452439),在klt成功追踪人眼区域之后,我们将抠出人眼并采取一系列图像处理:伽马增强+二值化反色处理+形态学闭运算(平滑连通部分)+提取最大连通域(虹膜区域)+计算虹膜均值中心。
在提取虹膜的二值化过程中,为了适应不同光照下提取的鲁棒性,我们可以通过gamma和thresh滑动条设置gamma系数和二值化的阈值,来更好地提取可靠的虹膜区域。
该部分使用的函数主要有:特征点提取:detectMinEigenFeatures(其他特征点提取可参考图像特征点检测)
光流追踪:vision.PointTracker、initialize()、setPoints()
几何运动估计:estimateGeometricTransform
点的几何变换:transformPointsForward
图像处理:imadjust(图像增强)、imbinarize(图像二值化)、imclose(形态学闭运算)、bwlabel(连通域提取)
%% preview回调函数同时也是main函数,故大部分操作仍在该回调中执行
%% KLT光流追踪
handles.win.String='The inital ROI to eyes has been located! Starting KLT-Track now .';
bboxPoints = bbox2points(eyesbbox(1, :));
points = detectMinEigenFeatures(rgb2gray(shot), 'ROI', eyesbbox(1,:));
imshow(detectedshot),hold on,plot(points),hold off;
% klt准备工作:提取眼部特征点并初始化
pointTracker = vision.PointTracker('MaxBidirectionalError', 2);
points = points.Location;
initialize(pointTracker, points, shot);
oldPoints = points;
EARdata=[];
numOfsamples=0;
recent=1;
RECORD=zeros(20,1);
se=strel('disk',1);
%网络摄像头运行正常(获取视频流,开始追踪)
while isempty(handles.cam)==0
if handles.exit.Value==1
break;
end
% 获取当前捕捉画面
shot=snapshot(handles.cam);
% 获取可疑点
[points, isFound] = step(pointTracker, shot);
% 获取当前可靠追踪点
visiblePoints = points(isFound, :);
% 获取可靠点上一帧位置
oldInliers = oldPoints(isFound, :);
% need at least 2 points
if size(visiblePoints, 1) >= 2
% 获取新旧点之间的几何变换映射
[xform, oldInliers, visiblePoints] = estimateGeometricTransform(oldInliers, visiblePoints, 'similarity', 'MaxDistance', 4);
% 对包围盒进行同样映射,保持包围盒的追踪同步
bboxPoints = transformPointsForward(xform, bboxPoints);
bboxPolygon = reshape(bboxPoints', 1, []);
rectangeBbox = rectbbox(bboxPoints);
% 获取校正后的bbox,便于裁取人眼
a= rectangeBbox(1);
b= rectangeBbox(2);
deltaX= rectangeBbox(3);
deltaY= rectangeBbox(4);
rectangeBbox= round([a+0.1*deltaX,b+0.5*deltaY,0.7*deltaX,0.4*deltaY]);
% 裁取人眼
eyes=imresize(imcrop(shot,rectangeBbox),[35 35]);
% 显示原始图像
axes(handles.axes3);
imshow(eyes);
drawnow;
% 伽马增强+反色处理+形态学闭运算平滑连通域
axes(handles.axes4);
eyes_gamma=imadjust(eyes,[],[],handles.gamma.Value);
eyesBin=1-imbinarize(rgb2gray(eyes_gamma),handles.thresh.Value);
eyesBin=imclose(eyesBin,se);
imshow(eyesBin);
drawnow;
% 提取最大连通域即人眼的虹膜区域
axes(handles.axes5);
% 提取最大连通域
[L num]=bwlabel(eyesBin,8);
maxL=mode(L(L~=0));
eyesBin(find(L~=maxL))=0;
% 提取虹膜的矩形边界
[r c]=find(eyesBin==1);
minX=min(c);
maxX=max(c);
minY=min(r);
maxY=max(r);
if max(eyesBin)==0
minX=16;
maxX=16;
minY=16;
maxY=16;
end
% 计算虹膜区域的均值中心
Xmean=mean([minX,maxX]);
Ymean=mean([minY,maxY]);
% 绘制定位经纬线
target=eyesBin;
target(:,minX)=1;
target(:,maxX)=1;
target(minY,:)=1;
target(maxY,:)=1;
imshow(target);
hold on,plot(Xmean,Ymean,'Marker','*','MarkerSize',13,'MarkerEdgeColor','r','MarkerFaceColor','r'),hold off;
% 显示klt追踪
axes(handles.axes1);
shot = insertShape(shot, 'Rectangle', rectangeBbox,'LineWidth', 2,'Color','green');
shot = insertShape(shot, 'Polygon', bboxPolygon,'LineWidth', 2);
shot = insertMarker(shot, visiblePoints, '+', 'Color', 'white');
imshow(shot);
drawnow;
% 新旧追踪点轮替
oldPoints = visiblePoints;
setPoints(pointTracker, oldPoints);
end
⑧auto:该组件命令将自动检测眨眼并检测疲劳
眨眼检测:
基于眼部的landmarks分析眨眼信息(Real-Time Eye Blink Detection using Facial Landmarks)的论文中提出眼睛开闭系数EAR来判断眼睛的开闭程度。
作者通过分析眼部轮廓特征点的纵横比来分析睁眼情况,对于提取的虹膜区域,我们采用简单的高度信息来表示眼睛开闭特征。考虑到眼睛大小因人而异,因此不宜使用一个恒定阈值来判定眨眼情况。首先我们先采样100次虹膜高度信息(包含眨眼动作),我们采用kmeans方法对其分为两类并分别计算类别中心。然后在实时眨眼检测时,计算当前虹膜高度与类别中心的距离可以区分两种状态。
疲劳检测:
由于聚类算法未能给出睁眼和闭眼状态的标签。因此我们将两个类别中心的均值作为疲劳判别的阈值,分析当前帧是否为疲劳帧,采用时间窗分析的形式分析20帧内情况疲劳帧的个数,当fatigue_frames > fatigue_coefficient * 20 的时候即可判定疲劳状态,当然考虑到不同人眨眼持续时长不同,可以滑动条手动设置疲劳系数 fatigue_coefficient
该部分主要函数有:kmeans(聚类)
pdist(欧式距离计算)
%% preview回调函数同时也是main函数,故大部分操作仍在该回调中执行
%% 疲劳检测
% 记录最近眨眼情况
RECORD(recent)=EAR;
if recent==20
axes(handles.axes6);
axis([1 20 0 max(Center)+10]);
stem(RECORD);
hold on,plot([0 20],[Center(1,:),Center(1,:)],'LineWidth',2,'Color','r'),...
plot([0 20],[Center(2,:),Center(2,:)],'LineWidth',2,'Color','blue');
plot([0 20],[Average Average],'--','LineWidth',2,'Color','green');
text(20,Center(1,:),'open');
text(20,Center(2,:),'close');
text(20,Average,'thresh');
hold off;
recent=0;
weak=numel(RECORD(RECORD=round(handles.fatigueCoef.Value*20)
handles.fatigue.String='疲劳';
else
handles.fatigue.String='正常';
end
end
recent=recent+1;
end
收集样本:
聚类成功,眨眼分析:
疲劳检测: