Beispiel #1
0
        private static async Task <CognitiveIdentifyResponse.Candidate> identifyFace(Guid cognitiveFaceId, TraceWriter log)
        {
            if (cognitiveFaceId == Guid.Empty)
            {
                throw new ArgumentNullException(nameof(cognitiveFaceId));
            }

            try
            {
                var result = await FaceAPIClient.Call <CognitiveIdentifyResponse>(
                    $"/identify",
                    new
                {
                    personGroupId = Settings.FACE_API_GROUP_NAME,
                    faceIds       = new Guid[] { cognitiveFaceId },
                    maxNumOfCandidatesReturned = 1,
                    confidenceThreshold        = 0.7
                },
                    log);

                return(result
                       .FirstOrDefault()
                       ?.Candidates
                       .FirstOrDefault());
            }
            catch (InvalidOperationException ex)
            {
                log.Error("Failed while trying to identify (second phase) face", ex);
                return(null);
            }
        }
        public static async Task Run(
            [BlobTrigger("faces/{name}", Connection = Settings.STORAGE_CONN_NAME)] CloudBlockBlob inputImage,
            [ServiceBus("atmosphere-processed-images", AccessRights.Send, Connection = Settings.SB_CONN_NAME, EntityType = EntityType.Queue)] ICollector <string> outputQueue,
            TraceWriter log)
        {
            log.Info($"Blob trigger '{nameof(DetectFaces)}' with {inputImage.Name}");

            var result = await FaceAPIClient.Call <IdentifyResponse>(
                $"/detect?returnFaceAttributes=emotion",
                new { url = $"{Settings.IMAGES_ENDPOINT}/{Settings.CONTAINER_FACES}/{inputImage.Name}" },
                log);

            await inputImage.FetchAttributesAsync();

            if (result.Count == 0)
            {
                log.Info($"Didn't detect faces => image will be delete down the pipe");
                return;
            }

            outputQueue.Add((new ProcessedImage
            {
                ImageName = inputImage.Name,
                ClientId = Int32.Parse(inputImage.Metadata["clientId"]),
                Faces = result
                        .Select(r => new DetectedFace
                {
                    FaceId = r.FaceId,
                    FaceRectangle = r.FaceRectangle,
                    Scores = r.FaceAttributes.Emotion
                })
                        .ToArray()
            }).ToJson());
        }
Beispiel #3
0
        public static async Task Run([TimerTrigger("0 0 3 * * *")] TimerInfo myTimer, TraceWriter log)
        {
            log.Info($"Timer trigger '{nameof(StartTraining)}' at: {DateTime.Now}");

            var newTagsExists = (await getNewTagsCount(DateTimeOffset.UtcNow.AddHours(-24))) > 0;

            if (!newTagsExists)
            {
                log.Info($"No new faces were tagged => exiting");
                return;
            }
            var result = await FaceAPIClient.Call <dynamic>(
                $"/persongroups/{Settings.FACE_API_GROUP_NAME}/train",
                null,
                log);

            log.Info($"Received result from faces API {result.ToJson()}");
        }
        public static async Task Run(
            [ServiceBusTrigger("atmosphere-face-tagged", AccessRights.Listen, Connection = Settings.SB_CONN_NAME)] string message,
            [ServiceBus("atmosphere-face-cleanup", AccessRights.Send, Connection = Settings.SB_CONN_NAME, EntityType = EntityType.Queue)] ICollector <string> cleanupQueue,
            [ServiceBus("atmosphere-face-training-sent", AccessRights.Send, Connection = Settings.SB_CONN_NAME, EntityType = EntityType.Queue)] ICollector <string> trainingSentQueue,
            [ServiceBus("atmosphere-face-enrich-user", AccessRights.Send, Connection = Settings.SB_CONN_NAME, EntityType = EntityType.Queue)] ICollector <string> enrichQueue,
            TraceWriter log)
        {
            log.Info($"Queue trigger '{nameof(SendFaceForTraining)}' with message: {message}");
            var slackInput = message.FromJson <TaggingMessage>();

            // check if the slack message's votes got to the point that
            // * The required number of people taged face as same person => the image should be submitted to congetive service
            // * Not enough votes => wait for more
            // * Too many votes - edge case, only if two users voted simultaniously
            var votesForSamePerson = await getFaceTagsOnImageCount(slackInput.UserId, slackInput.FaceId);

            log.Info($"Votes for same person was {votesForSamePerson} while required is {REQUIRED_VOTES_FROM_DIFF_USERS}");
            if (votesForSamePerson < REQUIRED_VOTES_FROM_DIFF_USERS)
            {
                log.Info($"Not enough votes for face on image. Requires at least {REQUIRED_VOTES_FROM_DIFF_USERS} different user votes to vote for the same user.");
                return;
            }
            else if (votesForSamePerson > REQUIRED_VOTES_FROM_DIFF_USERS)
            {
                log.Info($"Voting alredy closed for the faceId {slackInput.FaceId}, meaning the image was already submitted.");
                return;
            }

            if (await getFaceTagsCount(slackInput.UserId) > MAX_IMAGES_PER_PERSON)
            {
                log.Info($"Reached limit of images per person. Maximum amount is {MAX_IMAGES_PER_PERSON}. This means no more training required for the person.");
                return;
            }

            // ensure mapping of our identifier of user - SlackId has a mapping to user identifier on Cognetive service
            var user = await getUsersMap(slackInput.UserId);

            if (user == null)
            {
                log.Info($"Creating mapping for slackId and cognitiveId");
                var faceApiMapping = await FaceAPIClient.Call <CreateUserResponse>(
                    $"/persongroups/{Settings.FACE_API_GROUP_NAME}/persons",
                    new { name = slackInput.UserId },
                    log);

                user = new UserMap
                {
                    UserId       = slackInput.UserId,
                    CognitiveUid = faceApiMapping.PersonId
                };
                await saveUsersMap(user);

                enrichQueue.Add(user.ToJson());
                log.Info($"Stored new user map {user.ToJson()}");
            }

            try
            {
                // image submitted only once to congetive when a required number of votes reached
                // once submitted we need to prevent any more voting on slack image
                await FaceAPIClient.Call <dynamic>(
                    $"/persongroups/{Settings.FACE_API_GROUP_NAME}/persons/{user.CognitiveUid}/persistedFaces",
                    new { url = $"{Settings.IMAGES_ENDPOINT}/{Settings.CONTAINER_RECTANGLES}/{slackInput.FaceId}.jpg" },
                    log);

                trainingSentQueue.Add(message);
            }
            catch (InvalidOperationException)
            {
                // something went wrong, probably with image itself (e.g. blured) close voting
                // and remove all taggin info perfored till now
                log.Info($"Going to cleanup tagging for this faceId");
                cleanupQueue.Add(message);
            }
        }