Face API Similar Face Searching Using ASP.NET MVC, AngularJS

Datetime:2017-04-19 05:17:25         Topic: AngularJS  ASP.NET MVC          Share        Original >>
Here to See The Original Article!!!

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: http://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 JsonResultSaveCandidateFiles()
{
  //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 Task<dynamic> GetDetectedFaces()
{
  //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 Task<dynamic> FindSimilar()
{
  //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<vmFace> _facesCollection = new ObservableCollection<vmFace>();
    private static ObservableCollection<vmFindSimilarResult> _findSimilarCollection = new ObservableCollection<vmFindSimilarResult>();
 
    public ObservableCollection<vmFace> FacesCollection
    {
        get
        {
            return _facesCollection;
        }
    }
    public ObservableCollection<vmFindSimilarResult> FindSimilarCollection
    {
        get
        {
            return _findSimilarCollection;
        }
    }
 
 
    // GET: FaceSimilar
    public ActionResultIndex()
    {
        return View();
    }
 
    [HttpPost]
    public async Task<JsonResult> SaveCandidateFiles()
    {
        string message = string.Empty, fileName = string.Empty, actualFileName = string.Empty; bool flag = false;
 
        //Requested File Collection
        HttpFileCollectionfileRequested = 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)
                            {
                                BitmapCroppedFace = null;
                                foreach (var facein faces)
                                {
                                    //Create & Save Cropped Images
                                    var croppedImg = Convert.ToString(Guid.NewGuid()) + ".jpeg" as string;
                                    var croppedImgPath = directory + '\\' + croppedImgas string;
                                    var croppedImgFullPath = Server.MapPath(directory) + '\\' + croppedImgas 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<dynamic> GetCandidateFiles()
    {
        string message = string.Empty;
        var faceServiceClient = new FaceServiceClient(ServiceKey);
        FacesCollection.Clear();
        DirectoryInfodir = 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 itemin files)
            {
                var imgPath = Server.MapPath(directory) + '\\' + item.Nameas 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 (FaceAPIExceptionfe)
                {
                    //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<dynamic> FindSimilar()
    {
        string message = string.Empty, fileName = string.Empty, actualFileName = string.Empty; bool flag = false;
        var faceServiceClient = new FaceServiceClient(ServiceKey);
        FindSimilarCollection.Clear();
 
        //Requested File Collection
        HttpFileCollectionfileRequested = 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) + '/' + fileNameas 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<vmFace>();
                                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 frin 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 (FaceAPIExceptionfex)
                            {
                                message = fex.ErrorMessage;
                            }
                        }
                    }
                }
                catch (Exceptionex)
                {
                    ex.ToString();
                }
            }
        }
        return new JsonResult
        {
            Data = new
            {
                Message = message,
                SimilarFace = FindSimilarCollection,
                Status = flag
            }
        };
    }
 
    public BitmapCropBitmap(Bitmapbitmap, int cropX, int cropY, int cropWidth, int cropHeight)
    {
        Rectanglerect = new Rectangle(cropX, cropY, cropWidth, cropHeight);
        Bitmapcropped = 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 (Exceptionex)
            {
                ex.ToString();
            }
        }
    }
 
    public void ClearDirectory()
    {
        DirectoryInfodir = new DirectoryInfo(Path.Combine(Server.MapPath(directory)));
        var files = dir.GetFiles();
        if (files.Length > 0)
        {
            try
            {
                foreach (FileInfofiin dir.GetFiles())
                {
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                    fi.Delete();
                }
            }
            catch (Exceptionex)
            {
                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 (Exceptionex)
            {
                ex.ToString();
            }
        }
    }
}

MVC View:

@{
    ViewBag.Title = "Find Face Similar";
}
 
<divng-controller="faceSimilarCtrl">
    <h3>{{Title}}</h3>
    <divclass="loadmore">
        <divng-show="loaderMoreupl" ng-class="result">
            <imgsrc="~/Content/ng-loader.gif"/>{{uplMessage}}
        </div>
    </div>
    <divclass="clearfix"></div>
    <tablestyle="width:100%">
        <tr>
            <th><h4>Select Multiple Candidate Face</h4></th>
            <th><h4>Select Query Face</h4></th>
        </tr>
        <tr>
            <tdstyle="width:60%" valign="top">
                <formnovalidate name="f1">
                    <inputtype="file" name="file" accept="image/*" multiple onchange="angular.element(this).scope().selectCandidateFileforUpload(this.files)" required/>
                </form>
                <divclass="clearfix"></div>
                <hr/>
                <h4>Face Collection {{resultFaceMessage}}</h4>
                <inputtype="submit" value="Reload Faces" ng-click="GetCandidateFile()" class="btn btn-success"/>
                <divclass="clearfix"></div>
                <divclass="loadmore">
                    <divng-show="loaderMore" ng-class="result">
                        <imgsrc="~/Content/ng-loader.gif"/>{{faceMessage}}
                    </div>
                </div>
                <hr/>
                <divng-repeat="item in UploadedFiles" class="pull-left">
                    <imgng-src="{{item.FilePath}}" width="100" class="media-list"/>
                </div>
                <divng-hide="UploadedFiles.length">No face found!!</div>
            </td>
            <tdstyle="width:40%" valign="top">
                <formnovalidate name="f2">
                    <inputtype="file" name="file" accept="image/*" onchange="angular.element(this).scope().selectFileforFindSimilar(this.files)" required/>
                </form>
                <divclass="clearfix"></div>
                <divclass="loadmore">
                    <divng-show="loaderMorefacefinder" ng-class="result">
                        <imgsrc="~/Content/ng-loader.gif"/>{{facefinderMessage}}
                    </div>
                </div>
                <hr/>
                <h4>Result</h4>
                <p>{{resultMessage}}</p>
                <divclass="clearfix"></div>
                <divclass="facePreview_thumb_big">
                    <imgng-src="{{QueryFace}}" width="200"/>
                </div>
                <hr/>
                <divng-repeat="item in SimilarFace" class="pull-left">
                    <imgng-src="{{item.FilePath}}" width="100" class="media-list"/>
                </div>
                <divng-hide="SimilarFace.length">No similar face found!!</div>
            </td>
        </tr>
    </table>
</div>
 
@section NgScript{
    <scriptsrc="~/ScriptsNg/FaceSimilarCtrl.js"></script>
}

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:








New