-
Notifications
You must be signed in to change notification settings - Fork 558
Expand file tree
/
Copy pathFaceQuickstart-single.cs
More file actions
199 lines (175 loc) · 10.2 KB
/
FaceQuickstart-single.cs
File metadata and controls
199 lines (175 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// <snippet_single>
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.CognitiveServices.Vision.Face;
using Microsoft.Azure.CognitiveServices.Vision.Face.Models;
namespace FaceQuickstart
{
class Program
{
static string personGroupId = Guid.NewGuid().ToString();
// <snippet_image_url>
// URL path for the images.
const string IMAGE_BASE_URL = "https://csdx.blob.core.windows.net/resources/Face/Images/";
// </snippet_image_url>
// <snippet_creds>
// From your Face subscription in the Azure portal, get your subscription key and endpoint.
const string SUBSCRIPTION_KEY = "PASTE_YOUR_FACE_SUBSCRIPTION_KEY_HERE";
const string ENDPOINT = "PASTE_YOUR_FACE_SUBSCRIPTION_ENDPOINT_HERE";
// </snippet_creds>
static void Main(string[] args)
{
// Recognition model 4 was released in 2021 February.
// It is recommended since its accuracy is improved
// on faces wearing masks compared with model 3,
// and its overall accuracy is improved compared
// with models 1 and 2.
const string RECOGNITION_MODEL4 = RecognitionModel.Recognition04;
// <snippet_main_call>
// Authenticate.
IFaceClient client = Authenticate(ENDPOINT, SUBSCRIPTION_KEY);
// Identify - recognize a face(s) in a person group (a person group is created in this example).
IdentifyInPersonGroup(client, IMAGE_BASE_URL, RECOGNITION_MODEL4).Wait();
// </snippet_main_call>
Console.WriteLine("End of quickstart.");
}
// <snippet_auth>
/*
* AUTHENTICATE
* Uses subscription key and region to create a client.
*/
public static IFaceClient Authenticate(string endpoint, string key)
{
return new FaceClient(new ApiKeyServiceClientCredentials(key)) { Endpoint = endpoint };
}
// </snippet_auth>
// <snippet_detect_face_with_quality>
// Detect faces from image url for recognition purpose. This is a helper method for other functions in this quickstart.
// Parameter `returnFaceId` of `DetectWithUrlAsync` must be set to `true` (by default) for recognition purpose.
// Parameter `FaceAttributes` is set to include the QualityForRecognition attribute.
// Recognition model must be set to recognition_03 or recognition_04 as a result.
// Result faces with insufficient quality for recognition are filtered out.
// The field `faceId` in returned `DetectedFace`s will be used in Face - Find Similar, Face - Verify. and Face - Identify.
// It will expire 24 hours after the detection call.
private static async Task<List<DetectedFace>> DetectFaceRecognize(IFaceClient faceClient, string url, string recognition_model)
{
// Detect faces from image URL. Since only recognizing, use the recognition model 1.
// We use detection model 3 because we are not retrieving attributes.
IList<DetectedFace> detectedFaces = await faceClient.Face.DetectWithUrlAsync(url, recognitionModel: recognition_model, detectionModel: DetectionModel.Detection03, returnFaceAttributes: new List<FaceAttributeType> { FaceAttributeType.QualityForRecognition });
List<DetectedFace> sufficientQualityFaces = new List<DetectedFace>();
foreach (DetectedFace detectedFace in detectedFaces){
var faceQualityForRecognition = detectedFace.FaceAttributes.QualityForRecognition;
if (faceQualityForRecognition.HasValue && (faceQualityForRecognition.Value >= QualityForRecognition.Medium)){
sufficientQualityFaces.Add(detectedFace);
}
}
Console.WriteLine($"{detectedFaces.Count} face(s) with {sufficientQualityFaces.Count} having sufficient quality for recognition detected from image `{Path.GetFileName(url)}`");
return sufficientQualityFaces.ToList();
}
// </snippet_detect_face_with_quality>
/*
* IDENTIFY FACES
* To identify faces, you need to create and define a person group.
* The Identify operation takes one or several face IDs from DetectedFace or PersistedFace and a PersonGroup and returns
* a list of Person objects that each face might belong to. Returned Person objects are wrapped as Candidate objects,
* which have a prediction confidence value.
*/
// <snippet_persongroup_files>
public static async Task IdentifyInPersonGroup(IFaceClient client, string url, string recognitionModel)
{
Console.WriteLine("========IDENTIFY FACES========");
Console.WriteLine();
// Create a dictionary for all your images, grouping similar ones under the same key.
Dictionary<string, string[]> personDictionary =
new Dictionary<string, string[]>
{ { "Family1-Dad", new[] { "Family1-Dad1.jpg", "Family1-Dad2.jpg" } },
{ "Family1-Mom", new[] { "Family1-Mom1.jpg", "Family1-Mom2.jpg" } },
{ "Family1-Son", new[] { "Family1-Son1.jpg", "Family1-Son2.jpg" } },
{ "Family1-Daughter", new[] { "Family1-Daughter1.jpg", "Family1-Daughter2.jpg" } },
{ "Family2-Lady", new[] { "Family2-Lady1.jpg", "Family2-Lady2.jpg" } },
{ "Family2-Man", new[] { "Family2-Man1.jpg", "Family2-Man2.jpg" } }
};
// A group photo that includes some of the persons you seek to identify from your dictionary.
string sourceImageFileName = "identification1.jpg";
// </snippet_persongroup_files>
// <snippet_persongroup_create>
// Create a person group.
Console.WriteLine($"Create a person group ({personGroupId}).");
await client.PersonGroup.CreateAsync(personGroupId, personGroupId, recognitionModel: recognitionModel);
// The similar faces will be grouped into a single person group person.
foreach (var groupedFace in personDictionary.Keys)
{
// Limit TPS
await Task.Delay(250);
Person person = await client.PersonGroupPerson.CreateAsync(personGroupId: personGroupId, name: groupedFace);
Console.WriteLine($"Create a person group person '{groupedFace}'.");
// Add face to the person group person.
foreach (var similarImage in personDictionary[groupedFace])
{
Console.WriteLine($"Check whether image is of sufficient quality for recognition");
IList<DetectedFace> detectedFaces1 = await client.Face.DetectWithUrlAsync($"{url}{similarImage}",
recognitionModel: recognitionModel,
detectionModel: DetectionModel.Detection03,
returnFaceAttributes: new List<FaceAttributeType> { FaceAttributeType.QualityForRecognition });
bool sufficientQuality = true;
foreach (var face1 in detectedFaces1)
{
var faceQualityForRecognition = face1.FaceAttributes.QualityForRecognition;
// Only "high" quality images are recommended for person enrollment
if (faceQualityForRecognition.HasValue && (faceQualityForRecognition.Value != QualityForRecognition.High)){
sufficientQuality = false;
break;
}
}
if (!sufficientQuality){
continue;
}
Console.WriteLine($"Add face to the person group person({groupedFace}) from image `{similarImage}`");
PersistedFace face = await client.PersonGroupPerson.AddFaceFromUrlAsync(personGroupId, person.PersonId,
$"{url}{similarImage}", similarImage);
}
}
// </snippet_persongroup_create>
// <snippet_persongroup_train>
// Start to train the person group.
Console.WriteLine();
Console.WriteLine($"Train person group {personGroupId}.");
await client.PersonGroup.TrainAsync(personGroupId);
// Wait until the training is completed.
while (true)
{
await Task.Delay(1000);
var trainingStatus = await client.PersonGroup.GetTrainingStatusAsync(personGroupId);
Console.WriteLine($"Training status: {trainingStatus.Status}.");
if (trainingStatus.Status == TrainingStatusType.Succeeded) { break; }
}
Console.WriteLine();
// </snippet_persongroup_train>
List<Guid> sourceFaceIds = new List<Guid>();
// Detect faces from source image url.
List<DetectedFace> detectedFaces = await DetectFaceRecognize(client, $"{url}{sourceImageFileName}", recognitionModel);
// Add detected faceId to sourceFaceIds.
foreach (var detectedFace in detectedFaces) { sourceFaceIds.Add(detectedFace.FaceId.Value); }
// <snippet_identify_face>
// Identify the faces in a person group.
var identifyResults = await client.Face.IdentifyAsync(sourceFaceIds, personGroupId);
foreach (var identifyResult in identifyResults)
{
if (identifyResult.Candidates.Count==0) {
Console.WriteLine($"No person is identified for the face in: {sourceImageFileName} - {identifyResult.FaceId},");
continue;
}
Person person = await client.PersonGroupPerson.GetAsync(personGroupId, identifyResult.Candidates[0].PersonId);
Console.WriteLine($"Person '{person.Name}' is identified for the face in: {sourceImageFileName} - {identifyResult.FaceId}," +
$" confidence: {identifyResult.Candidates[0].Confidence}.");
}
// </snippet_identify_face>
Console.WriteLine();
}
}
}
// </snippet_single>