using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; using System.IO; using OpenCvSharp; using System.Runtime.InteropServices; using System.Diagnostics; using System.Xml.Serialization; namespace MathPirate.AlternativeInputDevices.FacialRecognition { public class Recognizer { public Size FaceSize = new Size(50, 50); public Dictionary IdentityMap { get; set; } public int EigenCount { get; set; } public int TrainingCount { get; set; } public CvMat EigenvalueMatrix { get; set; } public CvMat ProjectionMatrix { get; set; } public IplImage AverageImage { get; set; } public IplImage[] EigenImages { get; set; } public IplImage[] TrainingImages { get; set; } public void Train(string sourcePath) { LoadTrainingImages(sourcePath); if (TrainingImages.Length == 0) { return; } CalculatePrincipalComponents(); ProjectFaces(); } protected void LoadTrainingImages(string path) { string[] identityPaths = Directory.GetDirectories(path); List trainingImages = new List(); IdentityMap = new Dictionary(); int trainingImageIndex = 0; Debug.WriteLine("Loading Images"); foreach (string identityPath in identityPaths) { string[] trainingImagePaths = Directory.GetFiles(identityPath, "*.jpg"); if (trainingImagePaths == null || trainingImagePaths.Length == 0) { continue; } string identity = Path.GetFileName(identityPath); foreach (string trainingImagePath in trainingImagePaths) { IplImage fullSizeFace = new IplImage(trainingImagePath); IplImage thumbnailGrayFace = NormalizeFace(fullSizeFace); trainingImages.Add(thumbnailGrayFace); fullSizeFace.Dispose(); IdentityMap[trainingImageIndex] = identity; trainingImageIndex++; } Debug.WriteLine("Images Loaded From: " + identityPath); //Temporary break to speed things up... //if (trainingImageIndex > 1000) { break; } } Debug.WriteLine("All Images Loaded"); TrainingImages = trainingImages.ToArray(); TrainingCount = TrainingImages.Length; } protected void CalculatePrincipalComponents() { Debug.WriteLine("CalculatePrincipalComponents"); EigenCount = TrainingImages.Length - 1; float[] eigenvalueArray = new float[EigenCount]; AverageImage = new IplImage(FaceSize.Width, FaceSize.Height, BitDepth.F32, 1); CvTermCriteria termCriteria = new CvTermCriteria(CriteriaType.Iteration, EigenCount, 1); EigenImages = new IplImage[EigenCount]; for (int i = 0; i < EigenCount; i++) { EigenImages[i] = new IplImage(FaceSize.Width, FaceSize.Height, BitDepth.F32, 1); } Debug.WriteLine("CalcEigenObjects"); Cv.CalcEigenObjects(TrainingImages, EigenImages, 0, termCriteria, AverageImage, eigenvalueArray); Debug.WriteLine("CalcEigenObjects Complete"); EigenvalueMatrix = new CvMat(1, EigenCount, MatrixType.F32C1, eigenvalueArray); } protected void ProjectFaces() { Debug.WriteLine("Project Faces"); List projectionList = new List();; for (int i = 0; i < TrainingImages.Length; i++) { float[] projectionArray = new float[EigenCount]; try { Cv.EigenDecomposite(TrainingImages[i], EigenImages, AverageImage, projectionArray); } catch (Exception ex) { Console.WriteLine(ex.Message); } projectionList.AddRange(projectionArray); Console.Write("."); } ProjectionMatrix = new CvMat(TrainingImages.Length, EigenCount, MatrixType.F32C1, projectionList.ToArray()); Debug.WriteLine("Decomposition Complete"); } protected IplImage NormalizeFace(IplImage input) { IplImage thumbnailColorFace = new IplImage(FaceSize.Width, FaceSize.Height, input.Depth, input.ElemChannels); input.Resize(thumbnailColorFace, Interpolation.NearestNeighbor); IplImage thumbnailGrayFace = new IplImage(FaceSize.Width, FaceSize.Height, BitDepth.U8, 1); Cv.CvtColor(thumbnailColorFace, thumbnailGrayFace, ColorConversion.RgbToGray); thumbnailColorFace.Dispose(); return thumbnailGrayFace; } public void Save(string savePath) { CvFileStorage saveFile = new CvFileStorage(savePath, null, FileStorageMode.Write); saveFile.WriteInt("EigenCount", EigenCount); saveFile.WriteInt("TrainingCount", TrainingCount); saveFile.Write("EigenvalueMatrix", EigenvalueMatrix); saveFile.Write("ProjectionMatrix", ProjectionMatrix); saveFile.Write("AverageImage", AverageImage); for (int eigenIndex = 0; eigenIndex < EigenImages.Length; eigenIndex++) { saveFile.Write("EigenImage_" + eigenIndex, EigenImages[eigenIndex]); } for (int identityIndex = 0; identityIndex < TrainingCount; identityIndex++) { byte[] stringBytes = Encoding.ASCII.GetBytes(IdentityMap[identityIndex]); CvMat charArr = new CvMat(1, stringBytes.Length, MatrixType.U8C1, stringBytes); saveFile.Write("Identity_" + identityIndex, charArr); } saveFile.Dispose(); } public void Load(string loadPath) { CvFileStorage loadFile = new CvFileStorage(loadPath, null, FileStorageMode.Read); EigenCount = loadFile.ReadIntByName(null, "EigenCount", 0); TrainingCount = loadFile.ReadIntByName(null, "TrainingCount", 0); EigenvalueMatrix = loadFile.ReadByName(null, "EigenvalueMatrix"); ProjectionMatrix = loadFile.ReadByName(null, "ProjectionMatrix"); AverageImage = loadFile.ReadByName(null, "AverageImage"); EigenImages = new IplImage[EigenCount]; for (int eigenIndex = 0; eigenIndex < EigenImages.Length; eigenIndex++) { EigenImages[eigenIndex] = loadFile.ReadByName(null, "EigenImage_" + eigenIndex); } IdentityMap = new Dictionary(); for (int identityIndex = 0; identityIndex < TrainingCount; identityIndex++) { CvMat charArr = loadFile.ReadByName(null, "Identity_" + identityIndex); byte[] charBytes = new byte[charArr.Cols]; for(int i = 0; i