public ContentResult ToggleTagImage(long tagId, long thumbnailId) { try { var tag = Context.Tags.Include(t => t.TagThumbnails).FirstOrDefault(p => p.Id == tagId); if (tag == null) { return(AjaxFailedResult("Tag not found.")); } var thumbnail = Context.Thumbnails.FirstOrDefault(t => t.Id == thumbnailId); if (thumbnail == null) { return(AjaxFailedResult("Image not found.")); } var tagged = tag.TagThumbnails.FirstOrDefault(t => t.ThumbnailId == thumbnail.Id && t.TagId == tagId); if (tagged != null) { tag.TagThumbnails.Remove(tagged); Context.Entry(tag).State = EntityState.Modified; Context.SaveChanges(); return(AjaxResult <bool>(false, $"Removed {thumbnail.FileName} from {tag.Name}")); } tagged = new TagThumbnail { Tag = tag, TagId = tagId, Thumbnail = thumbnail, ThumbnailId = thumbnailId }; tag.TagThumbnails.Add(tagged); Context.Entry(tag).State = EntityState.Modified; Context.SaveChanges(); return(AjaxResult <bool>(true, $"Added {thumbnail.FileName} to {tag.Name}")); } catch (Exception ex) { Logger.Error(ex, $"Failed to toggle tag {tagId} for image {thumbnailId}. {ex.Message}: {ex}"); return(AjaxFailedResult($"Failed to toggle tag {tagId} for image {thumbnailId}: {ex.Message}")); } }
private int _ScanImages(List <long> imagesToScan) { var numNewFaces = 0; using (var context = GetNewDataContext()) using (var recognizer = SetupFacialRecognition(context)) { foreach (var id in imagesToScan) { var thumbnail = context.Thumbnails .Include(t => t.FileSystemFolder) .Include(t => t.Faces) .Include(t => t.TagThumbnails) .ThenInclude(tt => tt.Tag) .ThenInclude(tag => tag.TagType) .First(t => t.Id == id); thumbnail.Scanned = true; context.Entry(thumbnail).State = EntityState.Modified; using (var img = Image.Load(GetFullPath(thumbnail))) { ExifRotate(img); using (var imageStream = new MemoryStream()) { img.SaveAsBmp(imageStream); Logger.Trace($"Scanning image {thumbnail.FileName} for faces"); foreach (var unknown in thumbnail.Faces .Where(f => f.TagId == Base.Constants.Tags.UnknownTagId && !f.IsValid && f.NeedsValidation).ToList()) { //re-evaluate non-validated faces double dist; var tagId = recognizer.Recognize(unknown.Bytes, out dist); if (tagId.HasValue && tagId.Value != Base.Constants.Tags.UnknownTagId && dist <= _minDistanceForFacialRecognition) { unknown.TagId = tagId.Value; unknown.Distance = dist; } } var foundRectangles = thumbnail.Faces.Select(f => f.Rectangle) .ToList(); var faces = recognizer.Recognize(foundRectangles, imageStream); var sideFaces = recognizer.Recognize(foundRectangles, imageStream, FacialRecognition.HaarCascadeSideProfile); using (var flippedStream = new MemoryStream()) { img.Mutate(x => x.RotateFlip(RotateMode.None, FlipMode.Horizontal)); img.SaveAsBmp(flippedStream); var flipped = foundRectangles.Select(k => new System.Drawing.Rectangle(k.X + k.Width + thumbnail.ImageWidth, k.Y, k.Width, k.Height)).ToList(); var leftSideFaces = recognizer.Recognize(flipped, flippedStream, FacialRecognition.HaarCascadeSideProfile); foreach (var face in leftSideFaces) { //need to flip the images back. face.RectX = thumbnail.ImageWidth - face.RectWidth - face.RectX; } Logger.Trace($"Found {leftSideFaces.Count} flipped faces. {sideFaces.Count}"); faces.AddRange(sideFaces); faces.AddRange(leftSideFaces); } var filtered = new List <Face>(); foreach (var face in faces) { if ((face.Distance <= _minDistanceForFacialRecognition || face.RectWidth > _minWidthForOverride || face.RectHeight > _minHeightForOverride) && !filtered.Any(f => f.Rectangle.Contains(face.Rectangle) || face.Rectangle.Contains(f.Rectangle) || Overlaps(f.Rectangle, face.Rectangle, 70))) { if (face.Distance <= _minDistanceForFacialRecognition) { face.TagId = Base.Constants.Tags.UnknownTagId; } filtered.Add(face); } else if (_writeImagesToLocal) { var filePath = Path.Combine(_imagesToLocalPath, "Skipped"); if (!Directory.Exists(filePath)) { Directory.CreateDirectory(filePath); } using (var tmp = Image.Load(new MemoryStream(face.Bytes))) { tmp.Save(Path.Combine(filePath, $"{(int)face.Distance}_{face.TagId}_{face.RectWidth}_{face.RectHeight}_{Guid.NewGuid():N}.jpg")); } } } var groups = filtered.GroupBy(f => !thumbnail.Faces.Any(i => f.Rectangle.Contains(i.Rectangle) || i.Rectangle.Contains(f.Rectangle) || (i.Rectangle.IntersectsWith(f.Rectangle) && (i.TagId == f.TagId || Overlaps(i.Rectangle, f.Rectangle, 70))) )).ToList(); var newFaces = groups.Where(g => g.Key).SelectMany(v => v).ToList(); var oldFaces = groups.Where(g => !g.Key).SelectMany(v => v).Where(f => f.TagId != Base.Constants.Tags.UnknownTagId).ToList(); Logger.Trace($"Updating the old faces for {thumbnail.FileName}"); foreach (var face in thumbnail.Faces.Where(i => i.TagId == Base.Constants.Tags.UnknownTagId && !i.IsValid && i.NeedsValidation)) { var matches = oldFaces.Where(f => f.Rectangle.Contains(face.Rectangle) || face.Rectangle.Contains(f.Rectangle) || (face.Rectangle.IntersectsWith(f.Rectangle) && Overlaps(face.Rectangle, f.Rectangle, 70))).ToList(); if (matches.Any() && matches.Select(m => m.TagId).Distinct().Count() == 1) { face.TagId = matches.First().TagId; face.Distance = matches.First().Distance; context.Entry(face).State = EntityState.Modified; } } Logger.Trace($"Adding new faces for {thumbnail.FileName}"); foreach (var face in newFaces) { numNewFaces++; face.Thumbnail = thumbnail; face.ThumbnailId = thumbnail.Id; if (_writeImagesToLocal) { var filePath = Path.Combine(_imagesToLocalPath, "Added"); if (!Directory.Exists(filePath)) { Directory.CreateDirectory(filePath); } using (var tmp = Image.Load(new MemoryStream(face.Bytes))) { tmp.Save(Path.Combine(filePath, $"{face.TagId}_{Guid.NewGuid():N}.jpg")); } } thumbnail.Faces.Add(face); context.Faces.Add(face); } Logger.Trace($"Updating the people tags for {thumbnail.FileName}"); var tagIds = thumbnail.Faces.Where(f => f.TagId.HasValue && f.TagId != Base.Constants.Tags.UnknownTagId && !f.IsHidden).Select(f => f.TagId.Value).Distinct().ToList(); foreach (var tagId in tagIds) { if (!context.TagThumbnails.Any(tt => tt.ThumbnailId == thumbnail.Id && tt.TagId == tagId && tt.Tag.TagTypeId == Constants.Tags.PersonTagTypeId)) { var tag = context.Tags.FirstOrDefault(t => t.Id == tagId && t.TagTypeId == Constants.Tags.PersonTagTypeId); if (tag != null) { var tagThumbnail = new TagThumbnail { Tag = tag, TagId = tag.Id, Thumbnail = thumbnail, ThumbnailId = thumbnail.Id }; thumbnail.TagThumbnails.Add(tagThumbnail); } else { Logger.Error($"Tag id not found {tagId}."); } } } } Logger.Trace($"{thumbnail.FileName} complete"); } } context.SaveChanges(); } return(numNewFaces); }