数字图像处理课程设计-疲劳检测系统

前言

  • 此系统基于MATLAB设计,核心思想是PERCLOS算法.

  • 参考文章MATLAB疲劳检测系统 - 知乎

  • 需要源码的,私信或者留下邮箱

    一、课程设计任务

应用数字图像处理相关知识和技术实现某一应用,如人脸识别、动物识别、水果识别等综合性任务,题目自选。

本文在matlab R2018b开发环境下,实现人脸检测系统。

疲劳检测可以应用于大巴车司机,货车司机疲劳驾驶监测,现在很多情况下大巴车或者货车等司机都由于休息不好,疲劳上路,这就给安全造成了及其大的隐患。如果有一套系统,可以实时接入车辆摄像头,摄像头对准司机,当检测到司机疲劳状态的时候,则提醒后台并且语音提醒,以做出正确决策,避免车祸等悲剧的发生。该系统也可以应用于上课学生专注度分析,进行疲劳预警。

二、设计框图

image-20211224002323644

三、准备工作

  • 开发环境:windows 10,matlab R2018b
  • 制图软件:visio 2013
  • 素材示意:人脸图像/视频
image-20211224002445267

四、任务流程

4.1视频预处理

  1. 首先将彩色视频video.avi读入,将图像分帧。
obj = VideoReader(uigetfile('*.avi','选择视频'));%输入视频位置
setappdata(0,'obj',obj);%设置全局变量
Show_Frames=read(obj,1);%显示第一帧作为封面
axes(handles.axes1);
imshow(Show_Frames);
set(handles.listbox1,'String','分帧开始...');

prompt={'输入图片名是几位数:'};
defans={'2'};%默认两位数
p=inputdlg(prompt,'输入位数',1,defans);
numzeros=str2num(p{1});
nz = strcat('%0',num2str(numzeros),'d');

numFrames = obj.NumberOfFrames;% 帧的总数
for k = 1 :5 % 读取前5帧 numFrames
frame = read(obj,k);%读取第几帧
id=sprintf(nz,k);
imwrite(frame,strcat('video_images/',id,'.jpg'),'jpg');% 保存帧
end
set(handles.listbox1,'String','分帧结束');
  1. 利用MATLAB函数rgb2gray转换成灰度图像。

  2. 去除视频黑边,定位有效图像区域。

  3. 将结果输出到指定路径images下。

function [Irect, rect] = GetValideImage(Img, flag)
% 获取有效图像区域
if nargin < 2
flag = 1;
end

% 灰度化
if ndims(Img) == 3
I = rgb2gray(Img);
else
I = Img;
end
% 去除视频黑边,定位有效图像区域
tol = 1000;
sz = size(I);
cs = sum(I, 1);
c = find(cs > tol);
cmin = min(c);
cmax = max(c);
rect = [cmin 1 cmax-cmin sz(1)];
% 图像切割,获取有效区域图像
Irect = imcrop(Img, rect);
% 显示中间处理过程图像
if flag
figure;
subplot(2, 2, 1); imshow(Img, []); title('原图像');
subplot(2, 2, 2); imshow(I, []); title('灰度图像');
subplot(2, 2, 3); imshow(Img, []); title('有效区域图像标记');
hold on;
rectangle('Position', rect, 'EdgeColor', 'r', 'LineWidth', 2);
hold off;
subplot(2, 2, 4); imshow(Irect, []); title('有效区域图像');
end

4.2图片分割

4.2.1 人脸定位

  1. 读入images路径下所有jpg图像。

  2. 利用MATLAB函数rgb2hsv将RGB颜色转换为HSV。

% 颜色空间转换
hsv = rgb2hsv(Img);
h = hsv(:, :, 1);
s = hsv(:, :, 2);
v = hsv(:, :, 3);
% 区域数据范围
hsp = [0.01 0.5];
ssp = [0.1 0.85];
vsp = [0.25 0.85];
sz = size(h);
  1. 根据HSV对肤色定位,提取人脸区域。
% 初始化模板
mask = zeros(sz);
% 肤色定位
for i = 1 : sz(1)
for j = 1 : sz(2)
if h(i, j) > hsp(1) && h(i, j) < hsp(2) && ...
s(i, j) > ssp(1) && s(i, j) < ssp(2) && ...
v(i, j) > vsp(1) && v(i, j) < vsp(2)
mask(i, j) = 1;
end
end
end
% 形态学处理
mask = logical(mask);
mask = imclose(mask, strel('disk', 15));
mask = imopen(mask, strel('disk', 15));
mask = imfill(mask, 'holes');
% 提取人脸区域
[L, num] = bwlabel(mask);
stats = regionprops(L);
Ar = cat(1, stats.Area);
[Ar, ind] = sort(Ar, 'descend');
bw = mask;
bw(L ~= ind(1)) = 0;

4.2.2人眼定位

  1. 先对图像预处理,利用MATLAB函数rgb2gray转换成灰度图像。利用函数medfilt2对图像中值滤波,利用灰度积分find进行投影。
% 灰度化
if ndims(Img) == 3
I = rgb2gray(Img);
else
I = Img;
end
% 中值滤波
I = medfilt2(I, [5 5]);
% 灰度积分投影
sz = size(I);
[r, c] = find(I > 0);
rmin = min(r);
rmax = max(r);
cs = sum(I, 1);
rs = sum(I, 2);
[maxcs, indmaxcs] = max(cs);
[maxrs, indmaxrs] = max(rs);
  1. 对人眼区域定位。
% 人眼区域定位
cstart = max(sz(2)-indmaxcs-35, 8);
csend = min(indmaxcs + 15, sz(2)-20);
rstart = max(indmaxrs-40, 25);
rsend = indmaxrs;
rect = [cstart rstart csend-cstart rsend-rstart];
  1. 裁掉多余的区域。
% 人眼区域裁剪
Im = imcrop(Img, rect);
if flag
figure;
subplot(2, 2, 1); imshow(Img, []); title('原图像');
subplot(2, 2, 2); imshow(I, []); hold on;
rectangle('Position', rect, 'EdgeColor', 'r');
hold off;
title('灰度图像');
subplot(2, 2, 3); plot(1:sz(2), cs); title('列投影曲线');
subplot(2, 2, 4); plot(rs, 1:sz(1)); title('行投影曲线');
end

4.2.3人眼精确定位

  1. 图像预处理,利用MATLAB函数rgb2gray对图像进行灰度化。利用函数graythresh进行二值化。提取图像边缘。
% 获取精确人眼区域
if nargin < 2
flag = 1;
end

% 灰度化
if ndims(Img) == 3
I = rgb2gray(Img);
else
I = Img;
end
% 二值化
th = max(graythresh(I)*0.4, 0.1);
bw = im2bw(I, th);
% 提取边缘
bwe = edge(bw, 'canny');
% 填孔处理
bwd = imfill(bwe, 'holes');
bwf = bwd;
bwf = imdilate(bwf, strel('square', 3));
bwf = imfill(bwf, 'holes');
% 去掉边缘噪声
[L, num] = bwlabel(bwf);
stats = regionprops(L);
Ar = cat(1, stats.Area);
[Ar, ind] = sort(Ar, 'descend');
if num > 2
for j = 3 : num
bwf(L == ind(j)) = 0;
end
end
  1. 提取定位结果。
% 提取定位结果
rect1 = stats(ind(1)).BoundingBox;
rect2 = stats(ind(2)).BoundingBox;
rect1(2) = rect1(2) - 2;
rect2(2) = rect2(2) - 2;
rect{1} = rect1;
rect{2} = rect2;

4.3疲劳检测

  1. 利用PERCLOS算法,计算人眼在单位时间内闭合所占比。
data = cat(1, Nv.nv);
Nmin = min(data);
Nmax = max(data);
rate = (data-Nmin)./(Nmax-Nmin);
set(handles.listbox3,'string',rate)
pause(5) %%%%每间隔2s时间处理下一帧图像
  1. 输出结果, 计算的perclos值与tol做比较判断是否疲劳
tol = 0.4;  %%%归一化判断标准
status = '正常';
for i = 1 : N
if rate(i) < tol && isequal(status, '正常')
status = '疲劳';
start = i;
end
if rate(i) < tol && isequal(status, '疲劳') && i - start > 1
status = '睡着';
start = i;
end
if rate(i) < tol && isequal(status, '睡着') && i - start > 2
status = '疲劳';
start = i;
end
if rate(i) > tol
status = '正常';
end
Nv(i).status = status;

end

五、结果

  1. GUI界面
  1. 输入视频,分帧处理,分割图像
img
  1. 输出结果
img

六、项目总结

使用图像预处理技术得到灰度分配较为均匀的图像,然后分别利用水平和垂直灰度积分投影曲线结合人脸的结构特征找到眼睛的位置坐标,实现了准确的眼睛定位,通过perclos技术技术眨眼率,根据先验值得到是否疲劳。完成了疲劳检测系统的设计。

通过本次项目设计,不仅熟练应用了MATLAB的基本函数,也学到了PERCLOS算法。

PERCLOS算法(Percentage of Eyelid Closure Over the Pupil Time的缩写,意为单位时间里眼睛闭合时间所占的百分比)

PERCLOS原理:F=$\frac{t3-t2}{t4-t1}$*100%

F是一的话就是睁眼;连续N帧后便可获取关于01之间的序列,然后分析0在该序列中所占比例来描述疲劳状态。

img