/// <summary> /// Pick the root person database folder, to minimum the data preparation logic, the folder should be under following construction /// Each person's image should be put into one folder named as the person's name /// All person's image folder should be put directly under the root person database folder /// </summary> /// <param name="sender">Event sender</param> /// <param name="e">Event argument</param> private async void FolderPicker_Click(object sender, RoutedEventArgs e) { bool groupExists = false; MainWindow mainWindow = Window.GetWindow(this) as MainWindow; string subscriptionKey = mainWindow._scenariosControl.SubscriptionKey; var faceServiceClient = new FaceServiceClient(subscriptionKey); // Test whether the group already exists try { MainWindow.Log("Request: Group {0} will be used for build person database. Checking whether group exists.", GroupName); await faceServiceClient.GetPersonGroupAsync(GroupName); groupExists = true; MainWindow.Log("Response: Group {0} exists.", GroupName); } catch (FaceAPIException ex) { if (ex.ErrorCode != "PersonGroupNotFound") { MainWindow.Log("Response: {0}. {1}", ex.ErrorCode, ex.ErrorMessage); return; } else { MainWindow.Log("Response: Group {0} does not exist before.", GroupName); } } if (groupExists) { var cleanGroup = System.Windows.MessageBox.Show(string.Format("Requires a clean up for group \"{0}\" before setup new person database. Click OK to proceed, group \"{0}\" will be fully cleaned up.", GroupName), "Warning", MessageBoxButton.OKCancel); if (cleanGroup == MessageBoxResult.OK) { await faceServiceClient.DeletePersonGroupAsync(GroupName); } else { return; } } // Show folder picker System.Windows.Forms.FolderBrowserDialog dlg = new System.Windows.Forms.FolderBrowserDialog(); var result = dlg.ShowDialog(); // Set the suggestion count is intent to minimum the data preparation step only, // it's not corresponding to service side constraint const int SuggestionCount = 15; if (result == System.Windows.Forms.DialogResult.OK) { // User picked a root person database folder // Clear person database Persons.Clear(); TargetFaces.Clear(); SelectedFile = null; // Call create person group REST API // Create person group API call will failed if group with the same name already exists MainWindow.Log("Request: Creating group \"{0}\"", GroupName); try { await faceServiceClient.CreatePersonGroupAsync(GroupName, GroupName); MainWindow.Log("Response: Success. Group \"{0}\" created", GroupName); } catch (FaceAPIException ex) { MainWindow.Log("Response: {0}. {1}", ex.ErrorCode, ex.ErrorMessage); return; } int processCount = 0; bool forceContinue = false; MainWindow.Log("Request: Preparing faces for identification, detecting faces in chosen folder."); // Enumerate top level directories, each directory contains one person's images foreach (var dir in System.IO.Directory.EnumerateDirectories(dlg.SelectedPath)) { var tasks = new List<Task>(); var tag = System.IO.Path.GetFileName(dir); Person p = new Person(); p.PersonName = tag; var faces = new ObservableCollection<Face>(); p.Faces = faces; // Call create person REST API, the new create person id will be returned MainWindow.Log("Request: Creating person \"{0}\"", p.PersonName); p.PersonId = (await faceServiceClient.CreatePersonAsync(GroupName, p.PersonName)).PersonId.ToString(); MainWindow.Log("Response: Success. Person \"{0}\" (PersonID:{1}) created", p.PersonName, p.PersonId); // Enumerate images under the person folder, call detection foreach (var img in System.IO.Directory.EnumerateFiles(dir, "*.jpg", System.IO.SearchOption.AllDirectories)) { tasks.Add(Task.Factory.StartNew( async (obj) => { var imgPath = obj as string; using (var fStream = File.OpenRead(imgPath)) { try { // Update person faces on server side var persistFace = await faceServiceClient.AddPersonFaceAsync(GroupName, Guid.Parse(p.PersonId), fStream, imgPath); return new Tuple<string, ClientContract.AddPersistedFaceResult>(imgPath, persistFace); } catch (FaceAPIException) { // Here we simply ignore all detection failure in this sample // You may handle these exceptions by check the Error.Error.Code and Error.Message property for ClientException object return new Tuple<string, ClientContract.AddPersistedFaceResult>(imgPath, null); } } }, img).Unwrap().ContinueWith((detectTask) => { // Update detected faces for rendering var detectionResult = detectTask.Result; if (detectionResult == null || detectionResult.Item2 == null) { return; } this.Dispatcher.Invoke( new Action<ObservableCollection<Face>, string, ClientContract.AddPersistedFaceResult>(UIHelper.UpdateFace), faces, detectionResult.Item1, detectionResult.Item2); })); if (processCount >= SuggestionCount && !forceContinue) { var continueProcess = System.Windows.Forms.MessageBox.Show("The images loaded have reached the recommended count, may take long time if proceed. Would you like to continue to load images?", "Warning", System.Windows.Forms.MessageBoxButtons.YesNo); if (continueProcess == System.Windows.Forms.DialogResult.Yes) { forceContinue = true; } else { break; } } } Persons.Add(p); await Task.WhenAll(tasks); } MainWindow.Log("Response: Success. Total {0} faces are detected.", Persons.Sum(p => p.Faces.Count)); try { // Start train person group MainWindow.Log("Request: Training group \"{0}\"", GroupName); await faceServiceClient.TrainPersonGroupAsync(GroupName); // Wait until train completed while (true) { await Task.Delay(1000); var status = await faceServiceClient.GetPersonGroupTrainingStatusAsync(GroupName); MainWindow.Log("Response: {0}. Group \"{1}\" training process is {2}", "Success", GroupName, status.Status); if (status.Status != Contract.Status.Running) { break; } } } catch (FaceAPIException ex) { MainWindow.Log("Response: {0}. {1}", ex.ErrorCode, ex.ErrorMessage); } } }
private void CreatePersonGroup(List <Contact> lstContacts) { try { using (var faceServiceClient = new FaceServiceClient(this.strSubscriptionKey, this.strEndpoint)) { bool isGroupExists = CheckIfGroupExists(); if (!isGroupExists) { Task taskCreatePersonGroup = Task.Run(async() => await faceServiceClient.CreatePersonGroupAsync(this.PersonGroupId, "Dynamics 365 Contacts")); } lstContacts.ForEach(contact => { Task <CreatePersonResult> taskCreatePerson = Task.Run(async() => await faceServiceClient.CreatePersonAsync( // Id of the PersonGroup that the person belonged to this.PersonGroupId, contact.FullName, contact.Id)); while (!taskCreatePerson.IsCompleted) { taskCreatePerson.Wait(); } CreatePersonResult person = taskCreatePerson.Result as CreatePersonResult; using (Stream stream = new MemoryStream(contact.ImageBytes)) { Task <AddPersistedFaceResult> taskPersisted = Task.Run(async() => await faceServiceClient.AddPersonFaceAsync(PersonGroupId, person.PersonId, stream)); while (!taskPersisted.IsCompleted) { taskPersisted.Wait(); } AddPersistedFaceResult persistedFaces = taskPersisted.Result as AddPersistedFaceResult; Persons.Add(new Person() { PersonName = contact.FullName, PersonId = person.PersonId.ToString(), PersistedFaceId = persistedFaces.PersistedFaceId.ToString() }); } }); Task taskTrainPerson = Task.Run(async() => await faceServiceClient.TrainPersonGroupAsync(this.PersonGroupId)); while (!taskTrainPerson.IsCompleted) { taskTrainPerson.Wait(); } while (true) { try { Task <TrainingStatus> taskTrainingStatus = Task.Run(async() => await faceServiceClient.GetPersonGroupTrainingStatusAsync(this.PersonGroupId)); if (taskTrainingStatus.Result.Status != Status.Running) { break; } else { taskTrainingStatus.Wait(); } } catch (FaceAPIException fEx) { continue; } } } } catch (Exception ex) { MessageBox.Show(ex.Message); } }