In this tutorial, we will learn about Face API and create a simple ASP.Net MVC application to search similar face from collection of face by using Face API.
Contents already Discussed:
- What is Cognitive Services?
- What is Face API?
- Sign Up for Face API
- Create ASP.Net MVC Sample Application
- Add AngularJS
- Install & Configure the Face API
Please follow the below link to get all those questions in my previous post: https://shashangka.com/2017/01/08/face-api-using-asp-net-mvc
Contents to Focused:
- Upload Multiple Candidate Face
- List Detected Faces
- Query Face
- Summary
Open existing sample application> Right Click > Controller > Add Controller > Controller > FaceSimilarController
MVC Controller: This is where we are performing our main operation. First of all get FaceServiceKey Value from web.config by ConfigurationManager.AppSettings.
private static string ServiceKey = ConfigurationManager.AppSettings[“FaceServiceKey”];
Here in MVC Controller we have two main method to performing the face detection operation. One is HttpPost method, which is using for uploading the image file to folder and the other one is HttpGet method is using to get uploaded image and detecting faces by calling API Service.
Both methods are getting called from client script while uploading image to detect faces. Let’s get explained in steps.
Multiple Face Upload: This method is responsible for uploading multiple face image.
[HttpPost] public JsonResult SaveCandidateFiles() { //Get Requested File Collection //Create New Folder if not Exist //Clear Existing File in Folder //Create Instance of Service Client by passing Servicekey as parameter in constructor //Create & Save Cropped Detected Faces }
Face Detection: This method is responsible for detecting the faces from uploaded images.
[HttpGet] public async TaskGetDetectedFaces() { //Get Files in Directory //Create FaceList //Add Face to FaceList }
Find Similar Faces: This method is responsible for find similar faces from facelist.
[HttpPost] public async TaskFindSimilar() { //Upload Face to Search //Find similar faces for each face //Update find similar results collection for rendering }
Finally Full MVC Controller:
public class FaceSimilarController : Controller { private static string ServiceKey = ConfigurationManager.AppSettings["FaceServiceKey"]; private static string directory = "../UploadedFiles"; private static string _faceListName = string.Empty; private static ObservableCollection_facesCollection = new ObservableCollection (); private static ObservableCollection _findSimilarCollection = new ObservableCollection (); public ObservableCollection FacesCollection { get { return _facesCollection; } } public ObservableCollection FindSimilarCollection { get { return _findSimilarCollection; } } // GET: FaceSimilar public ActionResult Index() { return View(); } [HttpPost] public async Task SaveCandidateFiles() { string message = string.Empty, fileName = string.Empty, actualFileName = string.Empty; bool flag = false; //Requested File Collection HttpFileCollection fileRequested = System.Web.HttpContext.Current.Request.Files; if (fileRequested != null) { //Create New Folder CreateDirectory(); //Clear Existing File in Folder ClearDirectory(); for (int i = 0; i < fileRequested.Count; i++) { var file = Request.Files[i]; actualFileName = file.FileName; fileName = Guid.NewGuid() + Path.GetExtension(file.FileName); int size = file.ContentLength; string FullImgPath = Path.Combine(Server.MapPath(directory), fileName); try { file.SaveAs(FullImgPath); message = "File uploaded successfully"; flag = true; if (FullImgPath != "") { using (var fStream = System.IO.File.OpenRead(FullImgPath)) { // User picked one image var imageInfo = UIHelper.GetImageInfoForRendering(FullImgPath); // Create Instance of Service Client by passing Servicekey as parameter in constructor var faceServiceClient = new FaceServiceClient(ServiceKey); Face[] faces = await faceServiceClient.DetectAsync(fStream, true, true, new FaceAttributeType[] { FaceAttributeType.Gender, FaceAttributeType.Age, FaceAttributeType.Smile, FaceAttributeType.Glasses }); if (faces.Count() > 0) { Bitmap CroppedFace = null; foreach (var face in faces) { //Create & Save Cropped Images var croppedImg = Convert.ToString(Guid.NewGuid()) + ".jpeg" as string; var croppedImgPath = directory + '\\' + croppedImg as string; var croppedImgFullPath = Server.MapPath(directory) + '\\' + croppedImg as string; CroppedFace = CropBitmap( (Bitmap)Image.FromFile(FullImgPath), face.FaceRectangle.Left, face.FaceRectangle.Top, face.FaceRectangle.Width, face.FaceRectangle.Height); CroppedFace.Save(croppedImgFullPath, ImageFormat.Jpeg); if (CroppedFace != null) ((IDisposable)CroppedFace).Dispose(); } //Clear Query File DeleteFile(FullImgPath); } } } } catch (Exception) { message = "File upload failed! Please try again"; } } } return new JsonResult { Data = new { Message = message, Status = flag } }; } [HttpGet] public async Task GetCandidateFiles() { string message = string.Empty; var faceServiceClient = new FaceServiceClient(ServiceKey); FacesCollection.Clear(); DirectoryInfo dir = new DirectoryInfo(Path.Combine(Server.MapPath(directory))); FileInfo[] files = null; files = dir.GetFiles().OrderBy(p => p.CreationTime).ToArray(); if (files.Count() > 0) { _faceListName = Guid.NewGuid().ToString(); await faceServiceClient.CreateFaceListAsync(_faceListName, _faceListName, "face list for sample"); foreach (var item in files) { var imgPath = Server.MapPath(directory) + '\\' + item.Name as string; try { using (var fStream = System.IO.File.OpenRead(imgPath)) { var faces = await faceServiceClient.AddFaceToFaceListAsync(_faceListName, fStream); FacesCollection.Add(new vmFace { ImagePath = imgPath, FileName = item.Name, FilePath = directory + '\\' + item.Name, FaceId = Convert.ToString(faces.PersistedFaceId) }); } } catch (FaceAPIException fe) { //do exception work message = fe.ToString(); } } } else { message = "No files to Detect!! Please Upload Files"; } return new JsonResult { Data = new { Message = message, FacesCollection = FacesCollection }, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; } [HttpPost] public async Task FindSimilar() { string message = string.Empty, fileName = string.Empty, actualFileName = string.Empty; bool flag = false; var faceServiceClient = new FaceServiceClient(ServiceKey); FindSimilarCollection.Clear(); //Requested File Collection HttpFileCollection fileRequested = System.Web.HttpContext.Current.Request.Files; if (fileRequested != null) { for (int i = 0; i < fileRequested.Count; i++) { var file = Request.Files[i]; actualFileName = file.FileName; fileName = Guid.NewGuid() + Path.GetExtension(file.FileName); int size = file.ContentLength; try { file.SaveAs(Path.Combine(Server.MapPath(directory), fileName)); var imgPath = Server.MapPath(directory) + '/' + fileName as string; using (var fStream = System.IO.File.OpenRead(imgPath)) { var faces = await faceServiceClient.DetectAsync(fStream); //Find similar faces for each face foreach (var f in faces) { var faceId = f.FaceId; try { //Call find similar REST API, the result contains all the face ids which similar to the query face const int requestCandidatesCount = 10; var result = await faceServiceClient.FindSimilarAsync(faceId, _faceListName, requestCandidatesCount); var findResult = new vmFindSimilarResult(); findResult.Faces = new ObservableCollection (); findResult.QueryFace = new vmFace() { ImagePath = imgPath, FileName = fileName, FilePath = directory + '/' + fileName, Top = f.FaceRectangle.Top, Left = f.FaceRectangle.Left, Width = f.FaceRectangle.Width, Height = f.FaceRectangle.Height, FaceId = faceId.ToString(), }; //Update find similar results collection for rendering foreach (var fr in result) { findResult.Faces.Add(FacesCollection.First(ff => ff.FaceId == fr.PersistedFaceId.ToString())); } //Update UI FindSimilarCollection.Add(findResult); message = Convert.ToString("Total " + findResult.Faces.Count() + " faces are detected."); flag = true; } catch (FaceAPIException fex) { message = fex.ErrorMessage; } } } } catch (Exception ex) { ex.ToString(); } } } return new JsonResult { Data = new { Message = message, SimilarFace = FindSimilarCollection, Status = flag } }; } public Bitmap CropBitmap(Bitmap bitmap, int cropX, int cropY, int cropWidth, int cropHeight) { Rectangle rect = new Rectangle(cropX, cropY, cropWidth, cropHeight); Bitmap cropped = bitmap.Clone(rect, bitmap.PixelFormat); return cropped; } public void CreateDirectory() { bool exists = System.IO.Directory.Exists(Server.MapPath(directory)); if (!exists) { try { Directory.CreateDirectory(Server.MapPath(directory)); } catch (Exception ex) { ex.ToString(); } } } public void ClearDirectory() { DirectoryInfo dir = new DirectoryInfo(Path.Combine(Server.MapPath(directory))); var files = dir.GetFiles(); if (files.Length > 0) { try { foreach (FileInfo fi in dir.GetFiles()) { GC.Collect(); GC.WaitForPendingFinalizers(); fi.Delete(); } } catch (Exception ex) { ex.ToString(); } } } public void DeleteFile(string FullImgPath) { if (FullImgPath != "") { try { //Clear Query File if ((System.IO.File.Exists(FullImgPath))) { GC.Collect(); GC.WaitForPendingFinalizers(); System.IO.File.Delete(FullImgPath); } } catch (Exception ex) { ex.ToString(); } } } }
MVC View:
@{ ViewBag.Title = "Find Face Similar"; }NgScript{ }{{Title}}
{{uplMessage}}
Select Multiple Candidate Face
Select Query Face
Face Collection {{resultFaceMessage}}
{{faceMessage}}
No face found!! {{facefinderMessage}}
Result
{{resultMessage}}
No similar face found!!
Angular Controller:
angular.module('myFaceApp', []) .controller('faceSimilarCtrl', function ($scope, FileUploadService) { $scope.Title = 'Microsoft FaceAPI - Find Face Similar'; $scope.resultMessage = 'No result found!!'; $scope.SelectedFileForUpload = null; $scope.UploadedFiles = []; $scope.SimilarFace = []; //File Select & Save $scope.selectCandidateFileforUpload = function (file) { $scope.SelectedFileForUpload = file; $scope.loaderMoreupl = true; $scope.uplMessage = 'Uploading, please wait....!'; $scope.result = "color-red"; //Save File var uploaderUrl = "/FaceSimilar/SaveCandidateFiles"; var fileSave = FileUploadService.UploadFile($scope.SelectedFileForUpload, uploaderUrl); fileSave.then(function (response) { if (response.data.Status) { $scope.GetCandidateFile(); angular.forEach(angular.element("input[type='file']"), function (inputElem) { angular.element(inputElem).val(null); }); $scope.f1.$setPristine(); //$scope.uplMessage = response.data.Message; $scope.loaderMoreupl = false; } }, function (error) { console.warn("Error: " + error); }); } $scope.GetCandidateFile = function () { $scope.loaderMore = true; $scope.faceMessage = 'Preparing, please wait....!'; $scope.result = "color-red"; var fileUrl = "/FaceSimilar/GetCandidateFiles"; var fileView = FileUploadService.GetUploadedFile(fileUrl); fileView.then(function (response) { $scope.UploadedFiles = response.data.FacesCollection; $scope.resultFaceMessage = response.data.Message; $scope.loaderMore = false; }, function (error) { console.warn("Error: " + error); }); }; $scope.selectFileforFindSimilar = function (file) { $scope.SelectedFileForUpload = file; $scope.loaderMorefacefinder = true; $scope.facefinderMessage = 'Preparing, detecting faces, please wait....!'; $scope.result = "color-red"; //Find Similar Face var uploaderUrl = "/FaceSimilar/FindSimilar"; var fileSave = FileUploadService.UploadFile($scope.SelectedFileForUpload, uploaderUrl); fileSave.then(function (response) { if (response.data.Status) { $scope.QueryFace = response.data.SimilarFace[0].QueryFace.FilePath; $scope.SimilarFace = response.data.SimilarFace[0].Faces; angular.forEach(angular.element("input[type='file']"), function (inputElem) { angular.element(inputElem).val(null); }); $scope.f2.$setPristine(); $scope.resultMessage = response.data.Message; $scope.loaderMoreupl = false; } }, function (error) { console.warn("Error: " + error); }); } }) .factory('FileUploadService', function ($http, $q) { var fact = {}; fact.UploadFile = function (files, uploaderUrl) { var formData = new FormData(); angular.forEach(files, function (f, i) { formData.append("file", files[i]); }); var request = $http({ method: "post", url: uploaderUrl, data: formData, withCredentials: true, headers: { 'Content-Type': undefined }, transformRequest: angular.identity }); return request; } fact.GetUploadedFile = function (fileUrl) { return $http.get(fileUrl); } return fact; })
Summary: You have just seen how to call Face API to detect & find faces in FaceList. Hope this will help to make application more smart and intelligent.
References:
says:
You didn’t discuss the changes you should have for the models?
Where did you get vmFindSimilarResult?
Ali Hassan says:
vmFindSimilarResult() sir i cannot manage the defination of this class plz u provide the code of this class ???????
i am so confuse ..!!!!