mirror of https://github.com/emgucv/emgucv.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
6.3 KiB
165 lines
6.3 KiB
//----------------------------------------------------------------------------
|
|
// Copyright (C) 2004-2021 by EMGU Corporation. All rights reserved.
|
|
//----------------------------------------------------------------------------
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Net;
|
|
using System.Threading.Tasks;
|
|
using Emgu.CV;
|
|
using Emgu.CV.Structure;
|
|
using Emgu.CV.Cuda;
|
|
using Emgu.CV.CvEnum;
|
|
using Emgu.Util;
|
|
|
|
namespace Emgu.CV.Models
|
|
{
|
|
/// <summary>
|
|
/// Face and eye detector using HaarCascade.
|
|
/// </summary>
|
|
public class CascadeFaceAndEyeDetector : DisposableObject, IProcessAndRenderModel
|
|
{
|
|
private CascadeClassifier _faceCascadeClassifier = null;
|
|
private CascadeClassifier _eyeCascadeClassifier = null;
|
|
|
|
/// <summary>
|
|
/// Detect faces and eyes region from the input image
|
|
/// </summary>
|
|
/// <param name="image">The input image.</param>
|
|
/// <param name="faces">The region of the faces.</param>
|
|
/// <param name="eyes">The region of the eyes.</param>
|
|
public void Detect(
|
|
IInputArray image,
|
|
List<Rectangle> faces,
|
|
List<Rectangle> eyes)
|
|
{
|
|
using (Mat gray = new Mat())
|
|
{
|
|
CvInvoke.CvtColor(image, gray, Emgu.CV.CvEnum.ColorConversion.Bgr2Gray);
|
|
|
|
//normalizes brightness and increases contrast of the image
|
|
CvInvoke.EqualizeHist(gray, gray);
|
|
|
|
//Detect the faces from the gray scale image and store the locations as rectangle
|
|
//The first dimensional is the channel
|
|
//The second dimension is the index of the rectangle in the specific channel
|
|
Rectangle[] facesDetected = _faceCascadeClassifier.DetectMultiScale(
|
|
gray,
|
|
1.1,
|
|
10,
|
|
new Size(20, 20));
|
|
|
|
faces.AddRange(facesDetected);
|
|
|
|
foreach (Rectangle f in facesDetected)
|
|
{
|
|
//Get the region of interest on the faces
|
|
using (Mat faceRegion = new Mat(gray, f))
|
|
{
|
|
Rectangle[] eyesDetected = _eyeCascadeClassifier.DetectMultiScale(
|
|
faceRegion,
|
|
1.1,
|
|
10,
|
|
new Size(20, 20));
|
|
|
|
foreach (Rectangle e in eyesDetected)
|
|
{
|
|
Rectangle eyeRect = e;
|
|
eyeRect.Offset(f.X, f.Y);
|
|
eyes.Add(eyeRect);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Download and initialize the face and eye cascade classifier detection model
|
|
/// </summary>
|
|
/// <param name="onDownloadProgressChanged">Call back method during download</param>
|
|
/// <param name="initOptions">Initialization options. None supported at the moment, any value passed will be ignored.</param>
|
|
/// <returns>Asyn task</returns>
|
|
public async Task Init(DownloadProgressChangedEventHandler onDownloadProgressChanged = null, Object initOptions = null)
|
|
{
|
|
if (_faceCascadeClassifier == null || _eyeCascadeClassifier == null)
|
|
{
|
|
FileDownloadManager downloadManager = new FileDownloadManager();
|
|
String url = "https://github.com/opencv/opencv/raw/4.2.0/data/haarcascades/";
|
|
downloadManager.AddFile(url + "/haarcascade_frontalface_default.xml", "haarcascade");
|
|
downloadManager.AddFile(url + "/haarcascade_eye.xml", "haarcascade");
|
|
|
|
downloadManager.OnDownloadProgressChanged += onDownloadProgressChanged;
|
|
|
|
await downloadManager.Download();
|
|
String faceFile = downloadManager.Files[0].LocalFile;
|
|
String eyeFile = downloadManager.Files[1].LocalFile;
|
|
_faceCascadeClassifier = new CascadeClassifier(faceFile);
|
|
_eyeCascadeClassifier = new CascadeClassifier(eyeFile);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Process the input image and render into the output image
|
|
/// </summary>
|
|
/// <param name="imageIn">The input image</param>
|
|
/// <param name="imageOut">The output image, can be the same as imageIn, in which case we will render directly into the input image</param>
|
|
/// <returns>The messages that we want to display.</returns>
|
|
public string ProcessAndRender(IInputArray imageIn, IInputOutputArray imageOut)
|
|
{
|
|
List<Rectangle> faces = new List<Rectangle>();
|
|
List<Rectangle> eyes = new List<Rectangle>();
|
|
|
|
Stopwatch watch = Stopwatch.StartNew();
|
|
Detect(imageIn, faces, eyes);
|
|
watch.Stop();
|
|
|
|
if (imageOut != imageIn)
|
|
{
|
|
using (InputArray iaImageIn = imageIn.GetInputArray())
|
|
{
|
|
iaImageIn.CopyTo(imageOut);
|
|
}
|
|
}
|
|
|
|
//Draw the faces in red
|
|
foreach (Rectangle rect in faces)
|
|
CvInvoke.Rectangle(imageOut, rect, new MCvScalar(0, 0, 255), 2);
|
|
|
|
//Draw the eyes in blue
|
|
foreach (Rectangle rect in eyes)
|
|
CvInvoke.Rectangle(imageOut, rect, new MCvScalar(255, 0, 0), 2);
|
|
|
|
return String.Format("Detected in {0} milliseconds.", watch.ElapsedMilliseconds);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clear and reset the model. Required Init function to be called again before calling ProcessAndRender.
|
|
/// </summary>
|
|
public void Clear()
|
|
{
|
|
if (_faceCascadeClassifier != null)
|
|
{
|
|
_faceCascadeClassifier.Dispose();
|
|
_faceCascadeClassifier = null;
|
|
}
|
|
|
|
if (_eyeCascadeClassifier != null)
|
|
{
|
|
_eyeCascadeClassifier.Dispose();
|
|
_eyeCascadeClassifier = null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Release the memory associated with this face and eye detector
|
|
/// </summary>
|
|
protected override void DisposeObject()
|
|
{
|
|
Clear();
|
|
}
|
|
}
|
|
}
|