/// <summary>
        ///
        /// </summary>
        /// <param name="imageStream"></param>
        /// <param name="faceId"></param>
        /// <param name="faceRectangle"></param>
        /// <param name="complexScenario"> - Whether we are identifying face hard way - means whether we need to use db or not</param>
        /// <returns></returns>
        public static async Task <Tuple <SimilarPersistedFace, string> > FindSimilarPersistedFaceAsync(Stream imageStream, Guid faceId, FaceRectangle faceRectangle)
        {
            if (faceLists == null)
            {
                await Initialize();
            }

            Tuple <SimilarPersistedFace, string> bestMatch = null;

            var faceListId = faceLists.FirstOrDefault().Key;

            //Delete for testing purposes
            //await FaceServiceHelper.DeleteFaceListAsync(faceListId);
            try
            {
                SimilarPersistedFace similarFace = null;
                if (faceListId != null)
                {
                    try
                    {
                        similarFace = (await FaceServiceHelper.FindSimilarAsync(faceId, faceListId))?.FirstOrDefault();
                    }
                    catch (Exception e)
                    {
                        if ((e as FaceAPIException).ErrorCode == "FaceListNotReady")
                        {
                            // do nothing, list is empty but we continue
                        }
                    }
                }
                if (similarFace != null)
                {
                    if (bestMatch != null)
                    {
                        // We already found a match for this face in another list. Replace the previous one if the new confidence is higher.
                        if (bestMatch.Item1.Confidence < similarFace.Confidence)
                        {
                            bestMatch = new Tuple <SimilarPersistedFace, string>(similarFace, faceListId);
                        }
                    }
                    else
                    {
                        bestMatch = new Tuple <SimilarPersistedFace, string>(similarFace, faceListId);
                    }
                }
                else
                {
                    // If we are here we didnt' find a match, so let's add the face to the first FaceList that we can add it to. We
                    // might create a new list if none exist, and if all lists are full we will delete the oldest face list (based on when we
                    // last matched anything on it) so that we can add the new one.

                    if (!faceLists.Any())
                    {
                        // We don't have any FaceLists yet. Create one
                        newFaceListId = Guid.NewGuid().ToString();
                        // await FaceServiceHelper.CreateFaceListAsync(newFaceListId, "ManagedFaceList", FaceListsUserDataFilter);
                        //We are not using filters
                        await FaceServiceHelper.CreateFaceListAsync(newFaceListId, "ManagedFaceList");

                        faceLists.Add(newFaceListId, new FaceListInfo {
                            FaceListId = newFaceListId, LastMatchTimestamp = DateTime.Now
                        });
                    }

                    AddPersistedFaceResult addResult = null;

                    var faceList = faceLists.First();
                    if (faceList.Value.IsFull)
                    {
                        //It is here only for complex scenario where we use groups and lists mappings
                        try
                        {
                            DBSimilarFace faceToDelete = null;
                            using (var db = new KioskDBContext())
                            {
                                faceToDelete = db.SimilarFaces.OrderByDescending(sf => sf.PersonId).First();
                                db.SimilarFaces.Remove(faceToDelete);
                                await db.SaveChangesAsync();
                            }

                            await FaceServiceHelper.DeleteFaceFromFaceListAsync(faceList.Key, new Guid(faceToDelete.FaceId));
                        }
                        catch (Exception e)
                        {
                            Debug.WriteLine("No face to be deleted" + e.Message);
                        }
                    }

                    addResult = await FaceServiceHelper.AddFaceToFaceListAsync(faceList.Key, imageStream, faceRectangle);

                    if (addResult != null)
                    {
                        bestMatch = new Tuple <SimilarPersistedFace, string>(new SimilarPersistedFace {
                            Confidence = 1, PersistedFaceId = addResult.PersistedFaceId
                        }, null);
                    }
                }
            }
            catch (Exception e)
            {
                // Catch errors with individual face lists so we can continue looping through all lists. Maybe an answer will come from
                // another one.
                ErrorTrackingHelper.TrackException(e, "Face API FindSimilarAsync error");
            }

            return(bestMatch);
        }
Example #2
0
        private async Task CreatePrsonIfNoSimilarFaceExistsAsync(List <FaceSendInfo> facesInfo, Guid newPersonID, Face f)
        {
            //TODO return person result so we can change candidate if we are not going with the one selected

            //We try to find person also thru similar face api
            SimilarFaceMatch result = await GetSimilarFace(f);

            using (var db = new KioskDBContext())
            {
                //If we create new similar face, we create also new person
                if (result.isNew)
                {
                    //We create db where we map SimilarPersonID to PersonID, because those are different in cognitive services
                    var perResult = await CreatePerson(facesInfo, newPersonID, f);

                    db.SimilarFaces.Add(new DBSimilarFace()
                    {
                        CreatedAt = DateTime.Now, FaceId = result.SimilarPersistedFace.PersistedFaceId.ToString(), PersonId = perResult.ToString()
                    });
                    await db.SaveChangesAsync();
                }

                else
                {
                    string personId = "";
                    try
                    {
                        personId = db.SimilarFaces.Where(sf => sf.FaceId == result.SimilarPersistedFace.PersistedFaceId.ToString()).FirstOrDefault().PersonId;

                        var person = await FaceServiceHelper.GetPersonAsync(groupId, new Guid(personId));

                        //Fill new info
                        var fi = facesInfo.Where(fin => fin.faceId == f.FaceId.ToString()).FirstOrDefault();
                        fi.canid   = personId;
                        fi.canname = person.Name;
                        fi.canconf = result.SimilarPersistedFace.Confidence;

                        //We did not identified person thru person group and we needed to use silimar face api, so we add picture
                        await AddFaceToPerson(f, person, new Guid(personId));
                    }
                    catch (Exception)
                    {
                        //Person was not found due to old entry in local DB (Exception thrown by FaceApi GetPersonAsync) or face was created only in list when not using complex identification

                        //If person is only in list,  we need to create it also in person list
                        if (personId == "")
                        {
                            var perResult2 = await CreatePerson(facesInfo, newPersonID, f);

                            db.SimilarFaces.Add(new DBSimilarFace()
                            {
                                CreatedAt = DateTime.Now, FaceId = result.SimilarPersistedFace.PersistedFaceId.ToString(), PersonId = perResult2.ToString()
                            });
                            await db.SaveChangesAsync();
                        }

                        //We clean the old entry from DB and create new Person
                        var oldDbEntry = db.SimilarFaces.Where(sf => sf.FaceId == result.SimilarPersistedFace.PersistedFaceId.ToString()).FirstOrDefault();
                        var perResult  = await CreatePerson(facesInfo, newPersonID, f);

                        if (oldDbEntry != null)
                        {
                            db.SimilarFaces.Update(oldDbEntry);
                            oldDbEntry.FaceId   = result.SimilarPersistedFace.PersistedFaceId.ToString();
                            oldDbEntry.PersonId = perResult.ToString();
                        }
                        else
                        {
                            db.SimilarFaces.Add(new DBSimilarFace()
                            {
                                CreatedAt = DateTime.Now, FaceId = result.SimilarPersistedFace.PersistedFaceId.ToString(), PersonId = perResult.ToString()
                            });
                        }

                        await db.SaveChangesAsync();
                    }
                }
            }
        }