{"id":6177,"date":"2015-09-11T09:00:04","date_gmt":"2015-09-11T13:00:04","guid":{"rendered":"https:\/\/blogs.mathworks.com\/pick\/?p=6177"},"modified":"2015-09-10T10:49:55","modified_gmt":"2015-09-10T14:49:55","slug":"detect-and-track-multiple-faces","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/pick\/2015\/09\/11\/detect-and-track-multiple-faces\/","title":{"rendered":"Detect and Track Multiple Faces"},"content":{"rendered":"<h1><\/h1>\r\nAvi's pick of the week is <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/47105-detect-and-track-multiple-faces\">Detect and Track Multiple Faces <\/a>by <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/3112899-dima-lisin\">Dima Lisin<\/a>.\r\n\r\nOne of the projects I was working on recently required the detection and tracking of multiple objects (pedestrians in my case) over time in a video stream. While I know how to implement this myself I was hoping someone had some code I could modify for my problem, as I often do I called my friend Dima who is a developer on the <a href=\"https:\/\/www.mathworks.com\/products\/computer-vision\/\">Computer Vision System Toolbox<\/a> team. Dima pointed me to his excellent File Exchange submission that I was able to modify to solve my problem in under a minute.\r\n\r\nThere are three basic steps required to solve the object detection and tracking problem:\r\n<div>\r\n<ol>\r\n\t<li>Detect object of interest in current frame<\/li>\r\n\t<li>Match detections to current list of objects the system is tracking<\/li>\r\n\t<li>Update the status of each track, create new tracks, and delete lost tracks<\/li>\r\n<\/ol>\r\n<\/div>\r\nFirst, let's look at how this is done in Dima's code.\r\n\r\nWe start by connecting to a webcam using the USB Webcam support package.\r\n<pre class=\"codeinput\">vidObj = webcam;\r\n<\/pre>\r\nThe next step is to create an object that is used to detect faces in input frames, in this case I use vision.CascadeOjectDetector that detects faces by default.\r\n<pre class=\"codeinput\">faceDetector = vision.CascadeObjectDetector(); <span class=\"comment\">% Finds faces by default<\/span>\r\n<\/pre>\r\nThe last object I create is used to \"track\" all the detected faces.\r\n<pre class=\"codeinput\">tracker = MultiObjectTrackerKLT;\r\n\r\n<span class=\"comment\">% We then acquire new frames till we succesully detect the first<\/span>\r\n<span class=\"comment\">% object\/face.<\/span>\r\nvideoPlayer  = vision.DeployableVideoPlayer;\r\n\r\n<span class=\"comment\">% Iterate until we have successfully detected a face<\/span>\r\nbboxes = [];\r\n<span class=\"keyword\">while<\/span> isempty(bboxes)\r\n    framergb = snapshot(vidObj);\r\n    frame = rgb2gray(framergb);\r\n    bboxes = faceDetector.step(frame);\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre>\r\nNow lets look at the first detected object or face.\r\n<pre class=\"codeinput\">figure;\r\nframergb = insertObjectAnnotation(framergb,<span class=\"string\">'Rectangle'<\/span>,bboxes,<span class=\"string\">'Face'<\/span>);\r\nimshow(framergb);title(<span class=\"string\">'First Detected Face'<\/span>);\r\n<\/pre>\r\n&nbsp;\r\n\r\n<a href=\"https:\/\/blogs.mathworks.com\/pick\/files\/PickOfTheWeekPost_01.png\"><img decoding=\"async\" loading=\"lazy\" width=\"814\" height=\"575\" class=\"aligncenter size-full wp-image-6181\" src=\"https:\/\/blogs.mathworks.com\/pick\/files\/PickOfTheWeekPost_01.png\" alt=\"PickOfTheWeekPost_01\" \/><\/a><br> The next thing Dima's code does it adds a detection to the tracker object. This object does most of the heavy lifting and decided when to create a new track or if a detection is associated with an existing track. The tracker object in this File Exchange submission manages the new detections and the state of objects being tracked.\r\n<pre class=\"codeinput\">tracker.addDetections(frame, bboxes);\r\n<\/pre>\r\nAfter this the detection and tracking code is run in a loop till the video window is closed. Note that the detector is run only once every 10 frames to improve execution performance.\r\n<pre class=\"codeinput\"><span class=\"comment\">%And loop until the player is closed<\/span>\r\nframeNumber = 0;\r\nkeepRunning = true;\r\n<span class=\"keyword\">while<\/span> keepRunning\r\n\r\n    framergb = snapshot(vidObj);\r\n    frame = rgb2gray(framergb);\r\n\r\n    <span class=\"keyword\">if<\/span> mod(frameNumber, 10) == 0\r\n        <span class=\"comment\">%(Re)detect faces.<\/span>\r\n        <span class=\"comment\">%<\/span>\r\n        <span class=\"comment\">% NOTE: face detection is more expensive than imresize; we can<\/span>\r\n        <span class=\"comment\">% speed up the implementation by reacquiring faces using a<\/span>\r\n        <span class=\"comment\">% downsampled frame:<\/span>\r\n        <span class=\"comment\">% bboxes = faceDetector.step(frame);<\/span>\r\n        bboxes = 2 * faceDetector.step(imresize(frame, 0.5));\r\n        <span class=\"keyword\">if<\/span> ~isempty(bboxes)\r\n            tracker.addDetections(frame, bboxes);\r\n        <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">else<\/span>\r\n        <span class=\"comment\">%Track faces<\/span>\r\n        tracker.track(frame);\r\n    <span class=\"keyword\">end<\/span>\r\n\r\n    <span class=\"comment\">%Display bounding boxes and tracked points.<\/span>\r\n    displayFrame = insertObjectAnnotation(framergb, <span class=\"string\">'rectangle'<\/span>,<span class=\"keyword\">...<\/span>\r\n        tracker.Bboxes, tracker.BoxIds);\r\n    displayFrame = insertMarker(displayFrame, tracker.Points);\r\n    videoPlayer.step(displayFrame);\r\n\r\n    frameNumber = frameNumber + 1;\r\n    keepRunning = isOpen(videoPlayer);\r\n<span class=\"keyword\">end<\/span>\r\n\r\n<span class=\"comment\">%Clean up<\/span>\r\nrelease(videoPlayer);\r\n<\/pre>\r\nThis is what it looks like when I run the loop above.\r\n<br>\r\n<video controls=\"controls\" width=\"600\" height=\"400\"><source src=\"https:\/\/blogs.mathworks.com\/pick\/files\/POTW.mp4\" type=\"video\/mp4\" \/><\/video>\r\n<br>\r\nFinally, I modified Dima's code to solve by problem simply by replacing the object detector used with a model used to detect pedestrians by changing this code. The detector models to locate faces and pedestrians are both part of the <a href=\"https:\/\/www.mathworks.com\/products\/computer-vision\/\">Computer Vision System Toolbox<\/a>.\r\n<pre class=\"codeinput\">faceDetector = vision.CascadeObjectDetector(); <span class=\"comment\">% Finds faces by default<\/span>\r\n\r\n<span class=\"comment\">% to this<\/span>\r\npedestrianDetector = vision.PeopleDetector;\r\n<\/pre>\r\nIf you are working on a project that involves detecting and tracking objects in images and video, I'd highly recommend trying out this pick.\r\n<p class=\"footer\"><a href=\"https:\/\/www.mathworks.com\/products\/matlab\/\">Published with MATLAB\u00ae R2015a<\/a><\/p>","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img decoding=\"async\"  class=\"img-responsive\" src=\"https:\/\/blogs.mathworks.com\/pick\/files\/PickOfTheWeekPost_01.png\" onError=\"this.style.display ='none';\" \/><\/div><p>\r\nAvi's pick of the week is Detect and Track Multiple Faces by Dima Lisin.\r\n\r\nOne of the projects I was working on recently required the detection and tracking of multiple objects (pedestrians in my... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/pick\/2015\/09\/11\/detect-and-track-multiple-faces\/\">read more >><\/a><\/p>","protected":false},"author":132,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[16],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/6177"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/users\/132"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/comments?post=6177"}],"version-history":[{"count":15,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/6177\/revisions"}],"predecessor-version":[{"id":6196,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/posts\/6177\/revisions\/6196"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/media?parent=6177"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/categories?post=6177"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/pick\/wp-json\/wp\/v2\/tags?post=6177"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}