private async Task <List <FaceImage> > DownloadPersonFaces(Microsoft.ProjectOxford.Face.Contract.Person groupPerson) { var imgs = new List <FaceImage>(); var fimages = new List <FaceImage>(); foreach (var faceId in groupPerson.PersistedFaceIds) { var fm = new FaceImage(await Synchron.Instance.GetFace(faceId)) { MicrosoftId = faceId }; imgs.Add(fm); } //foreach (var face in groupPerson.PersistedFaceIds.Select(async x => //{ // var fm = new FaceImage(await Synchron.Instance.GetFace(x)); // fm.MicrosoftId = x; // return fm; //}).ToList()) // imgs.Add(await face); return(imgs); }
/// <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; // Test whether the group already exists try { Output = Output.AppendLine(string.Format("Request: Group {0} will be used for build person database. Checking whether group exists.", GroupName)); await App.Instance.GetPersonGroupAsync(GroupName); groupExists = true; Output = Output.AppendLine(string.Format("Response: Group {0} exists.", GroupName)); } catch (ClientException ex) { if (ex.Error.Code != "PersonGroupNotFound") { Output = Output.AppendLine(string.Format("Response: {0}. {1}", ex.Error.Code, ex.Error.Message)); return; } else { Output = Output.AppendLine(string.Format("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 App.Instance.DeletePersonGroupAsync(GroupName); } else { return; } } // Show folder picker FolderBrowserDialog dlg = new FolderBrowserDialog(); var result = dlg.ShowDialog(); // Set the suggestion count is intent to minimum the data preparetion step only, // it's not corresponding to service side constraint const int SuggestionCount = 15; if (result == 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 Output = Output.AppendLine(string.Format("Request: Creating group \"{0}\"", GroupName)); try { await App.Instance.CreatePersonGroupAsync(GroupName, GroupName); Output = Output.AppendLine(string.Format("Response: Success. Group \"{0}\" created", GroupName)); } catch (ClientException ex) { Output = Output.AppendLine(string.Format("Response: {0}. {1}", ex.Error.Code, ex.Error.Message)); return; } int processCount = 0; bool forceContinue = false; Output = Output.AppendLine("Request: Preparing faces for identification, detecting faces in choosen 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; // Call create person REST API, the new create person id will be returned var faces = new ObservableCollection<Face>(); p.Faces = faces; Persons.Add(p); // 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; // Call detection REST API using (var fStream = File.OpenRead(imgPath)) { try { var face = await App.Instance.DetectAsync(fStream); return new Tuple<string, ClientContract.Face[]>(imgPath, face); } catch (ClientException) { // Here we simply ignore all detection failure in this sample // You may handle these exceptions by check the Error.Code and Error.Message property for ClientException object return new Tuple<string, ClientContract.Face[]>(imgPath, null); } } }, img).Unwrap().ContinueWith((detectTask) => { // Update detected faces for rendering var detectionResult = detectTask.Result; if (detectionResult == null || detectionResult.Item2 == null) { return; } foreach (var f in detectionResult.Item2) { this.Dispatcher.Invoke( new Action<ObservableCollection<Face>, string, ClientContract.Face>(UIHelper.UpdateFace), faces, detectionResult.Item1, f); } })); 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", MessageBoxButtons.YesNo); if (continueProcess == DialogResult.Yes) { forceContinue = true; } else { break; } } } await Task.WhenAll(tasks); } Output = Output.AppendLine(string.Format("Response: Success. Total {0} faces are detected.", Persons.Sum(p => p.Faces.Count))); try { // Update person faces on server side foreach (var p in Persons) { // Call person update REST API Output = Output.AppendLine(string.Format("Request: Creating person \"{0}\"", p.PersonName)); p.PersonId = (await App.Instance.CreatePersonAsync(GroupName, p.Faces.Select(face => Guid.Parse(face.FaceId)).ToArray(), p.PersonName)).PersonId.ToString(); Output = Output.AppendLine(string.Format("Response: Success. Person \"{0}\" (PersonID:{1}) created, {2} face(s) added.", p.PersonName, p.PersonId, p.Faces.Count)); } // Start train person group Output = Output.AppendLine(string.Format("Request: Training group \"{0}\"", GroupName)); await App.Instance.TrainPersonGroupAsync(GroupName); // Wait until train completed while (true) { await Task.Delay(1000); var status = await App.Instance.GetPersonGroupTrainingStatusAsync(GroupName); Output = Output.AppendLine(string.Format("Response: {0}. Group \"{1}\" training process is {2}", "Success", GroupName, status.Status)); if (status.Status != "running") { break; } } } catch (ClientException ex) { Output = Output.AppendLine(string.Format("Response: {0}. {1}", ex.Error.Code, ex.Error.Message)); } } }
private void NewPersonButton_OnClick(object sender, RoutedEventArgs e) { var person = new Person(); SelectedPerson = person; _isSaveNew = true; }
private async Task UpdatePersonAsync(Person person) { await _client.UpdatePersonAsync(SelectedPersonGroupItem.Group.PersonGroupId, person.PersonId, person.FaceIds, person.Name, person.UserData); }
private async Task<CreatePersonResult> CreatePersonAsync(Person person) { return await _client.CreatePersonAsync(SelectedPersonGroupItem.Group.PersonGroupId, person.FaceIds, person.Name, person.UserData); }
public static BitmapSource DrawFaces(BitmapSource baseImage, Microsoft.ProjectOxford.Face.Contract.Face[] faces, Microsoft.ProjectOxford.Face.Contract.Person person) { if (faces == null) { return(baseImage); } Action <DrawingContext, double> drawAction = (drawingContext, annotationScale) => { for (int i = 0; i < faces.Length; i++) { var face = faces[i]; if (face.FaceRectangle == null) { continue; } Rect faceRect = new Rect( face.FaceRectangle.Left, face.FaceRectangle.Top, face.FaceRectangle.Width, face.FaceRectangle.Height); string text = ""; if (person != null) { text += person.Name; } faceRect.Inflate(6 * annotationScale, 6 * annotationScale); double lineThickness = 4 * annotationScale; drawingContext.DrawRectangle( Brushes.Transparent, new Pen(s_lineBrush, lineThickness), faceRect); if (text != "") { FormattedText ft = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, s_typeface, 16 * annotationScale, Brushes.Black); var pad = 3 * annotationScale; var ypad = pad; var xpad = pad + 4 * annotationScale; var origin = new System.Windows.Point( faceRect.Left + xpad - lineThickness / 2, faceRect.Top - ft.Height - ypad + lineThickness / 2); var rect = ft.BuildHighlightGeometry(origin).GetRenderBounds(null); rect.Inflate(xpad, ypad); drawingContext.DrawRectangle(s_lineBrush, null, rect); drawingContext.DrawText(ft, origin); } } }; return(DrawOverlay(baseImage, drawAction)); }
/// <summary> /// Add photos to the training group using Microsoft Face API /// </summary> /// <param name="Photos">List of photos to add</param> /// <param name="PersonGroupID">Name of the training group</param> /// <returns></returns> public async Task addPhotosToTrainingGroup(Dictionary<string, PhotoPerson> Photos, string PersonGroupID) { IFaceServiceClient faceClient = new FaceServiceClient(SubscriptionKey); // Get the group and add photos to the group. // The input dictionary is organized by person ID. The output dictionary is organized by the GUID returned by the added photo from the API. try { await faceClient.GetPersonGroupAsync(PersonGroupID); // training photos can support multiple pictures per person (more pictures will make the training more effective). // each photo is added as a Face object within the Face API and attached to a person. foreach (PhotoPerson person in Photos.Values) { Person p = new Person(); p.Name = person.Name; p.PersonId = Guid.NewGuid(); List<Guid> faceIDs = new List<Guid>(); foreach (Photo photo in person.Photos) { Stream stream = new MemoryStream(photo.Image); Face[] face = await faceClient.DetectAsync(stream); // check for multiple faces - should only have one for a training set. if (face.Length != 1) throw new FaceDetectionException("Expected to detect 1 face but found " + face.Length + " faces for person " + p.Name); else faceIDs.Add(face[0].FaceId); } Guid[] faceIDarray = faceIDs.ToArray(); // create the person in the training group with the image array of faces. CreatePersonResult result = await faceClient.CreatePersonAsync(PersonGroupID, faceIDarray, p.Name, null); p.PersonId = result.PersonId; TrainingPhotos.Add(p.PersonId, person); } await faceClient.TrainPersonGroupAsync(PersonGroupID); // Wait until train completed while (true) { await Task.Delay(1000); var status = await faceClient.GetPersonGroupTrainingStatusAsync(PersonGroupID); if (status.Status != "running") { break; } } } catch (ClientException ex) { throw; } }