in Kiosk/Views/VideoInsights/VideoInsightsPage.xaml.cs [175:296]
private async Task ProcessPeopleInsightsAsync(ImageAnalyzer analyzer, int frameNumber)
{
foreach (var item in analyzer.SimilarFaceMatches)
{
bool demographicsChanged = false;
Visitor personInVideo;
Guid persistedFaceId = item.SimilarPersistedFace.PersistedFaceId.GetValueOrDefault();
if (this.peopleInVideo.TryGetValue(persistedFaceId, out personInVideo))
{
personInVideo.Count++;
if (this.pendingIdentificationAttemptCount.ContainsKey(persistedFaceId))
{
// This is a face we haven't identified yet. See how many times we have tried it, if we need to do it again or stop trying
if (this.pendingIdentificationAttemptCount[persistedFaceId] <= 5)
{
string personName = GetDisplayTextForPersonAsync(analyzer, item);
if (string.IsNullOrEmpty(personName))
{
// Increment the times we have tried and failed to identify this person
this.pendingIdentificationAttemptCount[persistedFaceId]++;
}
else
{
// Bingo! Let's remove it from the list of pending identifications
this.pendingIdentificationAttemptCount.Remove(persistedFaceId);
VideoTrack existingTrack = (VideoTrack)this.peopleListView.Children.FirstOrDefault(f => (Guid)((FrameworkElement)f).Tag == persistedFaceId);
if (existingTrack != null)
{
existingTrack.DisplayText = ShowAgeAndGender ?
string.Format("{0}, {1}", personName, Math.Floor(item.Face.FaceAttributes.Age.GetValueOrDefault())) :
personName;
}
}
}
else
{
// Give up
this.pendingIdentificationAttemptCount.Remove(persistedFaceId);
}
}
}
else
{
// New person... let's catalog it.
// Crop the face, enlarging the rectangle so we frame it better
double heightScaleFactor = 1.8;
double widthScaleFactor = 1.8;
var biggerRectangle = new Microsoft.Azure.CognitiveServices.Vision.Face.Models.FaceRectangle
{
Height = Math.Min((int)(item.Face.FaceRectangle.Height * heightScaleFactor), FrameRelayVideoEffect.LatestSoftwareBitmap.PixelHeight),
Width = Math.Min((int)(item.Face.FaceRectangle.Width * widthScaleFactor), FrameRelayVideoEffect.LatestSoftwareBitmap.PixelWidth)
};
biggerRectangle.Left = Math.Max(0, item.Face.FaceRectangle.Left - (int)(item.Face.FaceRectangle.Width * ((widthScaleFactor - 1) / 2)));
biggerRectangle.Top = Math.Max(0, item.Face.FaceRectangle.Top - (int)(item.Face.FaceRectangle.Height * ((heightScaleFactor - 1) / 1.4)));
var croppedImage = await Util.GetCroppedBitmapAsync(analyzer.GetImageStreamCallback, biggerRectangle.ToRect());
if (croppedImage == null || biggerRectangle.Height == 0 && biggerRectangle.Width == 0)
{
// Couldn't get a shot of this person
continue;
}
demographicsChanged = true;
string personName = GetDisplayTextForPersonAsync(analyzer, item);
if (string.IsNullOrEmpty(personName))
{
if (ShowAgeAndGender)
{
personName = item.Face.FaceAttributes.Gender?.ToString();
}
// Add the person to the list of pending identifications so we can try again on some future frames
this.pendingIdentificationAttemptCount.Add(persistedFaceId, 1);
}
personInVideo = new Visitor { UniqueId = persistedFaceId };
this.peopleInVideo.Add(persistedFaceId, personInVideo);
this.demographics.Visitors.Add(personInVideo);
// Update the demographics stats.
this.UpdateDemographics(item);
VideoTrack videoTrack = new VideoTrack
{
Tag = persistedFaceId,
CroppedFace = croppedImage,
DisplayText = ShowAgeAndGender ? string.Format("{0}, {1}", personName, Math.Floor(item.Face.FaceAttributes.Age.GetValueOrDefault())) : personName,
Duration = (int)this.videoPlayer.NaturalDuration.TimeSpan.TotalSeconds,
};
videoTrack.Tapped += this.TimelineTapped;
this.peopleListView.Children.Insert(0, videoTrack);
}
// Update the timeline for this person
VideoTrack track = (VideoTrack)this.peopleListView.Children.FirstOrDefault(f => (Guid)((FrameworkElement)f).Tag == persistedFaceId);
if (track != null)
{
track.SetVideoFrameState(frameNumber, item.Face.FaceAttributes.Emotion);
uint childIndex = (uint)this.peopleListView.Children.IndexOf(track);
if (childIndex > 5)
{
// Bring to towards the top so it becomes visible
this.peopleListView.Children.Move(childIndex, 5);
}
}
if (demographicsChanged)
{
this.ageGenderDistributionControl.UpdateData(this.demographics);
}
this.overallStatsControl.UpdateData(this.demographics);
}
}