Smile Detection
This program demonstrates the smile detector.
NOTE: Smile intensity will only be valid after a first smile has been detected.
Sources:
Contents
Options
% this is the frontal face classifier cascadeName = fullfile(mexopencv.root(),'test','haarcascade_frontalface_alt.xml'); % this is the secondary smile classifier nestedCascadeName = fullfile(mexopencv.root(),'test','haarcascade_smile.xml'); % image scale greater or equal to 1, try 2.0 for example, % the larger the faster the processing scale = 1.0; % attempts detection of flipped image as well tryflip = false;
Initialize
% download XML files if missing download_classifier_xml(cascadeName); download_classifier_xml(nestedCascadeName); % load cacade classifiers cascade = cv.CascadeClassifier(cascadeName); assert(~cascade.empty(), 'Could not load face cascade'); nestedCascade = cv.CascadeClassifier(nestedCascadeName); assert(~nestedCascade.empty(), 'Could not load smile cascade'); scale = max(scale, 1.0);
Main loop
(either video feed or a still image)
if false % read an image frame = cv.imread(fullfile(mexopencv.root(),'test','lena.jpg'), 'Color',true); % detect faces/eyes and draw detections frame = detectAndDraw(frame, cascade, nestedCascade, scale, tryflip); imshow(frame); else % prepare video input cap = createVideoCapture([], 'lena'); pause(1); assert(cap.isOpened(), 'Failed to initialize camera capture'); % prepare figure frame = cap.read(); assert(~isempty(frame), 'Failed to read frame'); hImg = imshow(frame); % video feed while ishghandle(hImg) % read frame frame = cap.read(); if isempty(frame), break; end % detect faces/eyes and draw detections frame = detectAndDraw(frame, cascade, nestedCascade, scale, tryflip); % update set(hImg, 'CData',frame); drawnow; end cap.release(); end
Process function
function img = detectAndDraw(img, cascadeF, cascadeS, scale, tryflip) % smile min/max neighbors persistent minNB maxNB; % downscale image and preprocess it fx = 1/scale; gray = cv.cvtColor(img, 'RGB2GRAY'); gray = cv.resize(gray, fx, fx); gray = cv.equalizeHist(gray); [h,w] = size(gray); % detection options detectOpts = { 'ScaleFactor',1.1, ... 'MinNeighbors',2, ... ... 'FindBiggestObject',true, ... ... 'DoRoughSearch',true, ... 'ScaleImage',true, ... 'MinSize',[30 30] }; % detect faces tic faces = cascadeF.detect(gray, detectOpts{:}); if tryflip faces2 = cascadeF.detect(cv.flip(gray, 1), detectOpts{:}); faces2 = cellfun(@(r) [w-r(1)-r(3) r(2:4)], faces2, 'Uniform',false); faces = [faces(:); faces2(:)]; end toc % draw clrs = uint8(255 * lines(7)); for i=1:numel(faces) r = faces{i}; ii = mod(i-1, size(clrs,1)) + 1; drawOpts = {'Color',clrs(ii,:), 'Thickness',3}; % draw faces aspect_ratio = r(3)/r(4); if 0.75 < aspect_ratio && aspect_ratio < 1.3 center = round((r(1:2) + r(3:4)*0.5) * scale); radius = round((r(3) + r(4)) * 0.25*scale); img = cv.circle(img, center, radius, drawOpts{:}); else pt1 = round(r(1:2) * scale); pt2 = round((r(1:2) + r(3:4) - 1) * scale); img = cv.rectangle(img, pt1, pt2, drawOpts{:}); end % detect nested objects (smile) in lower half of face half_height = round(r(4)/2); r(2) = r(2) + half_height; r(4) = half_height - 1; if false && mexopencv.require('images') grayROI = imcrop(gray, [r(1:2)+1 r(3:4)]); else grayROI = cv.Rect.crop(gray, r); end nestedObjs = cascadeS.detect(grayROI, ... 'ScaleFactor',1.1, ... 'MinNeighbors',0, ... ... 'FindBiggestObject',true, ... ... 'DoRoughSearch',true, ... ... 'DoCannyPruning',true, ... 'ScaleImage',true, ... 'MinSize',[30 30]); % The number of detected neighbors depends on image size (and also % illumination, etc.). The following steps use a floating minimum % and maximum of neighbors. Intensity thus estimated will be accurate % only after a first smile has been displayed by the user. smileNB = numel(nestedObjs); if isempty(minNB) minNB = smileNB; maxNB = smileNB; end maxNB = max(maxNB, smileNB); % draw rectangle bar on left side of image reflecting smile intensity intensity = (smileNB - minNB) / (maxNB - minNB + 1); h_rect = round(h * intensity); clr = round([255 * intensity, 0, 0]); img = cv.rectangle(img, [0 h], [round(w/10) h-h_rect], ... 'Color',clr, 'Thickness','Filled'); end end
Elapsed time is 0.075507 seconds. Elapsed time is 0.056394 seconds. Elapsed time is 0.059050 seconds. Elapsed time is 0.058014 seconds. Elapsed time is 0.062390 seconds. Elapsed time is 0.058634 seconds. Elapsed time is 0.054683 seconds. Elapsed time is 0.054191 seconds. Elapsed time is 0.053590 seconds. Elapsed time is 0.056938 seconds. Elapsed time is 0.061333 seconds. Elapsed time is 0.059133 seconds. Elapsed time is 0.053069 seconds. Elapsed time is 0.059209 seconds. Elapsed time is 0.058121 seconds. Elapsed time is 0.056840 seconds. Elapsed time is 0.059636 seconds. Elapsed time is 0.056073 seconds. Elapsed time is 0.058268 seconds. Elapsed time is 0.055052 seconds. Elapsed time is 0.056169 seconds. Elapsed time is 0.054429 seconds. Elapsed time is 0.054508 seconds. Elapsed time is 0.054266 seconds. Elapsed time is 0.053605 seconds. Elapsed time is 0.054506 seconds. Elapsed time is 0.054681 seconds. Elapsed time is 0.054852 seconds. Elapsed time is 0.055301 seconds. Elapsed time is 0.060512 seconds. Elapsed time is 0.053368 seconds. Elapsed time is 0.055298 seconds. Elapsed time is 0.054175 seconds. Elapsed time is 0.055073 seconds. Elapsed time is 0.054710 seconds. Elapsed time is 0.054834 seconds. Elapsed time is 0.053693 seconds. Elapsed time is 0.053870 seconds. Elapsed time is 0.054673 seconds. Elapsed time is 0.054641 seconds. Elapsed time is 0.054990 seconds. Elapsed time is 0.054420 seconds. Elapsed time is 0.053657 seconds. Elapsed time is 0.054728 seconds. Elapsed time is 0.054503 seconds. Elapsed time is 0.053485 seconds. Elapsed time is 0.053717 seconds. Elapsed time is 0.053619 seconds. Elapsed time is 0.054895 seconds. Elapsed time is 0.054330 seconds.
Helper function
function download_classifier_xml(fname) if exist(fname, 'file') ~= 2 % attempt to download trained Haar/LBP/HOG classifier from Github url = 'https://cdn.rawgit.com/opencv/opencv/3.2.0/data/'; [~, f, ext] = fileparts(fname); if strncmpi(f, 'haarcascade_', length('haarcascade_')) url = [url, 'haarcascades/']; elseif strncmpi(f, 'lbpcascade_', length('lbpcascade_')) url = [url, 'lbpcascades/']; elseif strncmpi(f, 'hogcascade_', length('hogcascade_')) url = [url, 'hogcascades/']; else error('File not found'); end fprintf('Downloading cascade classifier "%s"...\n', [f ext]); url = [url f ext]; urlwrite(url, fname); end end