diff --git a/Distance/Models/_E_Distance.cs b/Distance/Models/_E_Distance.cs index 75fe4ed..b27af1d 100644 --- a/Distance/Models/_E_Distance.cs +++ b/Distance/Models/_E_Distance.cs @@ -10,30 +10,53 @@ namespace View_by_Distance.Distance.Models; public class E_Distance : Shared.Models.Methods.IFaceDistance { - public static void SaveFaceDistances(Property.Models.Configuration propertyConfiguration, string eResultsFullGroupDirectory, SortingContainer[] sortingContainers) + private readonly Serilog.ILogger? _Log; + private readonly string _ResultAllInOne; + private readonly int _FaceDistancePermyriad; + private readonly double _FaceDistanceTolerance; + private readonly int _SortingDaysDeltaTolerance; + private readonly bool _DistanceMoveUnableToMatch; + private readonly int _DistancePixelDistanceTolerance; + private readonly double _FaceDistanceMinimumConfidence; + private readonly int _SortingMaximumPerFaceShouldBeHigh; + + public E_Distance(bool distanceMoveUnableToMatch, int distancePixelDistanceTolerance, double faceDistanceMinimumConfidence, int faceDistancePermyriad, double faceDistanceTolerance, string resultAllInOne, int sortingDaysDeltaTolerance, int sortingMaximumPerFaceShouldBeHigh) { - string eDistanceContentCollectionDirectory = Path.Combine(eResultsFullGroupDirectory, "([])"); + _ResultAllInOne = resultAllInOne; + _Log = Serilog.Log.ForContext(); + _FaceDistancePermyriad = faceDistancePermyriad; + _FaceDistanceTolerance = faceDistanceTolerance; + _DistanceMoveUnableToMatch = distanceMoveUnableToMatch; + _SortingDaysDeltaTolerance = sortingDaysDeltaTolerance; + _FaceDistanceMinimumConfidence = faceDistanceMinimumConfidence; + _DistancePixelDistanceTolerance = distancePixelDistanceTolerance; + _SortingMaximumPerFaceShouldBeHigh = sortingMaximumPerFaceShouldBeHigh; + } + + public static void SaveFaceDistances(Property.Models.Configuration configuration, SortingContainer[] sortingContainers) + { + string eDistanceContentCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(E_Distance), "([])"); if (!Directory.Exists(eDistanceContentCollectionDirectory)) _ = Directory.CreateDirectory(eDistanceContentCollectionDirectory); #pragma warning disable string[] results = (from l in sortingContainers select string.Concat(l.Sorting.WithinRange, '\t', l.Sorting.DistancePermyriad, '\t', l.Sorting.DaysDelta, '\t', l.Sorting.Id, '\t', l.Sorting.NormalizedPixelPercentage, '\t', l.Sorting.Older, '\t', l.Face.Mapping.MappingFromItem.Id, '\t', l.Face.Mapping.MappingFromLocation.NormalizedPixelPercentage)).ToArray(); #pragma warning restore - string eDistanceContentFileName = Path.Combine(eDistanceContentCollectionDirectory, $"{propertyConfiguration.ResultAllInOne}.tvs"); + string eDistanceContentFileName = Path.Combine(eDistanceContentCollectionDirectory, $"{configuration.ResultAllInOne}.tvs"); File.WriteAllLines(eDistanceContentFileName, results); } - private static List GetSortingCollection(Configuration configuration, MapLogic mapLogic, List faceDistanceEncodings, int faceDistanceContainersLength, int i, FaceDistance faceDistanceEncoding) + private List GetSortingCollection(MapLogic mapLogic, List faceDistanceEncodings, int faceDistanceContainersLength, int i, FaceDistance faceDistanceEncoding) { List results; List faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncoding); if (faceDistanceLengths.Count != faceDistanceContainersLength) throw new NotSupportedException(); - bool anyLowerThanTolerance = (from l in faceDistanceLengths where l.Length is not null && l.Length.Value != 0 && l.Length.Value < configuration.FaceDistanceTolerance select true).Any(); + bool anyLowerThanTolerance = (from l in faceDistanceLengths where l.Length is not null && l.Length.Value != 0 && l.Length.Value < _FaceDistanceTolerance select true).Any(); results = mapLogic.GetSortingCollection(i, faceDistanceEncoding, faceDistanceLengths, anyLowerThanTolerance); return results; } - private static List GetSortingContainers(Configuration configuration, Face face, FaceDistance faceDistanceEncoding, List sortingCollection) + private List GetSortingContainers(Face face, FaceDistance faceDistanceEncoding, List sortingCollection) { List results = new(); SortingContainer sortingContainer; @@ -42,11 +65,11 @@ public class E_Distance : Shared.Models.Methods.IFaceDistance { if (face.Mapping is null || faceDistanceEncoding.NormalizedPixelPercentage is null) throw new NotSupportedException(); - if (face.Mapping.MappingFromLocation.Confidence < configuration.FaceDistanceMinimumConfidence || sorting.DistancePermyriad > configuration.FaceDistancePermyriad || sorting.DaysDelta > configuration.SortingDaysDeltaTolerance) + if (face.Mapping.MappingFromLocation.Confidence < _FaceDistanceMinimumConfidence || sorting.DistancePermyriad > _FaceDistancePermyriad || sorting.DaysDelta > _SortingDaysDeltaTolerance) continue; sortingContainer = new(face, sorting); results.Add(sortingContainer); - if (results.Count >= configuration.SortingMaximumPerFaceShouldBeHigh) + if (results.Count >= _SortingMaximumPerFaceShouldBeHigh) break; } return results; @@ -64,7 +87,16 @@ public class E_Distance : Shared.Models.Methods.IFaceDistance return faceDistanceEncodings; } - private static FaceDistanceContainer[] GetFaceDistanceContainers(List selectedFilteredFaces) + private static FaceDistanceContainer[] GetOrderedFaceDistanceContainers(List collection) + { + FaceDistanceContainer[] results; + results = (from l in collection orderby l.FaceDistance.Encoding is not null select l).ToArray(); + if (results.Any() && results[0].FaceDistance.Encoding is null) + throw new Exception("Sorting failed!"); + return results; + } + + private static FaceDistanceContainer[] GetOrderedFaceDistanceContainers(Face[] selectedFilteredFaces) { FaceDistanceContainer[] results; FaceDistance faceDistance; @@ -80,23 +112,22 @@ public class E_Distance : Shared.Models.Methods.IFaceDistance faceDistanceContainer = new(face, faceDistance); collection.Add(faceDistanceContainer); } - results = (from l in collection orderby l.FaceDistance.Encoding is not null select l).ToArray(); - if (results.Any() && results[0].FaceDistance.Encoding is null) - throw new Exception("Sorting failed!"); + results = GetOrderedFaceDistanceContainers(collection); return results; } - public static SortingContainer[] SetFaceMappingSortingCollectionThenGetSortingContainers(int maxDegreeOfParallelism, Configuration configuration, long ticks, MapLogic mapLogic, List selectedFilteredFaces) + public SortingContainer[] SetFaceMappingSortingCollectionThenGetSortingContainers(int maxDegreeOfParallelism, long ticks, MapLogic mapLogic, Face[] selectedFilteredFaces) { SortingContainer[] results; List collection = new(); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; - FaceDistanceContainer[] faceDistanceContainers = GetFaceDistanceContainers(selectedFilteredFaces); + FaceDistanceContainer[] faceDistanceContainers = GetOrderedFaceDistanceContainers(selectedFilteredFaces); List faceDistanceEncodings = GetFaceDistanceEncodings(faceDistanceContainers); string message = $") {faceDistanceContainers.Length:000} Get Sorting Containers Then Set Face Mapping Sorting Collection - {totalSeconds} total second(s)"; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - selectedFilteredFaces.Clear(); + foreach (Face face in selectedFilteredFaces) + face.ClearFaceDistance(); using ProgressBar progressBar = new(faceDistanceContainers.Length, message, options); _ = Parallel.For(0, faceDistanceContainers.Length, parallelOptions, (i, state) => { @@ -105,8 +136,8 @@ public class E_Distance : Shared.Models.Methods.IFaceDistance if (face.Mapping is null) throw new NotSupportedException(); FaceDistance faceDistanceEncoding = faceDistanceContainers[i].FaceDistance; - List sortingCollection = GetSortingCollection(configuration, mapLogic, faceDistanceEncodings, faceDistanceContainers.Length, i, faceDistanceEncoding); - List sortingContainers = GetSortingContainers(configuration, face, faceDistanceEncoding, sortingCollection); + List sortingCollection = GetSortingCollection(mapLogic, faceDistanceEncodings, faceDistanceContainers.Length, i, faceDistanceEncoding); + List sortingContainers = GetSortingContainers(face, faceDistanceEncoding, sortingCollection); lock (collection) collection.AddRange(sortingContainers); lock (face) @@ -116,49 +147,73 @@ public class E_Distance : Shared.Models.Methods.IFaceDistance return results; } - public static List GetSelectedFilteredFaces(List distinctFilteredFaces) + public static Face[] GetSelectedFilteredFaces(List distinctFilteredFaces) { - List results; - Face[] orderedFilteredFaces = (from l in distinctFilteredFaces orderby l.Mapping is not null, l.Mapping?.MappingFromItem.MinimumDateTime descending select l).ToArray(); - results = orderedFilteredFaces.ToList(); + Face[] results = (from l in distinctFilteredFaces orderby l.Mapping is not null, l.Mapping?.MappingFromItem.MinimumDateTime descending select l).ToArray(); return results; } - public static void SetFaceDistances(int maxDegreeOfParallelism, long ticks, List selectedFilteredFaces) + public static void SetFaceDistances(int maxDegreeOfParallelism, long ticks, Face[] selectedFilteredFaces) { int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; - string message = $") {selectedFilteredFaces.Count:000} Load Face Encoding - {totalSeconds} total second(s)"; + string message = $") {selectedFilteredFaces.Length:000} Load Face Encoding - {totalSeconds} total second(s)"; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - using ProgressBar progressBar = new(selectedFilteredFaces.Count, message, options); - _ = Parallel.For(0, selectedFilteredFaces.Count, parallelOptions, (i, state) => + using ProgressBar progressBar = new(selectedFilteredFaces.Length, message, options); + _ = Parallel.For(0, selectedFilteredFaces.Length, parallelOptions, (i, state) => { - progressBar.Tick(); - FaceDistance faceDistance; Face face = selectedFilteredFaces[i]; - FaceRecognitionDotNet.FaceEncoding faceEncoding; if (face.FaceEncoding is null || face.Mapping is null) throw new NotSupportedException(); + if (face.FaceDistance?.Encoding is not null && face.FaceDistance.Encoding is FaceRecognitionDotNet.FaceEncoding faceEncoding) + return; + progressBar.Tick(); faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); - faceDistance = new(face.Mapping.MappingFromLocation.Confidence, faceEncoding, face.Mapping.MappingFromItem.Id, face.Mapping.MappingFromItem.IsWrongYear, face.Mapping.MappingFromItem.MinimumDateTime, face.Mapping.MappingFromLocation.NormalizedPixelPercentage); + FaceDistance faceDistance = new(face.Mapping.MappingFromLocation.Confidence, faceEncoding, face.Mapping.MappingFromItem.Id, face.Mapping.MappingFromItem.IsWrongYear, face.Mapping.MappingFromItem.MinimumDateTime, face.Mapping.MappingFromLocation.NormalizedPixelPercentage); lock (face) - face.FaceDistanceAdd(faceDistance); + face.SetFaceDistance(faceDistance); }); } - List Shared.Models.Methods.IFaceDistance.GetMatchingFaces(double faceDistanceTolerance, string checkFile, List faces) + private static FaceDistanceContainer[] GetOrderedFaceDistanceContainers(MappingFromItem mappingFromItem, List faces) { - List results = new(); + FaceDistanceContainer[] results; + FaceDistance faceDistance; + int normalizedPixelPercentage; + FaceDistanceContainer faceDistanceContainer; + List collection = new(); + foreach (Face face in faces) + { + if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null) + throw new NotSupportedException(); + normalizedPixelPercentage = Shared.Models.Stateless.Methods.ILocation.GetNormalizedPixelPercentage(face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, face.OutputResolution); + if (face.FaceDistance?.Encoding is not null && face.FaceDistance.Encoding is FaceRecognitionDotNet.FaceEncoding faceEncoding) + faceDistance = new(face.Location.Confidence, faceEncoding, mappingFromItem.Id, mappingFromItem.IsWrongYear, mappingFromItem.MinimumDateTime, normalizedPixelPercentage); + else + { + faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); + faceDistance = new(face.Location.Confidence, faceEncoding, mappingFromItem.Id, mappingFromItem.IsWrongYear, mappingFromItem.MinimumDateTime, normalizedPixelPercentage); + lock (faces) + face.SetFaceDistance(faceDistance); + } + faceDistanceContainer = new(face, faceDistance); + collection.Add(faceDistanceContainer); + } + results = GetOrderedFaceDistanceContainers(collection); + return results; + } + + private static List<(Face Face, double Length)> GetValues(double faceDistanceTolerance, MappingFromItem mappingFromItem, List faces, string json) + { + List<(Face Face, double Length)> results = new(); Face face; FaceDistance faceDistanceLength; - string json = File.ReadAllText(checkFile); - List<(Face Face, double Length)> collection = new(); Shared.Models.FaceEncoding? modelsFaceEncoding = JsonSerializer.Deserialize(json); if (modelsFaceEncoding is null) throw new NotSupportedException(); FaceRecognitionDotNet.FaceEncoding faceRecognitionDotNetFaceEncoding = FaceRecognition.LoadFaceEncoding(modelsFaceEncoding.RawEncoding); FaceDistance faceDistanceEncoding = new(faceRecognitionDotNetFaceEncoding); - FaceDistanceContainer[] faceDistanceContainers = GetFaceDistanceContainers(faces); + FaceDistanceContainer[] faceDistanceContainers = GetOrderedFaceDistanceContainers(mappingFromItem, faces); int faceDistanceContainersLength = faceDistanceContainers.Length; if (faceDistanceContainersLength != faces.Count) throw new NotSupportedException(); @@ -172,12 +227,19 @@ public class E_Distance : Shared.Models.Methods.IFaceDistance { face = faces[i]; faceDistanceLength = faceDistanceLengths[i]; - if (face.Mapping is null || faceDistanceLength.Length is null) + if (faceDistanceLength.Length is null) throw new NotSupportedException(); if (faceDistanceLength.Length.Value > faceDistanceTolerance) continue; - collection.Add(new(face, faceDistanceLength.Length.Value)); + results.Add(new(face, faceDistanceLength.Length.Value)); } + return results; + } + + private static List GetMatchingFaces(double faceDistanceTolerance, MappingFromItem mappingFromItem, List faces, string json) + { + List results = new(); + List<(Face Face, double Length)> collection = GetValues(faceDistanceTolerance, mappingFromItem, faces, json); if (collection.Any()) { collection = (from l in collection orderby l.Length select l).ToList(); @@ -237,4 +299,320 @@ public class E_Distance : Shared.Models.Methods.IFaceDistance } } + private void MoveUnableToMatch(string eDistanceContentDirectory, string file) + { + bool result; + string? fileName = Path.GetFileName(file); + string? directoryName = Path.GetDirectoryName(file); + if (fileName is null || directoryName is null) + result = false; + else + { + if (string.IsNullOrEmpty(directoryName) || string.IsNullOrEmpty(directoryName) || !directoryName.Contains(eDistanceContentDirectory)) + result = false; + else + { + List directoryNames = new(); + string? checkDirectoryName = directoryName; + for (int i = 0; i < int.MaxValue; i++) + { + if (string.IsNullOrEmpty(checkDirectoryName)) + continue; + directoryNames.Add(Path.GetFileName(checkDirectoryName)); + checkDirectoryName = Path.GetDirectoryName(checkDirectoryName); + if (string.IsNullOrEmpty(checkDirectoryName)) + continue; + if (checkDirectoryName == eDistanceContentDirectory) + break; + } + if (string.IsNullOrEmpty(checkDirectoryName) || !directoryNames.Any() || !long.TryParse(directoryNames[^1][1..^1], out long directoryTicks)) + { + result = false; + File.Delete(file); + } + else + { + checkDirectoryName = Path.Combine(checkDirectoryName, $"({directoryTicks}{_FaceDistanceTolerance.ToString()[1..]})"); + for (int i = directoryNames.Count - 1 - 1; i > -1; i--) + checkDirectoryName = Path.Combine(checkDirectoryName, directoryNames[i]); + if (!Directory.Exists(checkDirectoryName)) + _ = Directory.CreateDirectory(checkDirectoryName); + File.Move(file, Path.Combine(checkDirectoryName, fileName)); + result = true; + } + } + } + if (result) + { } + } + + public static string? GetFaceEncoding(string file) + { + string? result; + List results = new(); + const string comment = "Comment: "; + if (File.Exists(file)) + { + IReadOnlyList directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(file); + foreach (MetadataExtractor.Directory directory in directories) + { + if (directory.Name != "PNG-tEXt") + continue; + foreach (MetadataExtractor.Tag tag in directory.Tags) + { + if (tag.Name != "Textual Data" || string.IsNullOrEmpty(tag.Description)) + continue; + if (!tag.Description.StartsWith(comment)) + continue; + results.Add(tag.Description); + } + } + } + result = results.Any() ? results[0][comment.Length..] : null; + return result; + } + + private static Face[] GetMatchingFaces(int pixelDistanceTolerance, List faces) + { + Face[] results; + int? x; + int? y; + double distance; + double center = 2f; + double xCenterValue; + double yCenterValue; + string normalizedPixelPercentagePadded; + List<(double Order, Face Face)> collection = new(); + foreach (Face face in faces) + { + if (face.Location is null || face.OutputResolution is null || face.Mapping is null) + throw new NotSupportedException(); + xCenterValue = (face.Location.Left + face.Location.Right) / center; + yCenterValue = (face.Location.Top + face.Location.Bottom) / center; + if (xCenterValue < face.Location.Left || xCenterValue > face.Location.Right) + throw new Exception(); + if (yCenterValue < face.Location.Top || yCenterValue > face.Location.Bottom) + throw new Exception(); + normalizedPixelPercentagePadded = Shared.Models.Stateless.Methods.ILocation.GetLeftPadded(Shared.Models.Stateless.ILocation.Digits, face.Mapping.MappingFromLocation.NormalizedPixelPercentage); + (x, y) = Shared.Models.Stateless.Methods.ILocation.GetXY(Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, face.OutputResolution.Width, face.OutputResolution.Height, normalizedPixelPercentagePadded); + if (x is null || y is null) + throw new NotSupportedException(); + distance = Math.Sqrt(Math.Pow(xCenterValue - x.Value, 2) + Math.Pow(yCenterValue - y.Value, 2)); + collection.Add(new(distance, face)); + } + results = (from l in collection orderby l.Order where l.Order < pixelDistanceTolerance select l.Face).ToArray(); + if (results.Any()) + { + if (results.Any()) + { } + } + return results; + } + + private static string[] GetMatchingDuplicates(string[] mappedFaceFiles, List duplicateMappedFaceFiles, string mappedFaceFile) + { + string[] results; + string checkFile; + FileInfo fileInfo = new(mappedFaceFile); + List<(long Length, string FullName)> collection = new(); + if (fileInfo.Exists) + collection.Add(new(fileInfo.Length, fileInfo.FullName)); + string fileName = Path.GetFileName(mappedFaceFile); + foreach (string file in mappedFaceFiles) + { + if (duplicateMappedFaceFiles.Contains(file)) + continue; + if (file == mappedFaceFile || !file.EndsWith(fileName)) + continue; + fileInfo = new(file); + if (!fileInfo.Exists) + continue; + collection.Add(new(fileInfo.Length, fileInfo.FullName)); + } + collection = collection.OrderBy(l => l.Length).ToList(); + for (int i = 0; i < collection.Count - 1; i++) + { + checkFile = string.Concat(collection[i].FullName, ".dup"); + if (File.Exists(checkFile)) + continue; + File.Move(collection[i].FullName, checkFile); + } + results = (from l in collection select l.FullName).ToArray(); + return results; + } + + private static List GetMatchingFaces(List faces, string? json) + { + List results = new(); + string check; + foreach (Face face in faces) + { + if (json is null || face.FaceEncoding is null) + continue; + if (!json.Contains(face.FaceEncoding.RawEncoding[0].ToString())) + continue; + check = JsonSerializer.Serialize(face.FaceEncoding); + if (check != json) + continue; + results.Add(face); + } + return results; + } + + private static FileInfo? CheckFileThenGetFileInfo(string facesFileNameExtension, Item item, string mappedFaceDirectory, string mappedFaceFile, List checkFaces) + { + FileInfo? result = null; + string checkFile; + string deterministicHashCodeKey; + foreach (Face face in checkFaces) + { + if (checkFaces.Count != 1) + break; + if (item.Property?.Id is null || item.ImageFileHolder is null) + throw new NotSupportedException(); + if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null) + throw new NotSupportedException(); + deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, face.OutputResolution); + checkFile = Path.Combine(mappedFaceDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{facesFileNameExtension}"); + if (checkFile == mappedFaceFile) + continue; + result = new FileInfo(checkFile); + if (!result.Exists) + continue; + File.Delete(result.FullName); + result = null; + } + return result; + } + + public (int, int) GetUnableToMatchCountAndRenameMatches(string facesFileNameExtension, string eDistanceContentDirectory, List duplicateMappedFaceFilesCollection, Item item, List faces, string[] mappedFaceFiles) + { + int result = 0; + int? id; + string? json; + bool debugCheck; + int renamed = 0; + bool? isWrongYear; + FileInfo? fileInfo; + DateTime minimumDateTime; + string? mappedFaceDirectory; + List checkFaces = new(); + List debugChecks = new(); + int? normalizedPixelPercentage; + MappingFromItem mappingFromItem; + int normalizedPixelPercentageLoop; + List normalizedPixelPercentages; + List duplicateMappedFaceFiles = new(); + Dictionary> idToNormalizedPixelPercentages = new(); + foreach (string mappedFaceFile in mappedFaceFiles) + { + mappedFaceDirectory = Path.GetDirectoryName(mappedFaceFile); + if (mappedFaceDirectory is null) + throw new NotSupportedException(); + if (item.Property?.Id is null) + throw new NotSupportedException(); + if (duplicateMappedFaceFiles.Contains(mappedFaceFile)) + continue; + (id, normalizedPixelPercentage, _) = Shared.Models.Stateless.Methods.IMapping.GetReversedDeterministicHashCodeKey( + Shared.Models.Stateless.ILocation.Digits, + facesFileNameExtension, + mappedFaceFile); + if (id is null || normalizedPixelPercentage is null) + { + result++; + continue; + } + if (id.Value != item.Property.Id.Value) + continue; + if (item.Property?.Id is null || item.ImageFileHolder is null || item.ResizedFileHolder is null) + continue; + minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); + (isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime); + mappingFromItem = new(item.Property.Id.Value, item.ImageFileHolder, isWrongYear, minimumDateTime, item.ResizedFileHolder); + json = null; + debugCheck = false; + checkFaces.Clear(); + debugChecks.Clear(); + if (!idToNormalizedPixelPercentages.ContainsKey(id.Value)) + idToNormalizedPixelPercentages.Add(id.Value, new()); + normalizedPixelPercentages = idToNormalizedPixelPercentages[id.Value]; + foreach (Face face in faces) + { + if (face.Location is null || face.OutputResolution is null) + throw new NotSupportedException(); + normalizedPixelPercentageLoop = Shared.Models.Stateless.Methods.ILocation.GetNormalizedPixelPercentage(face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, face.OutputResolution); + debugChecks.Add(normalizedPixelPercentageLoop); + if (normalizedPixelPercentage.Value != normalizedPixelPercentageLoop) + continue; + if (normalizedPixelPercentages.Contains(normalizedPixelPercentageLoop)) + { + duplicateMappedFaceFiles.AddRange(GetMatchingDuplicates(mappedFaceFiles, duplicateMappedFaceFiles, mappedFaceFile)); + continue; + } + debugCheck = true; + checkFaces.Add(face); + if (!debugCheck) + debugChecks.Add(normalizedPixelPercentageLoop); + } + if (checkFaces.Count != 1) + { + checkFaces.Clear(); + json = GetFaceEncoding(mappedFaceFile); + if (json is null) + { + result++; + if (_DistanceMoveUnableToMatch) + MoveUnableToMatch(eDistanceContentDirectory, mappedFaceFile); + continue; + } + checkFaces.AddRange(GetMatchingFaces(faces, json)); + } + if (checkFaces.Count != 1 && !string.IsNullOrEmpty(json)) + { + checkFaces.Clear(); + if (json is null) + { + result++; + if (_DistanceMoveUnableToMatch) + MoveUnableToMatch(eDistanceContentDirectory, mappedFaceFile); + continue; + } + checkFaces.AddRange(GetMatchingFaces(_FaceDistanceTolerance, mappingFromItem, faces, json)); + } + if (checkFaces.Count != 1 && _DistancePixelDistanceTolerance > 0) + { + checkFaces.Clear(); + checkFaces.AddRange(GetMatchingFaces(_DistancePixelDistanceTolerance, faces)); + } + if (!checkFaces.Any() && faces.Count == 1) + checkFaces.AddRange(faces); + if (!checkFaces.Any()) + { + result++; + if (_DistanceMoveUnableToMatch) + MoveUnableToMatch(eDistanceContentDirectory, mappedFaceFile); + continue; + } + if (checkFaces.Count != 1) + { + result++; + if (_DistanceMoveUnableToMatch) + MoveUnableToMatch(eDistanceContentDirectory, mappedFaceFile); + continue; + } + normalizedPixelPercentages.Add(normalizedPixelPercentage.Value); + fileInfo = CheckFileThenGetFileInfo(facesFileNameExtension, item, mappedFaceDirectory, mappedFaceFile, checkFaces); + if (fileInfo is null) + continue; + File.Move(mappedFaceFile, fileInfo.FullName); + renamed++; + } + if (duplicateMappedFaceFiles.Any()) + { + lock (duplicateMappedFaceFilesCollection) + duplicateMappedFaceFilesCollection.Add(duplicateMappedFaceFiles.ToArray()); + } + return new(result, renamed); + } + } \ No newline at end of file diff --git a/Face/Models/_D_Face.cs b/Face/Models/_D_Face.cs index a0647d2..963f28a 100644 --- a/Face/Models/_D_Face.cs +++ b/Face/Models/_D_Face.cs @@ -28,27 +28,25 @@ public class D_Face private readonly Model _Model; private readonly string _ArgZero; + private readonly int _NumberOfJitters; private readonly Serilog.ILogger? _Log; + private readonly bool _OverrideForFaceImages; + private readonly bool _RetryImagesWithoutAFace; private readonly Configuration _Configuration; + private readonly int _NumberOfTimesToUpsample; private readonly ImageCodecInfo _ImageCodecInfo; private readonly ModelParameter _ModelParameter; private readonly PredictorModel _PredictorModel; + private readonly bool _CheckDFaceAndUpWriteDates; + private readonly bool _PropertiesChangedForFaces; private readonly ConstructorInfo _ConstructorInfo; + private readonly int _FaceDistanceHiddenImageFactor; private readonly EncoderParameters _EncoderParameters; private readonly ImageCodecInfo _HiddenImageCodecInfo; + private readonly bool _ForceFaceLastWriteTimeToCreationTime; private readonly EncoderParameters _HiddenEncoderParameters; private readonly JsonSerializerOptions _WriteIndentedAndWhenWritingNull; - private readonly bool _CheckDFaceAndUpWriteDates; - private readonly int _FaceDistanceHiddenImageFactor; - private readonly bool _ForceFaceLastWriteTimeToCreationTime; - private readonly int _LocationDigits; - private readonly int _LocationFactor; - private readonly int _NumberOfJitters; - private readonly int _NumberOfTimesToUpsample; - private readonly bool _OverrideForFaceImages; - private readonly bool _PropertiesChangedForFaces; - public D_Face( string argZero, bool checkDFaceAndUpWriteDates, @@ -61,13 +59,12 @@ public class D_Face string hiddenFileNameExtension, ImageCodecInfo hiddenImageCodecInfo, ImageCodecInfo imageCodecInfo, - int locationDigits, - int locationFactor, Model model, ModelParameter modelParameter, int numberOfJitters, int numberOfTimesToUpsample, bool overrideForFaceImages, + bool retryImagesWithoutAFace, PredictorModel predictorModel, bool propertiesChangedForFaces) { @@ -75,8 +72,6 @@ public class D_Face _ArgZero = argZero; _Configuration = configuration; _ImageCodecInfo = imageCodecInfo; - _LocationDigits = locationDigits; - _LocationFactor = locationFactor; _ModelParameter = modelParameter; _PredictorModel = predictorModel; _NumberOfJitters = numberOfJitters; @@ -86,6 +81,7 @@ public class D_Face AngleBracketCollection = new List(); _HiddenImageCodecInfo = hiddenImageCodecInfo; _OverrideForFaceImages = overrideForFaceImages; + _RetryImagesWithoutAFace = retryImagesWithoutAFace; _HiddenEncoderParameters = hiddenEncoderParameters; _HiddenFileNameExtension = hiddenFileNameExtension; _NumberOfTimesToUpsample = numberOfTimesToUpsample; @@ -145,15 +141,15 @@ public class D_Face { if (fileInfo is null) continue; - if (face.FaceEncoding is null || face?.Location?.NormalizedPixelPercentage is null || face?.OutputResolution is null) + if (face.FaceEncoding is null || face?.Location is null || face?.OutputResolution is null) continue; - location = Shared.Models.Stateless.Methods.ILocation.GetLocation(face.Location, _LocationDigits, _LocationFactor, source.Height, source.Width, collection.Count); + location = Shared.Models.Stateless.Methods.ILocation.GetLocation(face.Location, ILocation.Digits, ILocation.Factor, source.Height, source.Width, collection.Count); if (location is null) continue; width = location.Right - location.Left; height = location.Bottom - location.Top; json = JsonSerializer.Serialize(face.FaceEncoding); - pixel = Shared.Models.Stateless.Methods.ILocation.GetNormalizedPixelPercentage(face.Location, _LocationDigits, _LocationFactor, face.OutputResolution); + pixel = Shared.Models.Stateless.Methods.ILocation.GetNormalizedPixelPercentage(face.Location, ILocation.Digits, ILocation.Factor, face.OutputResolution); rectangle = new Rectangle(location.Left, location.Top, width, height); using (bitmap = new(width, height)) { @@ -165,7 +161,7 @@ public class D_Face } if (File.Exists(fileName)) File.Delete(fileName); - location = Shared.Models.Stateless.Methods.ILocation.GetLocation(_FaceDistanceHiddenImageFactor, face.Location, _LocationDigits, _LocationFactor, source.Height, source.Width, collection.Count); + location = Shared.Models.Stateless.Methods.ILocation.GetLocation(_FaceDistanceHiddenImageFactor, face.Location, ILocation.Digits, ILocation.Factor, source.Height, source.Width, collection.Count); if (location is null) continue; width = location.Right - location.Left; @@ -199,22 +195,22 @@ public class D_Face { unknownImage = null; } } if (unknownImage is null) - results.Add(new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, item.RelativePath, i: null, location: null)); + results.Add(new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, item.RelativePath, location: null)); else { - List<(int, Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary? FaceParts)> collection; + List<(Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary? FaceParts)> collection; FaceRecognition faceRecognition = new(_NumberOfTimesToUpsample, _NumberOfJitters, _PredictorModel, _Model, _ModelParameter); - collection = faceRecognition.GetCollection(unknownImage, includeFaceEncoding: true, includeFaceParts: true, sortByNormalizedPixelPercentage: true); + collection = faceRecognition.GetCollection(unknownImage, includeFaceEncoding: true, includeFaceParts: true); if (!collection.Any()) - results.Add(new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, item.RelativePath, i: null, location: null)); + results.Add(new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, item.RelativePath, location: null)); else { double[] rawEncoding; Shared.Models.Face face; Shared.Models.FaceEncoding convertedFaceEncoding; - foreach ((int locationIndex, Location location, FaceRecognitionDotNet.FaceEncoding? faceEncoding, Dictionary? faceParts) in collection) + foreach ((Location location, FaceRecognitionDotNet.FaceEncoding? faceEncoding, Dictionary? faceParts) in collection) { - face = new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, item.RelativePath, locationIndex, location); + face = new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, item.RelativePath, location); if (faceEncoding is not null) { rawEncoding = faceEncoding.GetRawEncoding(); @@ -246,8 +242,6 @@ public class D_Face if (string.IsNullOrEmpty(dResultsFullGroupDirectory)) throw new NullReferenceException(nameof(dResultsFullGroupDirectory)); string json; - int?[] normalizedPixelPercentageCollection; - int normalizedPixelPercentageDistinctCount; string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize) }; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); string usingRelativePath = Path.Combine(AngleBracketCollection[0].Replace("<>", "[]"), $"{item.ImageFileHolder.NameWithoutExtension}.json"); @@ -296,13 +290,6 @@ public class D_Face results = JsonSerializer.Deserialize>(json); if (results is null) throw new NullReferenceException(nameof(results)); - if (!_ForceFaceLastWriteTimeToCreationTime) - { - normalizedPixelPercentageCollection = Shared.Models.Stateless.Methods.IFace.GetInts(results); - normalizedPixelPercentageDistinctCount = normalizedPixelPercentageCollection.Distinct().Count(); - if (normalizedPixelPercentageDistinctCount != normalizedPixelPercentageCollection.Length) - throw new Exception($"Not distinct! <{fileInfo.FullName}>"); - } subFileTuples.Add(new Tuple(nameof(D_Face), fileInfo.LastWriteTime)); } catch (Exception) @@ -311,22 +298,22 @@ public class D_Face parseExceptions.Add(nameof(D_Face)); } } - if (results is null) + if (results is null || (_RetryImagesWithoutAFace && results.Count == 1 && results[0].FaceEncoding is null)) { + bool wasNull = results is null; results = GetFaces(item, property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation); - json = JsonSerializer.Serialize(results, _WriteIndentedAndWhenWritingNull); - bool updateDateWhenMatches = dateTimes.Any() && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime; - DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); - if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) - subFileTuples.Add(new Tuple(nameof(D_Face), DateTime.Now)); + if (wasNull || (!wasNull && results.Any(l => l.FaceEncoding is not null))) + { + json = JsonSerializer.Serialize(results, _WriteIndentedAndWhenWritingNull); + bool updateDateWhenMatches = dateTimes.Any() && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime; + DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); + if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) + subFileTuples.Add(new Tuple(nameof(D_Face), DateTime.Now)); + } } if (_ForceFaceLastWriteTimeToCreationTime) { - results = (from l in results select new Shared.Models.Face(_LocationDigits, _LocationFactor, results.Count, l)).ToList(); - normalizedPixelPercentageCollection = Shared.Models.Stateless.Methods.IFace.GetInts(results); - normalizedPixelPercentageDistinctCount = normalizedPixelPercentageCollection.Distinct().Count(); - if (normalizedPixelPercentageDistinctCount != normalizedPixelPercentageCollection.Length) - throw new Exception($"Not distinct! <{fileInfo.FullName}>"); + results = (from l in results select new Shared.Models.Face(ILocation.Digits, ILocation.Factor, results.Count, l)).ToList(); json = JsonSerializer.Serialize(results, _WriteIndentedAndWhenWritingNull); bool updateDateWhenMatches = dateTimes.Any() && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime; DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); @@ -340,7 +327,7 @@ public class D_Face return results; } - public void SaveFaces(string dResultsFullGroupDirectory, List> subFileTuples, List parseExceptions, Item item, List faceCollection) + public void SaveFaces(string dResultsFullGroupDirectory, List> subFileTuples, List parseExceptions, Item item, List faces) { if (item.ImageFileHolder is null) throw new NullReferenceException(nameof(item.ImageFileHolder)); @@ -349,22 +336,22 @@ public class D_Face FileInfo fileInfo; bool check = false; string parentCheck; - string deterministicHashCodeKeyDisplay; + string deterministicHashCodeKey; List<(Shared.Models.Face, FileInfo?, string)> collection = new(); string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize) }; string facesDirectory = Path.Combine(AngleBracketCollection[0].Replace("<>", "()"), item.ImageFileHolder.NameWithoutExtension); List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); if (!Directory.Exists(facesDirectory)) _ = Directory.CreateDirectory(facesDirectory); - foreach (Shared.Models.Face face in faceCollection) + foreach (Shared.Models.Face face in faces) { - if (item.Property?.Id is null || face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) + if (item.Property?.Id is null || face.FaceEncoding is null || face.Location is null || face.OutputResolution is null) { collection.Add(new(face, null, string.Empty)); continue; } - deterministicHashCodeKeyDisplay = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, face.Location.NormalizedPixelPercentage.Value); - fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{deterministicHashCodeKeyDisplay}{item.ImageFileHolder.ExtensionLowered}{_FileNameExtension}")); + deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, face.Location, ILocation.Digits, ILocation.Factor, face.OutputResolution); + fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FileNameExtension}")); if (!fileInfo.Exists) { if (fileInfo.Directory?.Parent is null) @@ -373,7 +360,7 @@ public class D_Face if (File.Exists(parentCheck)) File.Delete(parentCheck); } - collection.Add(new(face, fileInfo, Path.Combine(facesDirectory, $"{deterministicHashCodeKeyDisplay}{item.ImageFileHolder.ExtensionLowered}{_HiddenFileNameExtension}"))); + collection.Add(new(face, fileInfo, Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_HiddenFileNameExtension}"))); if (_OverrideForFaceImages) check = true; else if (!fileInfo.Exists) diff --git a/FaceParts/Models/_D2_FaceParts.cs b/FaceParts/Models/_D2_FaceParts.cs index 17d32f2..03630af 100644 --- a/FaceParts/Models/_D2_FaceParts.cs +++ b/FaceParts/Models/_D2_FaceParts.cs @@ -144,7 +144,7 @@ public class D2_FaceParts Bitmap rotated; foreach ((Shared.Models.Face face, string fileName, string rotatedFileName) in collection) { - if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) + if (face.FaceEncoding is null || face.Location is null) continue; try { @@ -215,8 +215,8 @@ public class D2_FaceParts FileInfo rotatedFileInfo; DateTime? dateTime = null; long ticks = DateTime.Now.Ticks; + string deterministicHashCodeKey; bool updateDateWhenMatches = false; - string deterministicHashCodeKeyDisplay; List<(Shared.Models.Face, string, string)> collection = new(); string[] changesFrom = new string[] { nameof(Property.Models.A_Property), nameof(B_Metadata), nameof(C_Resize), nameof(D_Face) }; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); @@ -224,13 +224,13 @@ public class D2_FaceParts _ = Directory.CreateDirectory(facesDirectory); foreach (Shared.Models.Face face in faceCollection) { - if (item.Property?.Id is null || face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) + if (item.Property?.Id is null || face.FaceEncoding is null || face.Location is null || face.OutputResolution is null) { collection.Add(new(face, string.Empty, string.Empty)); continue; } - deterministicHashCodeKeyDisplay = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, face.Location.NormalizedPixelPercentage.Value); - fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{deterministicHashCodeKeyDisplay}{item.ImageFileHolder.ExtensionLowered}{_FileNameExtension}")); + deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, face.OutputResolution); + fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FileNameExtension}")); if (!fileInfo.Exists) { if (fileInfo.Directory?.Parent is null) @@ -241,7 +241,7 @@ public class D2_FaceParts } if (string.IsNullOrEmpty(fileInfo.DirectoryName)) continue; - rotatedFileInfo = new FileInfo(Path.Combine(fileInfo.DirectoryName, $"{deterministicHashCodeKeyDisplay} - R{item.ImageFileHolder.ExtensionLowered}{_FileNameExtension}")); + rotatedFileInfo = new FileInfo(Path.Combine(fileInfo.DirectoryName, $"{deterministicHashCodeKey} - R{item.ImageFileHolder.ExtensionLowered}{_FileNameExtension}")); collection.Add(new(face, fileInfo.FullName, rotatedFileInfo.FullName)); if (check) continue; diff --git a/FaceRecognitionDotNet/FaceRecognition.cs b/FaceRecognitionDotNet/FaceRecognition.cs index b0daac8..60f4b5f 100644 --- a/FaceRecognitionDotNet/FaceRecognition.cs +++ b/FaceRecognitionDotNet/FaceRecognition.cs @@ -134,7 +134,7 @@ public class FaceRecognition : DisposableObject } } - public List FaceLocations(Image image, bool sortByNormalizedPixelPercentage) + public List FaceLocations(Image image) { if (image is null) throw new NullReferenceException(nameof(image)); @@ -150,14 +150,6 @@ public class FaceRecognition : DisposableObject mModRect.Dispose(); results.Add(location); } - if (sortByNormalizedPixelPercentage) - { - results = (from l in results orderby l.NormalizedPixelPercentage select l).ToList(); - int?[] normalizedPixelPercentageCollection = Shared.Models.Stateless.Methods.ILocation.GetInts(results); - int normalizedPixelPercentageDistinctCount = normalizedPixelPercentageCollection.Distinct().Count(); - if (normalizedPixelPercentageDistinctCount != normalizedPixelPercentageCollection.Length) - throw new Exception("Not distinct!"); - } return results; } @@ -187,7 +179,7 @@ public class FaceRecognition : DisposableObject return results; } - private List GetLocations(Image image, bool sortByNormalizedPixelPercentage) + private List GetLocations(Image image) { List results = new(); MModRect[] mModRects = GetMModRects(image); @@ -203,33 +195,25 @@ public class FaceRecognition : DisposableObject results.Add(location); } } - if (sortByNormalizedPixelPercentage) - { - results = (from l in results orderby l.NormalizedPixelPercentage select l).ToList(); - int?[] normalizedPixelPercentageCollection = Shared.Models.Stateless.Methods.ILocation.GetInts(results); - int normalizedPixelPercentageDistinctCount = normalizedPixelPercentageCollection.Distinct().Count(); - if (normalizedPixelPercentageDistinctCount != normalizedPixelPercentageCollection.Length) - throw new Exception("Not distinct!"); - } return results; } - public List<(int, Location, FaceEncoding?, Dictionary?)> GetCollection(Image image, bool includeFaceEncoding, bool includeFaceParts, bool sortByNormalizedPixelPercentage) + public List<(Location, FaceEncoding?, Dictionary?)> GetCollection(Image image, bool includeFaceEncoding, bool includeFaceParts) { - List<(int, Location, FaceEncoding?, Dictionary?)> results = new(); + List<(Location, FaceEncoding?, Dictionary?)> results = new(); if (image is null) throw new NullReferenceException(nameof(image)); image.ThrowIfDisposed(); ThrowIfDisposed(); if (_PredictorModel == PredictorModel.Custom) throw new NotSupportedException("FaceRecognition.PredictorModel.Custom is not supported."); - List locations = GetLocations(image, sortByNormalizedPixelPercentage); + List locations = GetLocations(image); List fullObjectDetections = GetFullObjectDetections(image, locations); if (fullObjectDetections.Count != locations.Count) throw new Exception(); - List<(int LocationIndex, Location Location, List FaceEncodings, List> FaceParts)> collection = new(); - for (int i = 0; i < locations.Count; i++) - collection.Add(new(i, locations[i], new(), new())); + List<(Location Location, List FaceEncodings, List> FaceParts)> collection = new(); + foreach (Location location in locations) + collection.Add(new(location, new(), new())); if (locations.Count != collection.Count) throw new Exception(); if (!includeFaceEncoding) @@ -266,18 +250,18 @@ public class FaceRecognition : DisposableObject fullObjectDetection.Dispose(); const int indexZero = 0; Dictionary keyValuePairs; - foreach ((int locationIndex, Location location, List faceEncodings, List> faceParts) in collection) + foreach ((Location location, List faceEncodings, List> faceParts) in collection) { if (faceEncodings.Count != 1 || faceParts.Count != 1) continue; if (!faceParts[indexZero].Any()) - results.Add(new(locationIndex, location, faceEncodings[indexZero], null)); + results.Add(new(location, faceEncodings[indexZero], null)); else { keyValuePairs = new(); foreach ((FacePart facePart, FacePoint[] facePoints) in faceParts[indexZero]) keyValuePairs.Add(facePart, facePoints); - results.Add(new(locationIndex, location, faceEncodings[indexZero], keyValuePairs)); + results.Add(new(location, faceEncodings[indexZero], keyValuePairs)); } } return results; diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index e42141d..a4462da 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -28,6 +28,7 @@ public partial class DlibDotNet private readonly F_Random _Random; private readonly E3_Rename _Rename; private readonly IConsole _Console; + private readonly E_Distance _Distance; private readonly B_Metadata _Metadata; private readonly Serilog.ILogger? _Log; private readonly D2_FaceParts _FaceParts; @@ -67,10 +68,19 @@ public partial class DlibDotNet Verify(configuration); VerifyExtra(args, propertyConfiguration, configuration); _Configuration = configuration; - _Index = new G_Index(configuration); - _Random = new F_Random(configuration); + _Index = new(configuration); + _Random = new(configuration); + _Rename = new(configuration); _MapConfiguration = Get(configuration); - _Rename = new E3_Rename(configuration); + _Distance = new( + configuration.DistanceMoveUnableToMatch, + configuration.DistancePixelDistanceTolerance, + configuration.FaceDistanceMinimumConfidence, + configuration.FaceDistancePermyriad, + configuration.FaceDistanceTolerance, + configuration.PropertyConfiguration.ResultAllInOne, + configuration.SortingDaysDeltaTolerance, + configuration.SortingMaximumPerFaceShouldBeHigh); if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions)); string propertyRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(propertyConfiguration, nameof(A_Property), create: false); @@ -95,13 +105,12 @@ public partial class DlibDotNet hiddenFileNameExtension, hiddenImageCodecInfo, imageCodecInfo, - configuration.LocationDigits, - configuration.LocationFactor, model, modelParameter, configuration.NumberOfJitters, configuration.NumberOfTimesToUpsample, configuration.OverrideForFaceImages, + configuration.RetryImagesWithoutAFace, predictorModel, configuration.PropertiesChangedForFaces); } @@ -323,11 +332,9 @@ public partial class DlibDotNet configuration.FaceDistancePermyriad, configuration.FaceDistanceMinimumConfidence, configuration.FaceDistanceTolerance, - configuration.LocationDigits, - configuration.LocationFactor, configuration.MapLogicSigma, configuration.MappingDefaultName, - configuration.MappingMoveUnableToMatch, + configuration.DistanceMoveUnableToMatch, configuration.MappingSaveNotMapped, configuration.MappingSaveMapped, configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping, @@ -342,22 +349,7 @@ public partial class DlibDotNet return result; } - private void FullParallelForWork( - A_Property propertyLogic, - string outputResolution, - string bResultsFullGroupDirectory, - string cResultsFullGroupDirectory, - string dResultsFullGroupDirectory, - string d2ResultsFullGroupDirectory, - List> sourceDirectoryChanges, - List propertyFileHolderCollection, - List propertyCollection, - List>> metadataCollections, - List> resizeKeyValuePairs, - List?> imageFaceCollections, - Container container, - int index, - Item item) + private void FullParallelForWork(A_Property propertyLogic, string[] mappedFaceFiles, string outputResolution, string bResultsFullGroupDirectory, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string eDistanceContentDirectory, List> sourceDirectoryChanges, List propertyFileHolderCollection, List propertyCollection, List>> metadataCollections, List> resizeKeyValuePairs, List?> imageFaceCollections, List duplicateMappedFaceFilesCollection, Container container, int index, Item item) { if (item.ImageFileHolder is null) throw new NullReferenceException(nameof(item.ImageFileHolder)); @@ -366,8 +358,8 @@ public partial class DlibDotNet Shared.Models.Property property; long ticks = DateTime.Now.Ticks; DateTime dateTime = DateTime.Now; + List? faces; List parseExceptions = new(); - List? faceCollection; Dictionary imageResizeKeyValuePairs; List> subFileTuples = new(); List> metadataCollection; @@ -420,46 +412,35 @@ public partial class DlibDotNet File.WriteAllBytes(path, bytes); } if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution)) - faceCollection = null; + faces = null; else { int[] outputResolutionCollection = imageResizeKeyValuePairs[outputResolution]; int outputResolutionWidth = outputResolutionCollection[0]; int outputResolutionHeight = outputResolutionCollection[1]; int outputResolutionOrientation = outputResolutionCollection[2]; - faceCollection = _Faces.GetFaces( - dResultsFullGroupDirectory, - subFileTuples, - parseExceptions, - item, - property, - outputResolutionWidth, - outputResolutionHeight, - outputResolutionOrientation); + faces = _Faces.GetFaces(dResultsFullGroupDirectory, subFileTuples, parseExceptions, item, property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation); if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(D_Face.GetFaces)); - _Faces.SaveFaces(dResultsFullGroupDirectory, subFileTuples, parseExceptions, item, faceCollection); + _Faces.SaveFaces(dResultsFullGroupDirectory, subFileTuples, parseExceptions, item, faces); if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(D_Face.SaveFaces)); - int?[] normalizedPixelPercentageCollection = Shared.Models.Stateless.Methods.IFace.GetInts(faceCollection); - int normalizedPixelPercentageDistinctCount = normalizedPixelPercentageCollection.Distinct().Count(); - if (normalizedPixelPercentageDistinctCount != normalizedPixelPercentageCollection.Length || _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) + _ = _Distance.GetUnableToMatchCountAndRenameMatches(_Faces.FileNameExtension, eDistanceContentDirectory, duplicateMappedFaceFilesCollection, item, faces, mappedFaceFiles); + if (_Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) { - - bool saveRotated = _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution); - string sourceDirectorySegment = Property.Models.Stateless.IResult.GetRelativePath( - _Configuration.PropertyConfiguration, - container.SourceDirectory); - string facesDirectory = Path.GetFullPath(Path.Combine($"{Path.Combine(d2ResultsFullGroupDirectory, "()")}{sourceDirectorySegment}", item.ImageFileHolder.NameWithoutExtension)); - _FaceParts.SaveFaceLandmarkImages(facesDirectory, subFileTuples, parseExceptions, item, faceCollection, saveRotated); - if (_AppSettings.MaxDegreeOfParallelism < 2) - ticks = LogDelta(ticks, nameof(D2_FaceParts.SaveFaceLandmarkImages)); + throw new NotImplementedException(); + // bool saveRotated = _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution); + // string sourceDirectorySegment = Property.Models.Stateless.IResult.GetRelativePath(_Configuration.PropertyConfiguration, container.SourceDirectory); + // string facesDirectory = Path.GetFullPath(Path.Combine($"{Path.Combine(d2FacePartsContentDirectory, "()")}{sourceDirectorySegment}", item.ImageFileHolder.NameWithoutExtension)); + // _FaceParts.SaveFaceLandmarkImages(facesDirectory, subFileTuples, parseExceptions, item, faceCollection, saveRotated); + // if (_AppSettings.MaxDegreeOfParallelism < 2) + // ticks = LogDelta(ticks, nameof(D2_FaceParts.SaveFaceLandmarkImages)); } } lock (sourceDirectoryChanges) { + imageFaceCollections[index] = faces; propertyCollection[index] = property; - imageFaceCollections[index] = faceCollection; metadataCollections[index] = metadataCollection; resizeKeyValuePairs[index] = imageResizeKeyValuePairs; propertyFileHolderCollection[index] = item.ImageFileHolder; @@ -467,23 +448,7 @@ public partial class DlibDotNet } } - private int FullParallelWork( - int maxDegreeOfParallelism, - A_Property propertyLogic, - string outputResolution, - string bResultsFullGroupDirectory, - string cResultsFullGroupDirectory, - string dResultsFullGroupDirectory, - string d2ResultsFullGroupDirectory, - List> sourceDirectoryChanges, - List propertyFileHolderCollection, - List propertyCollection, - List>> metadataCollection, - List> resizeKeyValuePairs, - List?> imageFaceCollections, - Container container, - Item[] filteredItems, - string message) + private int FullParallelWork(int maxDegreeOfParallelism, A_Property propertyLogic, string[] mappedFaceFiles, string outputResolution, string bResultsFullGroupDirectory, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string eDistanceContentDirectory, List> sourceDirectoryChanges, List propertyFileHolderCollection, List propertyCollection, List>> metadataCollection, List> resizeKeyValuePairs, List?> imageFaceCollections, List duplicateMappedFaceFilesCollection, Container container, Item[] filteredItems, string message) { if (_Log is null) throw new NullReferenceException(nameof(_Log)); @@ -511,17 +476,19 @@ public partial class DlibDotNet { FullParallelForWork( propertyLogic, + mappedFaceFiles, outputResolution, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, - d2ResultsFullGroupDirectory, + eDistanceContentDirectory, sourceDirectoryChanges, propertyFileHolderCollection, propertyCollection, metadataCollection, resizeKeyValuePairs, imageFaceCollections, + duplicateMappedFaceFilesCollection, container, index: i, filteredItems[i]); @@ -595,9 +562,9 @@ public partial class DlibDotNet if (!(from l in propertyCollection where l?.Width is null select true).Any()) { string checkDirectory; - List?>> imageFaceCollectionsKeyValuePairs = new(); List> propertyCollectionKeyValuePairs = new(); List>> resizeKeyValuePairsCollections = new(); + List?>> imageFaceCollectionsKeyValuePairs = new(); List>>> metadataCollectionKeyValuePairs = new(); (int level, List directories) = Shared.Models.Stateless.Methods.IPath.Get( _Configuration.PropertyConfiguration.RootDirectory, @@ -616,9 +583,9 @@ public partial class DlibDotNet _FileKeyValuePairs.Add(new KeyValuePair(container.SourceDirectory, key)); _FilePropertiesKeyValuePairs[container.SourceDirectory].Add(new Tuple(key, propertyCollection[i])); } - imageFaceCollectionsKeyValuePairs.Add(new KeyValuePair?>(key, imageFaceCollections[i])); propertyCollectionKeyValuePairs.Add(new KeyValuePair(key, propertyCollection[i])); resizeKeyValuePairsCollections.Add(new KeyValuePair>(key, resizeKeyValuePairs[i])); + imageFaceCollectionsKeyValuePairs.Add(new KeyValuePair?>(key, imageFaceCollections[i])); metadataCollectionKeyValuePairs.Add(new KeyValuePair>>(key, metadataCollection[i])); } if (propertyLogic.AngleBracketCollection.Any()) @@ -664,10 +631,7 @@ public partial class DlibDotNet } } - private (string, string, string, string, string, string) GetResultsFullGroupDirectories( - Model? model, - PredictorModel? predictorModel, - string outputResolution) + private (string, string, string, string) GetResultsFullGroupDirectories(Model? model, PredictorModel? predictorModel, string outputResolution) { string aResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( _Configuration.PropertyConfiguration, @@ -705,25 +669,7 @@ public partial class DlibDotNet includeResizeGroup: true, includeModel: true, includePredictorModel: true); - string d2ResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( - _Configuration.PropertyConfiguration, - model, - predictorModel, - nameof(D2_FaceParts), - outputResolution, - includeResizeGroup: true, - includeModel: true, - includePredictorModel: true); - string eResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( - _Configuration.PropertyConfiguration, - model, - predictorModel, - nameof(E_Distance), - outputResolution, - includeResizeGroup: true, - includeModel: true, - includePredictorModel: true); - return new(aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, eResultsFullGroupDirectory); + return new(aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory); } private void SetAngleBracketCollections( @@ -733,8 +679,7 @@ public partial class DlibDotNet string aResultsFullGroupDirectory, string bResultsFullGroupDirectory, string cResultsFullGroupDirectory, - string dResultsFullGroupDirectory, - string d2ResultsFullGroupDirectory) + string dResultsFullGroupDirectory) { _Faces.AngleBracketCollection.Clear(); _Resize.AngleBracketCollection.Clear(); @@ -773,15 +718,6 @@ public partial class DlibDotNet singletonDescription: string.Empty, collectionDescription: "For each image a json file with all faces found", converted: true)); - if (_Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) - _ = Property.Models.Stateless.IResult.GetDirectoryInfoCollection( - _Configuration.PropertyConfiguration, - container.SourceDirectory, - d2ResultsFullGroupDirectory, - contentDescription: "n x 2 gif file(s) for each face found", - singletonDescription: string.Empty, - collectionDescription: string.Empty, - converted: false); } private Item[] GetFilterItems(Container container) @@ -798,15 +734,7 @@ public partial class DlibDotNet return results.ToArray(); } - private void FullDoWork( - string argZero, - Model? model, - PredictorModel? predictorModel, - string propertyRoot, - long ticks, - A_Property propertyLogic, - int t, - Container[] containers) + private void FullDoWork(string argZero, Model? model, PredictorModel? predictorModel, string propertyRoot, long ticks, A_Property propertyLogic, int t, Container[] containers, string eDistanceContentDirectory, string[] mappedFaceFiles) { if (_Log is null) throw new NullReferenceException(nameof(_Log)); @@ -820,33 +748,23 @@ public partial class DlibDotNet string bResultsFullGroupDirectory; string cResultsFullGroupDirectory; string dResultsFullGroupDirectory; - string eResultsFullGroupDirectory; - string d2ResultsFullGroupDirectory; int containersLength = containers.Length; Shared.Models.Property[] propertyCollection; - List?> imageFaceCollections = new(); List propertyFileHolderCollection = new(); + List duplicateMappedFaceFilesCollection = new(); List> resizeKeyValuePairs = new(); List> sourceDirectoryChanges = new(); + List?> imageFaceCollections = new(); List nullablePropertyCollection = new(); int maxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism; List>> metadataCollection = new(); - string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), "{}"); foreach (string outputResolution in _Configuration.OutputResolutions) { total = 0; _FileKeyValuePairs.Clear(); + duplicateMappedFaceFilesCollection.Clear(); _FilePropertiesKeyValuePairs.Clear(); - (aResultsFullGroupDirectory, - bResultsFullGroupDirectory, - cResultsFullGroupDirectory, - dResultsFullGroupDirectory, - d2ResultsFullGroupDirectory, - eResultsFullGroupDirectory) = GetResultsFullGroupDirectories( - model, - predictorModel, - outputResolution); - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(eResultsFullGroupDirectory, "()")); + (aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory) = GetResultsFullGroupDirectories(model, predictorModel, outputResolution); for (int i = 0; i < containers.Length; i++) { container = containers[i]; @@ -865,21 +783,23 @@ public partial class DlibDotNet propertyFileHolderCollection.Clear(); totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); message = $"{i + 1:000}.{container.G} [{filteredItems.Length:000} files] / {containersLength:000} - {total} / {t} total files - {totalSeconds} total second(s) - {outputResolution} - {container.SourceDirectory}"; - SetAngleBracketCollections(propertyLogic, outputResolution, container, aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory); + SetAngleBracketCollections(propertyLogic, outputResolution, container, aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory); exceptionCount = FullParallelWork( maxDegreeOfParallelism, propertyLogic, + mappedFaceFiles, outputResolution, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, - d2ResultsFullGroupDirectory, + eDistanceContentDirectory, sourceDirectoryChanges, propertyFileHolderCollection, nullablePropertyCollection, metadataCollection, resizeKeyValuePairs, imageFaceCollections, + duplicateMappedFaceFilesCollection, container, filteredItems, message); @@ -916,6 +836,11 @@ public partial class DlibDotNet // break; total += container.Items.Count; } + foreach (string[] duplicateMappedFaceFiles in duplicateMappedFaceFilesCollection) + { + foreach (string duplicateMappedFaceFile in duplicateMappedFaceFiles) + _Log.Information(duplicateMappedFaceFile); + } } } @@ -926,9 +851,10 @@ public partial class DlibDotNet bool? isWrongYear; Item[] filteredItems; DateTime minimumDateTime; + int normalizedPixelPercentage; + string deterministicHashCodeKey; MappingFromItem mappingFromItem; MappingFromPerson mappingFromPerson; - string deterministicHashCodeKeyDisplay; MappingFromLocation mappingFromLocation; foreach (Container container in containers) { @@ -949,14 +875,15 @@ public partial class DlibDotNet { if (face.RelativePath != item.RelativePath) break; - if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) + if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null) continue; minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); (isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime); mappingFromItem = new(item.Property.Id.Value, item.ImageFileHolder, isWrongYear, minimumDateTime, item.ResizedFileHolder); mappingFromPerson = new(approximateYears: null, by: null, displayDirectoryName: string.Empty, personBirthday: null, segmentB: string.Empty); - deterministicHashCodeKeyDisplay = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, face.Location.NormalizedPixelPercentage.Value); - mappingFromLocation = new(face.Location.Confidence, deterministicHashCodeKeyDisplay, face.Location.NormalizedPixelPercentage.Value); + normalizedPixelPercentage = Shared.Models.Stateless.Methods.ILocation.GetNormalizedPixelPercentage(face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, face.OutputResolution); + deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, face.OutputResolution); + mappingFromLocation = new(face.Location.Confidence, deterministicHashCodeKey, normalizedPixelPercentage); mapping = new(mappingFromItem, mappingFromLocation, mappingFromPerson); face.SetMapping(mapping); results.Add(face); @@ -972,21 +899,15 @@ public partial class DlibDotNet PersonContainer[] personContainers, Container[] containers, string dResultsFullGroupDirectory, - string eResultsFullGroupDirectory, - string d2ResultsFullGroupDirectory, string outputResolution) { - E_Distance distance = new(); - if (string.IsNullOrEmpty(eResultsFullGroupDirectory)) - throw new NullReferenceException(nameof(eResultsFullGroupDirectory)); - string eDistanceContentDirectory = Path.Combine(eResultsFullGroupDirectory, "()"); + string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, "()"); List distinctFilteredFaces = SetMappingThenGetDistinctFilteredFacesWithMapping(argZero, containers); - List selectedFilteredFaces = E_Distance.GetSelectedFilteredFaces(distinctFilteredFaces); + Shared.Models.Face[] selectedFilteredFaces = E_Distance.GetSelectedFilteredFaces(distinctFilteredFaces); E_Distance.SetFaceDistances(_AppSettings.MaxDegreeOfParallelism, ticks, selectedFilteredFaces); - string a2PeopleSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory( - _Configuration.PropertyConfiguration, - nameof(A2_People), - "{}"); + string eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), "()"); + string a2PeopleSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "{}"); + string d2FacePartsContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(D2_FaceParts), "()"); MapLogic mapLogic = new( _AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, @@ -996,33 +917,32 @@ public partial class DlibDotNet _FaceParts.FileNameExtension, ticks, personContainers, - eDistanceContentDirectory, a2PeopleSingletonDirectory, + eDistanceContentDirectory, distinctFilteredFaces, - distance); - SortingContainer[] sortingContainers = E_Distance.SetFaceMappingSortingCollectionThenGetSortingContainers( + _Distance); + SortingContainer[] sortingContainers = _Distance.SetFaceMappingSortingCollectionThenGetSortingContainers( _AppSettings.MaxDegreeOfParallelism, - _MapConfiguration, ticks, mapLogic, selectedFilteredFaces); - E_Distance.SaveFaceDistances(_Configuration.PropertyConfiguration, eResultsFullGroupDirectory, sortingContainers); + E_Distance.SaveFaceDistances(_Configuration.PropertyConfiguration, sortingContainers); int totalNotMapped = mapLogic.AddToMapping(distinctFilteredFaces); if (totalNotMapped > 0) mapLogic.ForceSingleImageThenSaveMapping( - dResultsFullGroupDirectory, - d2ResultsFullGroupDirectory, + dFacesContentDirectory, + d2FacePartsContentDirectory, distinctFilteredFaces, sortingContainers, totalNotMapped); - mapLogic.CopyManualFiles(dResultsFullGroupDirectory, distinctFilteredFaces); + mapLogic.CopyManualFiles(dFacesContentDirectory, distinctFilteredFaces); if (_MapConfiguration.MappingSaveNotMapped) mapLogic.SaveNotMappedTicks(); if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) mapLogic.SaveShortcuts(_Configuration.JuliePhares, distinctFilteredFaces); } - private static Container? AreAllSameStartsWith(string argZero, Container[] containers) + private static Container? AreAllSameEndsWith(string argZero, Container[] containers) { Container? result = null; string[] directoryNames = Shared.Models.Stateless.Methods.IPath.GetDirectoryNames(argZero); @@ -1037,7 +957,7 @@ public partial class DlibDotNet if (container.SourceDirectory == argZero) result = container; directoryName = Path.GetFileName(container.SourceDirectory); - if (!directoryName.StartsWith(rootDirectoryName)) + if (!directoryName.EndsWith(rootDirectoryName)) { result = null; break; @@ -1088,13 +1008,7 @@ public partial class DlibDotNet return result; } - private void Search( - long ticks, - Model? model, - PredictorModel? predictorModel, - string argZero, - string propertyRoot, - PersonContainer[] personContainers) + private void Search(long ticks, Model? model, PredictorModel? predictorModel, string argZero, string propertyRoot, PersonContainer[] personContainers) { int j; int f; @@ -1104,8 +1018,13 @@ public partial class DlibDotNet string bResultsFullGroupDirectory; string cResultsFullGroupDirectory; string dResultsFullGroupDirectory; - string eResultsFullGroupDirectory; - string d2ResultsFullGroupDirectory; + string eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), "()"); + string[] mappedFaceFiles = Map.Models.Stateless.Methods.IMapLogic.DeleteEmptyDirectoriesAndGetMappedFaceFiles( + _MapConfiguration, + _Faces.FileNameExtension, + ticks, + eDistanceContentDirectory, + personContainers); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); string message = $") Building Container(s) - {totalSeconds} total second(s)"; A_Property propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, model, predictorModel); @@ -1115,7 +1034,7 @@ public partial class DlibDotNet progressBar.Tick(); (j, f, t, containers) = Property.Models.Stateless.Container.GetContainers(_Configuration.PropertyConfiguration, _FirstRun, propertyLogic); } - Container? container = AreAllSameStartsWith(argZero, containers); + Container? container = AreAllSameEndsWith(argZero, containers); if (_ArgZeroIsConfigurationRootDirectory && container is not null) { string? newRootDirectory = SaveUrlAndGetNewRootDirectory(container); @@ -1138,20 +1057,12 @@ public partial class DlibDotNet model, predictorModel); } - FullDoWork(argZero, model, predictorModel, propertyRoot, ticks, propertyLogic, t, containers); + FullDoWork(argZero, model, predictorModel, propertyRoot, ticks, propertyLogic, t, containers, eDistanceContentDirectory, mappedFaceFiles); foreach (string outputResolution in _Configuration.OutputResolutions) { if (_FirstRun || container is not null) break; - (aResultsFullGroupDirectory, - bResultsFullGroupDirectory, - cResultsFullGroupDirectory, - dResultsFullGroupDirectory, - d2ResultsFullGroupDirectory, - eResultsFullGroupDirectory) = GetResultsFullGroupDirectories( - model, - predictorModel, - outputResolution); + (aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory) = GetResultsFullGroupDirectories(model, predictorModel, outputResolution); if (_ArgZeroIsConfigurationRootDirectory && _Configuration.SaveResizedSubfiles && outputResolution == _Configuration.OutputResolutions[0] @@ -1160,15 +1071,7 @@ public partial class DlibDotNet { if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Any()) break; - DistanceThenMapLogic( - argZero, - ticks, - personContainers, - containers, - dResultsFullGroupDirectory, - eResultsFullGroupDirectory, - d2ResultsFullGroupDirectory, - outputResolution); + DistanceThenMapLogic(argZero, ticks, personContainers, containers, dResultsFullGroupDirectory, outputResolution); if (_IsEnvironment.Development) continue; if (_FileKeyValuePairs.Any()) @@ -1194,10 +1097,6 @@ public partial class DlibDotNet _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(cResultsFullGroupDirectory, "{}")); if (_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution)) _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(dResultsFullGroupDirectory, "[]")); - if (_Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution)) - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(eResultsFullGroupDirectory, "[]")); - if (_Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(d2ResultsFullGroupDirectory, "[]")); } } } diff --git a/Instance/Models/Binder/Configuration.cs b/Instance/Models/Binder/Configuration.cs index 035a5bc..12b1eba 100644 --- a/Instance/Models/Binder/Configuration.cs +++ b/Instance/Models/Binder/Configuration.cs @@ -14,6 +14,8 @@ public class Configuration [Display(Name = "Check Json For Distance Results"), Required] public bool? CheckJsonForDistanceResults { get; set; } [Display(Name = "CrossDirectory Max Items In Distance Collection"), Required] public int? CrossDirectoryMaxItemsInDistanceCollection { get; set; } [Display(Name = "Distance Factor"), Required] public int? DistanceFactor { get; set; } + [Display(Name = "Distance Move Unable to Match by 1 Tick"), Required] public bool? DistanceMoveUnableToMatch { get; set; } + [Display(Name = "Distance Pixel Distance Tolerance"), Required] public int? DistancePixelDistanceTolerance { get; set; } [Display(Name = "Face Distance Hidden Image Factor"), Required] public int? FaceDistanceHiddenImageFactor { get; set; } [Display(Name = "Location Minimum Confidence"), Required] public double? FaceDistanceMinimumConfidence { get; set; } [Display(Name = "Face Distance Permyriad"), Required] public int? FaceDistancePermyriad { get; set; } @@ -33,7 +35,6 @@ public class Configuration [Display(Name = "Map Logic Sigma"), Required] public int? MapLogicSigma { get; set; } [Display(Name = "Mapped Max Index"), Required] public int? MappedMaxIndex { get; set; } [Display(Name = "Mapping Default Name"), Required] public string MappingDefaultName { get; set; } - [Display(Name = "Mapping Move Unable to Match by 1 Tick"), Required] public bool? MappingMoveUnableToMatch { get; set; } [Display(Name = "Mapping Save Mapped"), Required] public bool? MappingSaveMapped { get; set; } [Display(Name = "Mapping Save Not Mapped"), Required] public bool? MappingSaveNotMapped { get; set; } [Display(Name = "Mapping Use Deterministic Hash Code Unknown Face Key Value Pairs for Add to Mapping"), Required] public bool? MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping { get; set; } @@ -61,6 +62,7 @@ public class Configuration [Display(Name = "Properties Changed For Metadata"), Required] public bool? PropertiesChangedForMetadata { get; set; } [Display(Name = "Properties Changed For Resize"), Required] public bool? PropertiesChangedForResize { get; set; } [Display(Name = "Property Configuration"), Required] public Property.Models.Configuration PropertyConfiguration { get; set; } + [Display(Name = "Retry Images Without a Face"), Required] public bool? RetryImagesWithoutAFace { get; set; } [Display(Name = "Reverse"), Required] public bool? Reverse { get; set; } [Display(Name = "Save Face Landmark For Output Resolutions"), Required] public string[] SaveFaceLandmarkForOutputResolutions { get; set; } [Display(Name = "Save Full Year Of Random Files"), Required] public bool? SaveFullYearOfRandomFiles { get; set; } @@ -93,6 +95,10 @@ public class Configuration throw new NullReferenceException(nameof(configuration.CrossDirectoryMaxItemsInDistanceCollection)); if (configuration.DistanceFactor is null) throw new NullReferenceException(nameof(configuration.DistanceFactor)); + if (configuration.DistanceMoveUnableToMatch is null) + throw new NullReferenceException(nameof(configuration.DistanceMoveUnableToMatch)); + if (configuration.DistancePixelDistanceTolerance is null) + throw new NullReferenceException(nameof(configuration.DistancePixelDistanceTolerance)); if (configuration.FaceDistanceHiddenImageFactor is null) throw new NullReferenceException(nameof(configuration.FaceDistanceHiddenImageFactor)); if (configuration.FaceDistanceMinimumConfidence is null) @@ -127,8 +133,6 @@ public class Configuration throw new NullReferenceException(nameof(configuration.MapLogicSigma)); if (configuration.MappingDefaultName is null) throw new NullReferenceException(nameof(configuration.MappingDefaultName)); - if (configuration.MappingMoveUnableToMatch is null) - throw new NullReferenceException(nameof(configuration.MappingMoveUnableToMatch)); if (configuration.MappingSaveNotMapped is null) throw new NullReferenceException(nameof(configuration.MappingSaveNotMapped)); if (configuration.MappingSaveMapped is null) @@ -173,6 +177,8 @@ public class Configuration throw new NullReferenceException(nameof(configuration.PropertiesChangedForMetadata)); if (configuration.PropertiesChangedForResize is null) throw new NullReferenceException(nameof(configuration.PropertiesChangedForResize)); + if (configuration.RetryImagesWithoutAFace is null) + throw new NullReferenceException(nameof(configuration.RetryImagesWithoutAFace)); if (configuration.Reverse is null) throw new NullReferenceException(nameof(configuration.Reverse)); if (configuration.SaveFaceLandmarkForOutputResolutions is null) @@ -212,6 +218,8 @@ public class Configuration configuration.CheckJsonForDistanceResults.Value, configuration.CrossDirectoryMaxItemsInDistanceCollection.Value, configuration.DistanceFactor.Value, + configuration.DistanceMoveUnableToMatch.Value, + configuration.DistancePixelDistanceTolerance.Value, configuration.FaceDistanceHiddenImageFactor.Value, configuration.FaceDistanceMinimumConfidence.Value, configuration.FaceDistancePermyriad.Value, @@ -231,7 +239,6 @@ public class Configuration configuration.MapLogicSigma.Value, configuration.MappedMaxIndex, configuration.MappingDefaultName, - configuration.MappingMoveUnableToMatch.Value, configuration.MappingSaveNotMapped.Value, configuration.MappingSaveMapped.Value, configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping.Value, @@ -258,6 +265,7 @@ public class Configuration configuration.PropertiesChangedForIndex.Value, configuration.PropertiesChangedForMetadata.Value, configuration.PropertiesChangedForResize.Value, + configuration.RetryImagesWithoutAFace.Value, configuration.Reverse.Value, configuration.SaveFaceLandmarkForOutputResolutions, configuration.SaveFullYearOfRandomFiles.Value, diff --git a/Instance/Models/Configuration.cs b/Instance/Models/Configuration.cs index 0976a7a..7af41ed 100644 --- a/Instance/Models/Configuration.cs +++ b/Instance/Models/Configuration.cs @@ -13,6 +13,8 @@ public class Configuration public bool CheckJsonForDistanceResults { init; get; } public int CrossDirectoryMaxItemsInDistanceCollection { init; get; } public int DistanceFactor { init; get; } + public bool DistanceMoveUnableToMatch { init; get; } + public int DistancePixelDistanceTolerance { init; get; } public int FaceDistanceHiddenImageFactor { init; get; } public double FaceDistanceMinimumConfidence { init; get; } public int FaceDistancePermyriad { init; get; } @@ -32,7 +34,6 @@ public class Configuration public int MapLogicSigma { init; get; } public int? MappedMaxIndex { init; get; } public string MappingDefaultName { init; get; } - public bool MappingMoveUnableToMatch { init; get; } public bool MappingSaveNotMapped { init; get; } public bool MappingSaveMapped { init; get; } public bool MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping { init; get; } @@ -59,6 +60,7 @@ public class Configuration public bool PropertiesChangedForIndex { init; get; } public bool PropertiesChangedForMetadata { init; get; } public bool PropertiesChangedForResize { init; get; } + public bool RetryImagesWithoutAFace { init; get; } public bool Reverse { init; get; } public string[] SaveFaceLandmarkForOutputResolutions { init; get; } public bool SaveFullYearOfRandomFiles { init; get; } @@ -78,6 +80,8 @@ public class Configuration bool checkJsonForDistanceResults, int crossDirectoryMaxItemsInDistanceCollection, int distanceFactor, + bool distanceMoveUnableToMatch, + int distancePixelDistanceTolerance, int faceDistanceHiddenImageFactor, double faceDistanceMinimumConfidence, int faceDistancePermyriad, @@ -97,7 +101,6 @@ public class Configuration int mapLogicSigma, int? mappedMaxIndex, string mappingDefaultName, - bool mappingMoveUnableToMatch, bool mappingSaveNotMapped, bool mappingSaveMapped, bool mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping, @@ -124,6 +127,7 @@ public class Configuration bool propertiesChangedForIndex, bool propertiesChangedForMetadata, bool propertiesChangedForResize, + bool retryImagesWithoutAFace, bool reverse, string[] saveFaceLandmarkForOutputResolutions, bool saveFullYearOfRandomFiles, @@ -142,6 +146,8 @@ public class Configuration CheckJsonForDistanceResults = checkJsonForDistanceResults; CrossDirectoryMaxItemsInDistanceCollection = crossDirectoryMaxItemsInDistanceCollection; DistanceFactor = distanceFactor; + DistanceMoveUnableToMatch = distanceMoveUnableToMatch; + DistancePixelDistanceTolerance = distancePixelDistanceTolerance; FaceDistanceHiddenImageFactor = faceDistanceHiddenImageFactor; FaceDistanceMinimumConfidence = faceDistanceMinimumConfidence; FaceDistancePermyriad = faceDistancePermyriad; @@ -161,7 +167,6 @@ public class Configuration MapLogicSigma = mapLogicSigma; MappedMaxIndex = mappedMaxIndex; MappingDefaultName = mappingDefaultName; - MappingMoveUnableToMatch = mappingMoveUnableToMatch; MappingSaveNotMapped = mappingSaveNotMapped; MappingSaveMapped = mappingSaveMapped; MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping = mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping; @@ -188,6 +193,7 @@ public class Configuration PropertiesChangedForIndex = propertiesChangedForIndex; PropertiesChangedForMetadata = propertiesChangedForMetadata; PropertiesChangedForResize = propertiesChangedForResize; + RetryImagesWithoutAFace = retryImagesWithoutAFace; Reverse = reverse; SaveFaceLandmarkForOutputResolutions = saveFaceLandmarkForOutputResolutions; SaveFullYearOfRandomFiles = saveFullYearOfRandomFiles; diff --git a/Instance/appsettings.Development.json b/Instance/appsettings.Development.json index 1c56fec..0b92c6f 100644 --- a/Instance/appsettings.Development.json +++ b/Instance/appsettings.Development.json @@ -55,6 +55,8 @@ "CrossDirectoryMaxItemsInDistanceCollection": 7, "DateGroup": "2022-09-22", "DistanceFactor": 8, + "DistanceMoveUnableToMatch": false, + "DistancePixelDistanceTolerance": 1, "FaceDistanceHiddenImageFactor": 2, "FaceDistanceMinimumConfidence": 0.8, "FaceDistancePermyriad": 10000, @@ -71,7 +73,6 @@ "MapLogicSigma": 3, "MappedMaxIndex": 1034720, "MappingDefaultName": "John Doe~25", - "MappingMoveUnableToMatch": false, "MappingSaveFaceEncoding": false, "MappingSaveMapped": false, "MappingSaveNotMapped": false, @@ -106,9 +107,11 @@ "ResultCollection": "[]", "ResultContent": "()", "ResultSingleton": "{}", + "RetryImagesWithoutAFace": false, "Reverse": false, "xRootDirectory": "C:/Tmp/phares/Pictures", "RootDirectory": "F:/Tmp/Phares/Compare/Images 2022-09-22 - fb1c68e - III", + "xxRootDirectory": "F:/Tmp/Phares/Compare/Images 2022-09-22 - fb1c68e - III/Facebook/=2022.3 Facebook", "SaveFullYearOfRandomFiles": true, "SaveResizedSubFiles": true, "SkipSearch": false, diff --git a/Instance/appsettings.Staging.json b/Instance/appsettings.Staging.json index 9f99d43..27159cd 100644 --- a/Instance/appsettings.Staging.json +++ b/Instance/appsettings.Staging.json @@ -55,6 +55,8 @@ "CrossDirectoryMaxItemsInDistanceCollection": 7, "DateGroup": "2022-09-22", "DistanceFactor": 8, + "DistanceMoveUnableToMatch": false, + "DistancePixelDistanceTolerance": 1, "FaceDistanceHiddenImageFactor": 2, "FaceDistanceMinimumConfidence": 0.8, "FaceDistancePermyriad": 10000, @@ -71,7 +73,6 @@ "MapLogicSigma": 3, "MappedMaxIndex": 1034720, "MappingDefaultName": "John Doe~25", - "MappingMoveUnableToMatch": false, "MappingSaveFaceEncoding": false, "MappingSaveMapped": false, "MappingSaveNotMapped": false, @@ -106,6 +107,7 @@ "ResultCollection": "[]", "ResultContent": "()", "ResultSingleton": "{}", + "RetryImagesWithoutAFace": false, "Reverse": false, "RootDirectory": "E:/Images", "SaveFullYearOfRandomFiles": true, diff --git a/Instance/appsettings.json b/Instance/appsettings.json index 9351574..991e6ae 100644 --- a/Instance/appsettings.json +++ b/Instance/appsettings.json @@ -55,6 +55,8 @@ "CrossDirectoryMaxItemsInDistanceCollection": 7, "DateGroup": "2022-09-22", "DistanceFactor": 8, + "DistanceMoveUnableToMatch": false, + "DistancePixelDistanceTolerance": 1, "FaceDistanceHiddenImageFactor": 2, "FaceDistanceMinimumConfidence": 0.8, "FaceDistancePermyriad": 10000, @@ -71,7 +73,6 @@ "MapLogicSigma": 3, "MappedMaxIndex": 1034720, "MappingDefaultName": "John Doe~25", - "MappingMoveUnableToMatch": false, "MappingSaveFaceEncoding": false, "MappingSaveMapped": false, "MappingSaveNotMapped": false, @@ -106,6 +107,7 @@ "ResultCollection": "[]", "ResultContent": "()", "ResultSingleton": "{}", + "RetryImagesWithoutAFace": false, "Reverse": false, "RootDirectory": "D:/Images", "SaveFullYearOfRandomFiles": true, diff --git a/Map/Models/Configuration.cs b/Map/Models/Configuration.cs index 33200f9..6fb48ee 100644 --- a/Map/Models/Configuration.cs +++ b/Map/Models/Configuration.cs @@ -10,11 +10,9 @@ public class Configuration public int FaceDistancePermyriad { init; get; } public double FaceDistanceMinimumConfidence { init; get; } public double FaceDistanceTolerance { init; get; } - public int LocationDigits { init; get; } - public int LocationFactor { init; get; } public int MapLogicSigma { init; get; } public string MappingDefaultName { init; get; } - public bool MappingMoveUnableToMatch { init; get; } + public bool DistanceMoveUnableToMatch { init; get; } public bool MappingSaveNotMapped { init; get; } public bool MappingSaveMapped { init; get; } public bool MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping { init; get; } @@ -32,11 +30,9 @@ public class Configuration int faceDistancePermyriad, double faceDistanceMinimumConfidence, double faceDistanceTolerance, - int locationDigits, - int locationFactor, int mapLogicSigma, string mappingDefaultName, - bool mappingMoveUnableToMatch, + bool distanceMoveUnableToMatch, bool mappingSaveNotMapped, bool mappingSaveMapped, bool mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping, @@ -53,11 +49,9 @@ public class Configuration FaceDistancePermyriad = faceDistancePermyriad; FaceDistanceMinimumConfidence = faceDistanceMinimumConfidence; FaceDistanceTolerance = faceDistanceTolerance; - LocationDigits = locationDigits; - LocationFactor = locationFactor; MapLogicSigma = mapLogicSigma; MappingDefaultName = mappingDefaultName; - MappingMoveUnableToMatch = mappingMoveUnableToMatch; + DistanceMoveUnableToMatch = distanceMoveUnableToMatch; MappingSaveNotMapped = mappingSaveNotMapped; MappingSaveMapped = mappingSaveMapped; MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping = mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping; diff --git a/Map/Models/MapLogic.cs b/Map/Models/MapLogic.cs index 2e4155b..7c96690 100644 --- a/Map/Models/MapLogic.cs +++ b/Map/Models/MapLogic.cs @@ -464,7 +464,7 @@ public class MapLogic } personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday); directory = Path.Combine(_EDistanceContentTicksDirectory, "Shortcuts", personKeyFormatted, subDirectoryName); - if (face.FaceEncoding is not null && face.Location?.NormalizedPixelPercentage is not null) + if (face.FaceEncoding is not null) copyDirectory = Path.Combine(_EDistanceContentTicksDirectory, "Images", personKeyFormatted, subDirectoryName); else copyDirectory = Path.Combine(_EDistanceContentTicksDirectory, "ImagesBut", personKeyFormatted, subDirectoryName); @@ -578,7 +578,7 @@ public class MapLogic } } - private List GetMappingSaveContainers(string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, List filteredFaces) + private List GetMappingSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, List filteredFaces) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); @@ -597,8 +597,6 @@ public class MapLogic FileHolder facePartsFileHolder; FileHolder hiddenFaceFileHolder; Dictionary keyValuePairs = new(); - string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, "()"); - string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, "()"); string forceSingleImageHumanized = nameof(Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title); foreach (Face face in filteredFaces) { @@ -652,20 +650,20 @@ public class MapLogic return results; } - public void ForceSingleImageThenSaveMapping(string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, List distinctFilteredFaces, SortingContainer[] sortingContainers, int totalNotMapped) + public void ForceSingleImageThenSaveMapping(string dFacesContentDirectory, string d2FacePartsContentDirectory, List distinctFilteredFaces, SortingContainer[] sortingContainers, int totalNotMapped) { List saveContainers; if (!sortingContainers.Any()) { ForceSingleImage(distinctFilteredFaces); - saveContainers = GetMappingSaveContainers(dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, distinctFilteredFaces); + saveContainers = GetMappingSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, distinctFilteredFaces); } else { int updated = UpdateFromSortingContainers(sortingContainers); if (totalNotMapped - updated > 0) ForceSingleImage(distinctFilteredFaces); - saveContainers = GetMappingSaveContainers(dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, distinctFilteredFaces); + saveContainers = GetMappingSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, distinctFilteredFaces); } SaveContainers(saveContainers); } @@ -688,7 +686,7 @@ public class MapLogic return results; } - public void CopyManualFiles(string dResultsFullGroupDirectory, List distinctFilteredFaces) + public void CopyManualFiles(string dFacesContentDirectory, List distinctFilteredFaces) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); @@ -714,7 +712,6 @@ public class MapLogic Dictionary? keyValuePairs; string by = nameof(Stateless.IMapLogic.ManualCopy); Dictionary? normalizedPixelPercentageToFace; - string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, "()"); string successfull = $"_ {nameof(Stateless.IMapLogic.ManualCopy).Humanize(LetterCasing.Title)} Successfull"; Dictionary> idToNormalizedPixelPercentageToFace = GetKeyValuePairs(distinctFilteredFaces); foreach (KeyValuePair keyValuePair in _PersonKeyToPersonContainer) @@ -726,7 +723,7 @@ public class MapLogic { if (!personDisplayDirectoryAllFile.EndsWith(_FacesFileNameExtension)) continue; - (id, normalizedPixelPercentage, _) = IMapping.GetReversedDeterministicHashCodeKey(_Configuration.LocationDigits, _FacesFileNameExtension, personDisplayDirectoryAllFile); + (id, normalizedPixelPercentage, _) = IMapping.GetReversedDeterministicHashCodeKey(Shared.Models.Stateless.ILocation.Digits, _FacesFileNameExtension, personDisplayDirectoryAllFile); if (id is null || normalizedPixelPercentage is null) continue; if (_IdThenNormalizedPixelPercentageToPersonContainers.TryGetValue(id.Value, out keyValuePairs)) diff --git a/Map/Models/Stateless/MapLogic.cs b/Map/Models/Stateless/MapLogic.cs index c6e1a34..ccb32ae 100644 --- a/Map/Models/Stateless/MapLogic.cs +++ b/Map/Models/Stateless/MapLogic.cs @@ -46,7 +46,7 @@ internal abstract class MapLogic { if (!personDisplayDirectoryAllFile.EndsWith(facesFileNameExtension)) continue; - (id, normalizedPixelPercentage, _) = IMapping.GetReversedDeterministicHashCodeKey(configuration.LocationDigits, facesFileNameExtension, personDisplayDirectoryAllFile); + (id, normalizedPixelPercentage, _) = IMapping.GetReversedDeterministicHashCodeKey(Shared.Models.Stateless.ILocation.Digits, facesFileNameExtension, personDisplayDirectoryAllFile); if (id is null || normalizedPixelPercentage is null) continue; if (!skipCollection.ContainsKey(id.Value)) @@ -73,7 +73,7 @@ internal abstract class MapLogic } } - internal static List<(string, string[], string)> DeleteEmptyDirectoriesAndGetCollection(Configuration configuration, string facesFileNameExtension, long ticks, string eDistanceContentDirectory, List personKeyFormattedCollection) + internal static List<(string, string[], string)> DeleteEmptyDirectoriesAndGetCollection(Configuration configuration, string facesFileNameExtension, List personKeyFormattedCollection, string[] ticksDirectories, string message) { List<(string, string[], string)> results = new(); int? id; @@ -91,10 +91,7 @@ internal abstract class MapLogic string? personFirstInitialDirectory; string[] personDisplayDirectoryNames; string manualCopyHumanized = nameof(IMapLogic.ManualCopy).Humanize(LetterCasing.Title); - int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); string forceSingleImageHumanized = nameof(IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title); - string[] ticksDirectories = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly); - string message = $") {ticksDirectories.Length:000} compile from and clean ticks Director(ies) - A - {totalSeconds} total second(s)"; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; using ProgressBar progressBar = new(ticksDirectories.Length, message, options); foreach (string ticksDirectory in ticksDirectories) @@ -151,7 +148,7 @@ internal abstract class MapLogic { if (file.EndsWith(".lnk") || file.EndsWith(".json")) continue; - (id, normalizedPixelPercentage, _) = IMapping.GetReversedDeterministicHashCodeKey(configuration.LocationDigits, facesFileNameExtension, file); + (id, normalizedPixelPercentage, _) = IMapping.GetReversedDeterministicHashCodeKey(Shared.Models.Stateless.ILocation.Digits, facesFileNameExtension, file); if (id is null || normalizedPixelPercentage is null) continue; results.Add(new(personKeyFormatted, personDisplayDirectoryNames, file)); @@ -180,6 +177,35 @@ internal abstract class MapLogic return results; } + internal static string[] DeleteEmptyDirectoriesAndGetMappedFaceFiles(Configuration configuration, string facesFileNameExtension, long ticks, string eDistanceContentDirectory, PersonContainer[] personContainers) + { + string[] results; + string personKeyFormatted; + List personKeyFormattedCollection = new(); + _ = GetDistinctCollection(configuration, personContainers.ToList(), new()); + int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + string[] ticksDirectories = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly); + string message = $") {ticksDirectories.Length:000} collect from and clean ticks Director(ies) - A - {totalSeconds} total second(s)"; + foreach (PersonContainer personContainer in personContainers) + { + if (personContainer.Person is null || personContainer.Key is null || personContainer.Birthdays is null || !personContainer.Birthdays.Any()) + continue; + foreach (PersonBirthday personBirthday in personContainer.Birthdays) + { + personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personBirthday); + personKeyFormattedCollection.Add(personKeyFormatted); + } + } + List<(string PersonKeyFormatted, string[] PersonDisplayDirectoryNames, string File)> collection = DeleteEmptyDirectoriesAndGetCollection( + configuration, + facesFileNameExtension, + personKeyFormattedCollection, + ticksDirectories, + message); + results = (from l in collection select l.File).ToArray(); + return results; + } + private static PersonContainer[] GetDistinctPersonContainers(List personContainers) { List results = new(); @@ -195,32 +221,14 @@ internal abstract class MapLogic private static void SetKeyValuePairs(Configuration configuration, long ticks, List personContainers, List distinctFilteredFaces, List<(string, string[], int, int)> personKeyFormattedIdThenNormalizedPixelPercentageCollection, List<(string, int, int)> incorrectPersonKeyFormattedIdThenNormalizedPixelPercentageCollection, Dictionary personKeyToPersonContainer, Dictionary> idThenNormalizedPixelPercentageToPersonContainers, List<(string[], PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer, Dictionary> incorrectIdThenNormalizedPixelPercentageToPersonContainers, Dictionary personKeyToRanges) { - const int zero = 0; PersonBirthday? personBirthday; - string newestPersonKeyFormatted; PersonContainer[] distinctPersonContainers; Dictionary personKeyFormattedToPersonContainer = new(); - Dictionary> personKeyToPersonContainerCollection = new(); Dictionary>> idThenNormalizedPixelPercentageToPersonContainerCollection = new(); Dictionary>> incorrectIdThenNormalizedPixelPercentageToPersonContainerCollection = new(); - foreach (PersonContainer personContainer in personContainers) - { - if (personContainer.Key is null) - continue; - if (!personKeyToPersonContainerCollection.ContainsKey(personContainer.Key.Value)) - personKeyToPersonContainerCollection.Add(personContainer.Key.Value, new()); - personKeyToPersonContainerCollection[personContainer.Key.Value].Add(personContainer); - newestPersonKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personContainer.Key.Value); - if (!personKeyFormattedToPersonContainer.ContainsKey(newestPersonKeyFormatted)) - personKeyFormattedToPersonContainer.Add(newestPersonKeyFormatted, personContainer); - } - - foreach (KeyValuePair> keyValuePair in personKeyToPersonContainerCollection) - { - if (keyValuePair.Value.Count != 1 && (from l in keyValuePair.Value select l.DisplayDirectoryName).Distinct().Count() != 1) - throw new NotImplementedException(); - personKeyToPersonContainer.Add(keyValuePair.Key, keyValuePair.Value[zero]); - } + List<(long, PersonContainer)> collection = GetDistinctCollection(configuration, personContainers, personKeyFormattedToPersonContainer); + foreach ((long personKey, PersonContainer personContainer) in collection) + personKeyToPersonContainer.Add(personKey, personContainer); if (personKeyFormattedIdThenNormalizedPixelPercentageCollection.Any()) { string personDisplayDirectory; @@ -291,104 +299,60 @@ internal abstract class MapLogic } } - private static string? GetCheckFile(Configuration configuration, string facesFileNameExtension, string file, int id, int normalizedPixelPercentage) + private static List<(long, PersonContainer)> GetDistinctCollection(Configuration configuration, List personContainers, Dictionary personKeyFormattedToPersonContainer) { - string? result; - string fileName = Path.GetFileName(file); - string? directoryName = Path.GetDirectoryName(file); - (string? Id, string? NormalizedPixelPercentage, string? ExtensionLowered, bool? Check) segments = IMapping.GetSegments(configuration.LocationDigits, facesFileNameExtension, fileName); - if (string.IsNullOrEmpty(directoryName) || string.IsNullOrEmpty(segments.Id) || string.IsNullOrEmpty(segments.NormalizedPixelPercentage) || string.IsNullOrEmpty(segments.ExtensionLowered)) - result = null; - else - result = Path.Combine(directoryName, $"{IMapping.GetDeterministicHashCodeKey(id, normalizedPixelPercentage)}{segments.ExtensionLowered}.json"); - return result; - } - - private static void MoveUnableToMatch(Configuration configuration, string eDistanceContentDirectory, string file, string jsonFile) - { - bool result; - string? fileName = Path.GetFileName(file); - string? jsonFileName = Path.GetFileName(jsonFile); - if (fileName is null || jsonFileName is null) - result = false; - else + List<(long, PersonContainer)> results = new(); + const int zero = 0; + string newestPersonKeyFormatted; + Dictionary> personKeyToPersonContainerCollection = new(); + foreach (PersonContainer personContainer in personContainers) { - string? directoryName = Path.GetDirectoryName(jsonFile); - string? jsonDirectoryName = Path.GetDirectoryName(jsonFile); - if (string.IsNullOrEmpty(directoryName) || string.IsNullOrEmpty(directoryName) || directoryName != jsonDirectoryName || !directoryName.Contains(eDistanceContentDirectory)) - result = false; - else - { - List directoryNames = new(); - string? checkDirectoryName = directoryName; - for (int i = 0; i < int.MaxValue; i++) - { - if (string.IsNullOrEmpty(checkDirectoryName)) - continue; - directoryNames.Add(Path.GetFileName(checkDirectoryName)); - checkDirectoryName = Path.GetDirectoryName(checkDirectoryName); - if (string.IsNullOrEmpty(checkDirectoryName)) - continue; - if (checkDirectoryName == eDistanceContentDirectory) - break; - } - if (string.IsNullOrEmpty(checkDirectoryName) || !directoryNames.Any() || !long.TryParse(directoryNames[^1][1..^1], out long directoryTicks)) - { - result = false; - File.Delete(jsonFile); - File.Delete(file); - } - else - { - bool jsonFileExists = File.Exists(jsonFile); - if (!jsonFileExists) - checkDirectoryName = Path.Combine(checkDirectoryName, $"({directoryTicks}.00)"); - else - checkDirectoryName = Path.Combine(checkDirectoryName, $"({directoryTicks}{configuration.FaceDistanceTolerance.ToString()[1..]})"); - for (int i = directoryNames.Count - 1 - 1; i > -1; i--) - checkDirectoryName = Path.Combine(checkDirectoryName, directoryNames[i]); - if (!Directory.Exists(checkDirectoryName)) - _ = Directory.CreateDirectory(checkDirectoryName); - File.Move(file, Path.Combine(checkDirectoryName, fileName)); - if (jsonFileExists) - File.Move(jsonFile, Path.Combine(checkDirectoryName, jsonFileName)); - result = true; - } - } + if (personContainer.Key is null) + continue; + if (!personKeyToPersonContainerCollection.ContainsKey(personContainer.Key.Value)) + personKeyToPersonContainerCollection.Add(personContainer.Key.Value, new()); + personKeyToPersonContainerCollection[personContainer.Key.Value].Add(personContainer); + newestPersonKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personContainer.Key.Value); + if (!personKeyFormattedToPersonContainer.ContainsKey(newestPersonKeyFormatted)) + personKeyFormattedToPersonContainer.Add(newestPersonKeyFormatted, personContainer); } - if (result) - { } + foreach (KeyValuePair> keyValuePair in personKeyToPersonContainerCollection) + { + if (keyValuePair.Value.Count != 1 && (from l in keyValuePair.Value select l.DisplayDirectoryName).Distinct().Count() != 1) + throw new NotSupportedException(keyValuePair.Value[zero].DisplayDirectoryName); + results.Add(new(keyValuePair.Key, keyValuePair.Value[zero])); + } + return results; } - private static int SetCollectionsAndGetUnableToMatchCount(Configuration configuration, string facesFileNameExtension, long ticks, string eDistanceContentDirectory, Shared.Models.Methods.IFaceDistance? distance, Dictionary> idToFaces, Dictionary personKeyFormattedToNewestPersonKeyFormatted, List<(string, string[], int, int)> personKeyFormattedIdThenNormalizedPixelPercentageCollection, List<(string, int, int)> incorrectPersonKeyFormattedIdThenNormalizedPixelPercentageCollection, List<(string, string[], string)> collection) + private static (int, int) SetCollectionsAndGetUnableToMatchCount(string facesFileNameExtension, long ticks, Dictionary> idToFaces, Dictionary personKeyFormattedToNewestPersonKeyFormatted, List<(string, string[], int, int)> personKeyFormattedIdThenNormalizedPixelPercentageCollection, List<(string, int, int)> incorrectPersonKeyFormattedIdThenNormalizedPixelPercentageCollection, List<(string, string[], string)> collection) { - int? id; int result = 0; + int? id; bool debugCheck; - string? checkFile; List? faces; List debugChecks = new(); List checkFaces = new(); int? normalizedPixelPercentage; string newestPersonKeyFormatted; - List duplicates = new(); string personDisplayDirectoryName; bool idToFacesAny = idToFaces.Any(); List normalizedPixelPercentages; + List duplicateMappedFaceFiles = new(); Dictionary> idToNormalizedPixelPercentages = new(); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); - string message = $") {collection.Count:000} join from ticks Director(ies) - B - {totalSeconds} total second(s)"; + string message = $") {collection.Count:000} join from ticks Director(ies) - C - {totalSeconds} total second(s)"; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; using ProgressBar progressBar = new(collection.Count, message, options); - foreach ((string personKeyFormatted, string[] personDisplayDirectoryNames, string file) in collection) + foreach ((string personKeyFormatted, string[] personDisplayDirectoryNames, string mappedFaceFile) in collection) { progressBar.Tick(); (id, normalizedPixelPercentage, faces) = IMapping.GetReversedDeterministicHashCodeKey( - configuration.LocationDigits, + Shared.Models.Stateless.ILocation.Digits, facesFileNameExtension, idToFacesAny, idToFaces, - file); + mappedFaceFile); if (id is null || normalizedPixelPercentage is null) { result++; @@ -397,9 +361,6 @@ internal abstract class MapLogic if (!idToNormalizedPixelPercentages.ContainsKey(id.Value)) idToNormalizedPixelPercentages.Add(id.Value, new()); normalizedPixelPercentages = idToNormalizedPixelPercentages[id.Value]; - checkFile = GetCheckFile(configuration, facesFileNameExtension, file, id.Value, normalizedPixelPercentage.Value); - if (string.IsNullOrEmpty(checkFile)) - throw new NotSupportedException(); if (faces is null) { result++; @@ -417,35 +378,25 @@ internal abstract class MapLogic continue; if (normalizedPixelPercentages.Contains(face.Mapping.MappingFromLocation.NormalizedPixelPercentage)) { - duplicates.Add(string.Concat(id.Value, '.', normalizedPixelPercentage.Value, ".jpg", facesFileNameExtension)); + duplicateMappedFaceFiles.Add(mappedFaceFile); continue; } debugCheck = true; checkFaces.Add(face); if (!debugCheck) - debugChecks.Add(normalizedPixelPercentage.Value); + debugChecks.Add(face.Mapping.MappingFromLocation.NormalizedPixelPercentage); } - if (checkFaces.Count != 1 && distance is not null && File.Exists(checkFile)) - { - checkFaces.Clear(); - checkFaces.AddRange(distance.GetMatchingFaces(configuration.FaceDistanceTolerance, checkFile, faces)); - } - if (!checkFaces.Any() && faces.Count == 1) - checkFaces.AddRange(faces); if (!checkFaces.Any()) { result++; - if (configuration.MappingMoveUnableToMatch) - MoveUnableToMatch(configuration, eDistanceContentDirectory, file, checkFile); continue; } if (checkFaces.Count != 1) { result++; - if (configuration.MappingMoveUnableToMatch) - MoveUnableToMatch(configuration, eDistanceContentDirectory, file, checkFile); continue; } + normalizedPixelPercentages.Add(normalizedPixelPercentage.Value); idToNormalizedPixelPercentages[id.Value].Add(normalizedPixelPercentage.Value); if (!personKeyFormattedToNewestPersonKeyFormatted.ContainsKey(personKeyFormatted)) newestPersonKeyFormatted = personKeyFormatted; @@ -457,13 +408,13 @@ internal abstract class MapLogic else personKeyFormattedIdThenNormalizedPixelPercentageCollection.Add(new(newestPersonKeyFormatted, personDisplayDirectoryNames, id.Value, normalizedPixelPercentage.Value)); } - if (duplicates.Any()) + if (duplicateMappedFaceFiles.Any()) { - duplicates.Sort(); - if (duplicates.Any()) + duplicateMappedFaceFiles.Sort(); + if (duplicateMappedFaceFiles.Any()) { } } - return result; + return new(result, duplicateMappedFaceFiles.Count); } private static double GetStandardDeviation(IEnumerable values, double average) @@ -616,6 +567,8 @@ internal abstract class MapLogic { if (configuration is null) throw new NullReferenceException(nameof(configuration)); + string message; + int totalSeconds; List personKeys = new(); List nullablePersonKeyCollection = new(); List personKeyFormattedCollection = new(); @@ -636,7 +589,7 @@ internal abstract class MapLogic personContainers.AddRange(AddToPersonKeysThenGetNonSpecificPeopleCollection(configuration, personKeys)); foreach (Face face in distinctFilteredFaces) { - if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) + if (face.FaceEncoding is null || face.Location is null) throw new NotSupportedException(); if (face.Mapping is null) throw new NotSupportedException(); @@ -644,17 +597,18 @@ internal abstract class MapLogic keyValuePairs.Add(face.Mapping.MappingFromItem.Id, new()); keyValuePairs[face.Mapping.MappingFromItem.Id].Add(face); } - List<(string, string[], string)> collection = DeleteEmptyDirectoriesAndGetCollection(configuration, - facesFileNameExtension, - ticks, - eDistanceContentDirectory, - personKeyFormattedCollection); - int unableToMatchCount = SetCollectionsAndGetUnableToMatchCount( + totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + string[] ticksDirectories = Directory.GetDirectories(eDistanceContentDirectory, "*", SearchOption.TopDirectoryOnly); + message = $") {ticksDirectories.Length:000} compile from and clean ticks Director(ies) - B - {totalSeconds} total second(s)"; + List<(string, string[], string)> collection = DeleteEmptyDirectoriesAndGetCollection( configuration, + facesFileNameExtension, + personKeyFormattedCollection, + ticksDirectories, + message); + (int unableToMatchCount, int duplicateCount) = SetCollectionsAndGetUnableToMatchCount( facesFileNameExtension, ticks, - eDistanceContentDirectory, - faceDistance, keyValuePairs, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedIdThenNormalizedPixelPercentageCollection, @@ -672,8 +626,8 @@ internal abstract class MapLogic possiblyNewPersonDisplayDirectoryNamesAndPersonContainer, incorrectIdThenNormalizedPixelPercentageToPersonContainers, personKeyToRanges); - int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); - string message = $") {collection.Count:000} message from ticks Director(ies) - C - {unableToMatchCount} Unable To Match Count / {collection.Count} Collection - {totalSeconds} total second(s)"; + totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + message = $") {collection.Count:000} message from ticks Director(ies) - D - {duplicateCount} Duplicate Count {unableToMatchCount} Unable To Match Count / {collection.Count} Collection - {totalSeconds} total second(s)"; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; using (ProgressBar progressBar = new(collection.Count, message, options)) { diff --git a/Map/Models/Stateless/Methods/IMapLogic.cs b/Map/Models/Stateless/Methods/IMapLogic.cs index 0f6456e..626c4cb 100644 --- a/Map/Models/Stateless/Methods/IMapLogic.cs +++ b/Map/Models/Stateless/Methods/IMapLogic.cs @@ -3,4 +3,9 @@ namespace View_by_Distance.Map.Models.Stateless.Methods; public interface IMapLogic { // ... + string[] TestStatic_DeleteEmptyDirectoriesAndGetMappedFaceFiles(Configuration configuration, string facesFileNameExtension, long ticks, string eDistanceContentDirectory, Shared.Models.PersonContainer[] personContainers) => + DeleteEmptyDirectoriesAndGetMappedFaceFiles(configuration, facesFileNameExtension, ticks, eDistanceContentDirectory, personContainers); + static string[] DeleteEmptyDirectoriesAndGetMappedFaceFiles(Configuration configuration, string facesFileNameExtension, long ticks, string eDistanceContentDirectory, Shared.Models.PersonContainer[] personContainers) => + MapLogic.DeleteEmptyDirectoriesAndGetMappedFaceFiles(configuration, facesFileNameExtension, ticks, eDistanceContentDirectory, personContainers); + } \ No newline at end of file diff --git a/Shared/Models/Face.cs b/Shared/Models/Face.cs index 458c2e3..353f22b 100644 --- a/Shared/Models/Face.cs +++ b/Shared/Models/Face.cs @@ -12,7 +12,6 @@ public class Face : Properties.IFace protected Dictionary? _FaceParts; protected readonly OutputResolution? _OutputResolution; protected Location? _Location; - protected readonly int? _LocationIndex; protected Mapping? _Mapping; protected readonly string _RelativePath; public DateTime DateTime => _DateTime; @@ -20,34 +19,32 @@ public class Face : Properties.IFace public FaceEncoding? FaceEncoding => _FaceEncoding; public Dictionary? FaceParts => _FaceParts; public Location? Location => _Location; - public int? LocationIndex => _LocationIndex; public Mapping? Mapping => _Mapping; public OutputResolution? OutputResolution => _OutputResolution; public string RelativePath => _RelativePath; [JsonConstructor] - public Face(DateTime dateTime, FaceDistance? faceDistance, FaceEncoding? faceEncoding, Dictionary? faceParts, Location? location, int? locationIndex, Mapping? mapping, OutputResolution? outputResolution, string relativePath) + public Face(DateTime dateTime, FaceDistance? faceDistance, FaceEncoding? faceEncoding, Dictionary? faceParts, Location? location, Mapping? mapping, OutputResolution? outputResolution, string relativePath) { _DateTime = dateTime; _FaceDistance = faceDistance; _FaceEncoding = faceEncoding; _FaceParts = faceParts; _Location = location; - _LocationIndex = locationIndex; _Mapping = mapping; _OutputResolution = outputResolution; _RelativePath = relativePath; } public Face(int locationDigits, int locationFactor, int facesCount, Face face) : - this(face.DateTime, null, face.FaceEncoding, face.FaceParts, face.Location, face.LocationIndex, null, face.OutputResolution, face.RelativePath) + this(face.DateTime, null, face.FaceEncoding, face.FaceParts, face.Location, null, face.OutputResolution, face.RelativePath) { if (face.Location?.Confidence is not null && face.OutputResolution is not null) _Location = new(face.Location.Confidence, face.OutputResolution.Height, face.Location, locationDigits, locationFactor, face.OutputResolution.Width, facesCount); } - public Face(Property property, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, string relativePath, int? i, Location? location) : - this(DateTime.MinValue, null, null, null, location, i, null, null, relativePath) + public Face(Property property, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, string relativePath, Location? location) : + this(DateTime.MinValue, null, null, null, location, null, null, relativePath) { DateTime?[] dateTimes; _OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth); @@ -56,7 +53,7 @@ public class Face : Properties.IFace } public Face(Face face, int height, Location location, int locationDigits, int locationFactor, int width, int zCount) : - this(face.DateTime, face.FaceDistance, face.FaceEncoding, face.FaceParts, new(height, location, locationDigits, locationFactor, width, zCount), face.LocationIndex, face.Mapping, face.OutputResolution, face.RelativePath) + this(face.DateTime, face.FaceDistance, face.FaceEncoding, face.FaceParts, new(height, location, locationDigits, locationFactor, width, zCount), face.Mapping, face.OutputResolution, face.RelativePath) { } public override string ToString() @@ -73,6 +70,8 @@ public class Face : Properties.IFace public void SetMapping(Mapping mapping) => _Mapping = mapping; - public void FaceDistanceAdd(FaceDistance faceDistance) => _FaceDistance = faceDistance; + public void SetFaceDistance(FaceDistance? faceDistance) => _FaceDistance = faceDistance; + + public void ClearFaceDistance() => _FaceDistance = null; } \ No newline at end of file diff --git a/Shared/Models/FaceFileSystem.cs b/Shared/Models/FaceFileSystem.cs index e30d34c..a20728e 100644 --- a/Shared/Models/FaceFileSystem.cs +++ b/Shared/Models/FaceFileSystem.cs @@ -122,16 +122,8 @@ public class FaceFileSystem : FileSystem, Properties.IFaceFileSystem string locationDisplayIndex; int locationIndex; long sourceSize; - if (face.LocationIndex is null) - { - locationIndex = 0; - locationDisplayIndex = "01"; - } - else - { - locationIndex = face.LocationIndex.Value; - locationDisplayIndex = (face.LocationIndex.Value + 1).ToString("00"); - } + locationIndex = 0; + locationDisplayIndex = "01"; if (face.Location is null) { faceTop = null; @@ -161,7 +153,7 @@ public class FaceFileSystem : FileSystem, Properties.IFaceFileSystem string faceRelativePath = string.Concat(requestPath, new Uri(faceFullFileName).AbsoluteUri[rootResultsDirectoryAbsoluteUriLength..]); string sourceRelativePath = string.Concat(requestPath, new Uri(sourceFullFileName).AbsoluteUri[rootResultsDirectoryAbsoluteUriLength..]); FileInfo fileInfo = new(sourceFullFileName); - if (face.FaceEncoding is not null && face.Location?.NormalizedPixelPercentage is not null && !File.Exists(faceFullFileName)) + if (face.FaceEncoding is not null && face.Location is not null && face.OutputResolution is not null && !File.Exists(faceFullFileName)) Stateless.Methods.IFaceFileSystem.SearchForMissingFile(faceFullFileName, fileInfo: new FileInfo(string.Empty), dataFullFileName); if (fileInfo.Exists) FileExists(face, faceBottom, faceRight, out imageHeight, out imageWidth, out sourceSize, fileInfo); @@ -180,8 +172,8 @@ public class FaceFileSystem : FileSystem, Properties.IFaceFileSystem _LastModified = face.DateTime; _FaceLeft = faceLeft; _LocationDisplayIndex = locationDisplayIndex; - _LocationIndex = face.LocationIndex; - _Populated = face.FaceEncoding is not null && face.Location?.NormalizedPixelPercentage is not null; + _LocationIndex = null; + _Populated = face.FaceEncoding is not null && face.Location is not null && face.OutputResolution is not null; _RelativePath = string.Empty; _FaceRight = faceRight; _SourceFullFileName = sourceFullFileName; diff --git a/Shared/Models/Location.cs b/Shared/Models/Location.cs index 2fd6f71..13149be 100644 --- a/Shared/Models/Location.cs +++ b/Shared/Models/Location.cs @@ -9,20 +9,18 @@ public class Location : Properties.ILocation, IEquatable public int Bottom { init; get; } public double Confidence { init; get; } public int Left { init; get; } - public int? NormalizedPixelPercentage { init; get; } public int Right { init; get; } public int Top { init; get; } [JsonConstructor] - public Location(int bottom, double confidence, int left, int? normalizedPixelPercentage, int right, int top) + public Location(int bottom, double confidence, int left, int right, int top) { Confidence = confidence; Bottom = bottom; Left = left; - NormalizedPixelPercentage = normalizedPixelPercentage; Right = right; Top = top; - Stateless.Methods.Location.Check(bottom, left, normalizedPixelPercentage, right, top, zCount: 1); + Stateless.Methods.Location.Check(bottom, left, right, top, zCount: 1); } public Location(double confidence, int height, Location location, int locationDigits, int locationFactor, int width, int zCount) : @@ -30,30 +28,27 @@ public class Location : Properties.ILocation, IEquatable location.Bottom, confidence, location.Left, - Stateless.Methods.Location.GetNormalizedPixelPercentage(location.Bottom, height, location.Left, locationDigits, locationFactor, location.Right, location.Top, width, zCount), location.Right, location.Top) => - Stateless.Methods.Location.Check(Bottom, Left, NormalizedPixelPercentage, Right, Top, zCount); + Stateless.Methods.Location.Check(Bottom, height, Left, Right, Top, width, zCount); public Location(int bottom, double confidence, int height, int left, int locationDigits, int locationFactor, int right, int top, int width, int zCount) : this( bottom, confidence, left, - Stateless.Methods.Location.GetNormalizedPixelPercentage(bottom, height, left, locationDigits, locationFactor, right, top, width, zCount), right, top) => - Stateless.Methods.Location.Check(Bottom, height, Left, NormalizedPixelPercentage, Right, Top, width, zCount); + Stateless.Methods.Location.Check(Bottom, height, Left, Right, Top, width, zCount); public Location(int height, Location location, int locationDigits, int locationFactor, int width, int zCount) : this( location.Bottom, location.Confidence, location.Left, - Stateless.Methods.Location.GetNormalizedPixelPercentage(location.Bottom, height, location.Left, locationDigits, locationFactor, location.Right, location.Top, width, zCount), location.Right, location.Top) => - Stateless.Methods.Location.Check(Bottom, Left, NormalizedPixelPercentage, Right, Top, zCount); + Stateless.Methods.Location.Check(Bottom, height, Left, Right, Top, width, zCount); public Location(double confidence, int factor, int height, Location location, int locationDigits, int locationFactor, int width, int zCount) { @@ -63,14 +58,10 @@ public class Location : Properties.ILocation, IEquatable int left = Math.Max(location.Left - x, 0); int right = Math.Min(location.Right + x, width); int top = Math.Max(location.Top - y, 0); - int normalizedPixelPercentage = Stateless.Methods.Location.GetNormalizedPixelPercentage(location.Bottom, height, location.Left, locationDigits, locationFactor, location.Right, location.Top, width, zCount); - if (location.NormalizedPixelPercentage is null || normalizedPixelPercentage != location.NormalizedPixelPercentage.Value) - throw new Exception(); - Stateless.Methods.Location.Check(bottom, left, NormalizedPixelPercentage, right, top, zCount); + Stateless.Methods.Location.Check(Bottom, height, Left, Right, Top, width, zCount); Confidence = confidence; Bottom = bottom; Left = left; - NormalizedPixelPercentage = normalizedPixelPercentage; Right = right; Top = top; } diff --git a/Shared/Models/Mapping.cs b/Shared/Models/Mapping.cs index ca07bb5..fab93ee 100644 --- a/Shared/Models/Mapping.cs +++ b/Shared/Models/Mapping.cs @@ -38,10 +38,10 @@ public class MappingFromLocation : Properties.IMappingFromLocation public int NormalizedPixelPercentage { init; get; } [JsonConstructor] - public MappingFromLocation(double confidence, string deterministicHashCodeKeyDisplay, int normalizedPixelPercentage) + public MappingFromLocation(double confidence, string deterministicHashCodeKey, int normalizedPixelPercentage) { Confidence = confidence; - DeterministicHashCodeKey = deterministicHashCodeKeyDisplay; + DeterministicHashCodeKey = deterministicHashCodeKey; NormalizedPixelPercentage = normalizedPixelPercentage; } diff --git a/Shared/Models/Methods/IFaceDistance.cs b/Shared/Models/Methods/IFaceDistance.cs index 3f83cd6..5367588 100644 --- a/Shared/Models/Methods/IFaceDistance.cs +++ b/Shared/Models/Methods/IFaceDistance.cs @@ -3,7 +3,6 @@ namespace View_by_Distance.Shared.Models.Methods; public interface IFaceDistance { - List GetMatchingFaces(double faceDistanceTolerance, string checkFile, List faces); void SavePossiblyNewPersonContainers(Properties.IPropertyConfiguration propertyConfiguration, string personBirthdayFormat, string facesFileNameExtension, string a2PeopleContentDirectory, Dictionary personKeyToPersonContainer, List<(string[], PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer); } \ No newline at end of file diff --git a/Shared/Models/Properties/IFace.cs b/Shared/Models/Properties/IFace.cs index 9f68085..8a37881 100644 --- a/Shared/Models/Properties/IFace.cs +++ b/Shared/Models/Properties/IFace.cs @@ -7,8 +7,6 @@ public interface IFace public FaceDistance? FaceDistance { get; } public FaceEncoding? FaceEncoding { get; } public Dictionary? FaceParts { get; } - public Location? Location { get; } - public int? LocationIndex { get; } public Mapping? Mapping { get; } public OutputResolution? OutputResolution { get; } public string RelativePath { get; } diff --git a/Shared/Models/Properties/ILocation.cs b/Shared/Models/Properties/ILocation.cs index 0446f09..cd8291f 100644 --- a/Shared/Models/Properties/ILocation.cs +++ b/Shared/Models/Properties/ILocation.cs @@ -6,7 +6,6 @@ public interface ILocation public int Bottom { init; get; } public double Confidence { init; get; } public int Left { init; get; } - public int? NormalizedPixelPercentage { init; get; } public int Right { init; get; } public int Top { init; get; } diff --git a/Shared/Models/Stateless/Methods/FaceFileSystem.cs b/Shared/Models/Stateless/Methods/FaceFileSystem.cs index 99d4241..886d511 100644 --- a/Shared/Models/Stateless/Methods/FaceFileSystem.cs +++ b/Shared/Models/Stateless/Methods/FaceFileSystem.cs @@ -58,11 +58,7 @@ internal abstract class FaceFileSystem { if (face[i] is null) continue; - locationIndex = face[i].LocationIndex; - if (locationIndex is null) - locationIndex = 0; - else - locationIndex = locationIndex.Value; + locationIndex = 0; directoryName = Path.GetDirectoryName(face[i].RelativePath); if (directoryName is null) continue; diff --git a/Shared/Models/Stateless/Methods/IFace.cs b/Shared/Models/Stateless/Methods/IFace.cs index 5274e26..3f9e597 100644 --- a/Shared/Models/Stateless/Methods/IFace.cs +++ b/Shared/Models/Stateless/Methods/IFace.cs @@ -28,9 +28,4 @@ public interface IFace static double? Getα(Dictionary faceParts) => Face.Getα(faceParts); - int?[] TestStatic_GetInts(List faces) => - GetInts(faces); - static int?[] GetInts(List faces) => - (from l in faces where l.FaceEncoding is not null && l.Location?.NormalizedPixelPercentage is not null select l.Location?.NormalizedPixelPercentage).ToArray(); - } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/ILocation.cs b/Shared/Models/Stateless/Methods/ILocation.cs index 727586f..52ac8e3 100644 --- a/Shared/Models/Stateless/Methods/ILocation.cs +++ b/Shared/Models/Stateless/Methods/ILocation.cs @@ -6,13 +6,18 @@ public interface ILocation string TestStatic_GetLeftPadded(int locationDigits, string value) => GetLeftPadded(locationDigits, value); static string GetLeftPadded(int locationDigits, string value) => - value.Length == locationDigits ? value : value.Length > locationDigits ? value[..locationDigits] : value.PadLeft(locationDigits, '0'); + Location.GetLeftPadded(locationDigits, value); string TestStatic_GetLeftPadded(int locationDigits, int value) => GetLeftPadded(locationDigits, value); static string GetLeftPadded(int locationDigits, int value) => GetLeftPadded(locationDigits, value.ToString()); + (int?, int?) TestStatic_GetXY(int locationDigits, int locationFactor, int width, int height, string normalizedPixelPercentage) => + GetXY(locationDigits, locationFactor, width, height, normalizedPixelPercentage); + static (int?, int?) GetXY(int locationDigits, int locationFactor, int width, int height, string normalizedPixelPercentage) => + Location.GetXY(locationDigits, locationFactor, width, height, normalizedPixelPercentage); + Models.Location? TestStatic_GetLocation(Models.Location? location, int locationDigits, int locationFactor, int height, int width, int zCount) => GetLocation(location, locationDigits, locationFactor, height, width, zCount); static Models.Location? GetLocation(Models.Location? location, int locationDigits, int locationFactor, int height, int width, int zCount) => @@ -23,11 +28,6 @@ public interface ILocation static Models.Location? GetLocation(int factor, Models.Location? location, int locationDigits, int locationFactor, int height, int width, int zCount) => location is null ? null : new(location.Confidence, factor, height, location, locationDigits, locationFactor, width, zCount); - int?[] TestStatic_GetInts(List locations) => - GetInts(locations); - static int?[] GetInts(List locations) => - (from l in locations where l.NormalizedPixelPercentage is not null select l.NormalizedPixelPercentage).ToArray(); - int TestStatic_GetNormalizedPixelPercentage(Models.Location location, int locationDigits, int locationFactor, OutputResolution outputResolution) => GetNormalizedPixelPercentage(location, locationDigits, locationFactor, outputResolution); static int GetNormalizedPixelPercentage(Models.Location location, int locationDigits, int locationFactor, OutputResolution outputResolution) => diff --git a/Shared/Models/Stateless/Methods/IMapping.cs b/Shared/Models/Stateless/Methods/IMapping.cs index 19444bf..49475b7 100644 --- a/Shared/Models/Stateless/Methods/IMapping.cs +++ b/Shared/Models/Stateless/Methods/IMapping.cs @@ -3,14 +3,16 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods; public interface IMapping { // ... - static string GetDeterministicHashCodeKey(int id, int pixel) - => $"{id}.{pixel}"; - (string?, string?, string?, bool?) TestStatic_GetSegments(int locationDigits, string facesFileNameExtension, string fileName) => GetSegments(locationDigits, facesFileNameExtension, fileName); static (string?, string?, string?, bool?) GetSegments(int locationDigits, string facesFileNameExtension, string fileName) => Mapping.GetSegments(locationDigits, facesFileNameExtension, fileName); + string TestStatic_GetDeterministicHashCodeKey(int id, Models.Location location, int locationDigits, int locationFactor, OutputResolution outputResolution) + => GetDeterministicHashCodeKey(id, location, locationDigits, locationFactor, outputResolution); + static string GetDeterministicHashCodeKey(int id, Models.Location location, int locationDigits, int locationFactor, OutputResolution outputResolution) + => $"{id}.{ILocation.GetNormalizedPixelPercentage(location, locationDigits, locationFactor, outputResolution)}"; + (int?, int?, List?) TestStatic_GetReversedDeterministicHashCodeKey(int locationDigits, string facesFileNameExtension, string file) => GetReversedDeterministicHashCodeKey(locationDigits, facesFileNameExtension, file); static (int?, int?, List?) GetReversedDeterministicHashCodeKey(int locationDigits, string facesFileNameExtension, string file) => diff --git a/Shared/Models/Stateless/Methods/Location.cs b/Shared/Models/Stateless/Methods/Location.cs index 224eb21..1739dfd 100644 --- a/Shared/Models/Stateless/Methods/Location.cs +++ b/Shared/Models/Stateless/Methods/Location.cs @@ -33,26 +33,25 @@ internal abstract class Location throw new Exception(); if (zCount < 0) throw new Exception(); + Check(bottom, left, right, top, zCount); } - internal static void Check(int bottom, int left, int? normalizedPixelPercentage, int right, int top, int zCount) + internal static string GetLeftPadded(int locationDigits, string value) { - Check(bottom, left, right, top, zCount); - if (normalizedPixelPercentage.HasValue && normalizedPixelPercentage.Value < 0) - throw new Exception(); - } - - internal static void Check(int bottom, int height, int left, int? normalizedPixelPercentage, int right, int top, int width, int zCount) - { - Check(bottom, left, right, top, zCount); - Check(bottom, height, left, right, top, width, zCount); - if (normalizedPixelPercentage.HasValue && normalizedPixelPercentage.Value < 0) - throw new Exception(); + string result; + if (value.Length == locationDigits) + result = value; + else if (value.Length > locationDigits) + result = value[..locationDigits]; + else + result = value.PadLeft(locationDigits, '0'); + return result; } internal static int GetNormalizedPixelPercentage(int bottom, int height, int left, int locationDigits, int locationFactor, int right, int top, int width, int zCount) { int result; + Check(bottom, height, left, right, top, width, zCount); int checksum; decimal center = 2m; string xCenterPadded; @@ -60,10 +59,12 @@ internal abstract class Location decimal factor = locationFactor; // int.MaxPercentage = 21 4748 3647; int length = (locationDigits - 1) / 2; - Check(bottom, left, right, top, zCount); - Check(bottom, height, left, right, top, width, zCount); - decimal xCenterValue = left + ((right - left) / center); - decimal yCenterValue = top + ((bottom - top) / center); + decimal xCenterValue = (left + right) / center; + decimal yCenterValue = (top + bottom) / center; + if (xCenterValue < left || xCenterValue > right) + throw new Exception(); + if (yCenterValue < top || yCenterValue > bottom) + throw new Exception(); if (xCenterValue > yCenterValue) checksum = 1; else @@ -87,4 +88,28 @@ internal abstract class Location return result; } + internal static (int?, int?) GetXY(int locationDigits, int locationFactor, int width, int height, string normalizedPixelPercentage) + { + int? x; + int? y; + int center = 2; + decimal factor = locationFactor; + int each = (locationDigits - 1) / center; + string segmentA = normalizedPixelPercentage[..each]; + string segmentB = normalizedPixelPercentage[each..^1]; + if (!int.TryParse(segmentA, out int xNormalized) || !int.TryParse(segmentB, out int yNormalized)) + { + x = null; + y = null; + } + else + { + decimal xValue = xNormalized / factor * width; + decimal yValue = yNormalized / factor * height; + x = (int)Math.Round(xValue, 0); + y = (int)Math.Round(yValue, 0); + } + return new(x, y); + } + } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/PersonBirthday.cs b/Shared/Models/Stateless/Methods/PersonBirthday.cs index 6d3d529..e480383 100644 --- a/Shared/Models/Stateless/Methods/PersonBirthday.cs +++ b/Shared/Models/Stateless/Methods/PersonBirthday.cs @@ -112,6 +112,7 @@ internal abstract class PersonBirthday internal static List GetPersonBirthdays(string personBirthdayFormat, string[] personKeyDirectories, string personDisplayDirectory) { List results = new(); + string[] files; string personKeyFormatted; Models.PersonBirthday? personBirthday; foreach (string personKeyDirectory in personKeyDirectories) @@ -124,6 +125,10 @@ internal abstract class PersonBirthday if (personBirthday is null) continue; results.Add(personBirthday); + files = Directory.GetFiles(personKeyDirectory, "*", SearchOption.TopDirectoryOnly); + if (files.Any()) + continue; + File.WriteAllText(Path.Combine(personKeyDirectory, $"{personKeyFormatted}.txt"), string.Empty); } return results; } diff --git a/Tests/Models/Configuration.cs b/Tests/Models/Configuration.cs index ef10787..11719ff 100644 --- a/Tests/Models/Configuration.cs +++ b/Tests/Models/Configuration.cs @@ -98,7 +98,7 @@ public class Configuration string[] validResolutions) { _PropertyConfiguration = propertyConfiguration; - CheckDFaceAndUpWriteDates = CheckDFaceAndUpWriteDates; + CheckDFaceAndUpWriteDates = checkDFaceAndUpWriteDates; CheckJsonForDistanceResults = checkJsonForDistanceResults; CrossDirectoryMaxItemsInDistanceCollection = crossDirectoryMaxItemsInDistanceCollection; DistanceFactor = distanceFactor; diff --git a/Tests/UnitTestCalculations.cs b/Tests/UnitTestCalculations.cs index c3d5979..2b7adde 100644 --- a/Tests/UnitTestCalculations.cs +++ b/Tests/UnitTestCalculations.cs @@ -113,38 +113,38 @@ public class UnitTestCalculations [TestMethod] public void TestMethodDamn() { - string name; - string[] directories; - string? directoryName; - string checkDirectory; - string sourceDirectory = @"F:\Tmp\Phares\Compare\Images 2022-09-15 - 7390c13 - III - Results\E) Distance\2022-09-15\7680 x 4320\7680x4320 - Hog - Large\()"; - directories = Directory.GetDirectories(sourceDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string directory in directories) - { - directoryName = Path.GetDirectoryName(directory); - if (directoryName is null) - continue; - name = Path.GetFileName(directory); - if (name.Length is 1 or 20) - continue; - checkDirectory = Path.Combine(directoryName, "b", name); - Directory.Move(directory, checkDirectory); - } - directories = Directory.GetDirectories(Path.Combine(sourceDirectory, "b"), "*", SearchOption.TopDirectoryOnly); - foreach (string directory in directories) - { - directoryName = Path.GetDirectoryName(directory); - if (directoryName is null) - continue; - name = Path.GetFileName(directory); - if (name.Length is 1 or 20) - continue; - checkDirectory = Path.Combine(directoryName, $"{name[..^4]})"); - if (Directory.Exists(checkDirectory)) - continue; - Directory.Move(directory, checkDirectory); - } - Assert.IsTrue(true); + // string name; + // string[] directories; + // string? directoryName; + // string checkDirectory; + // string sourceDirectory = @"F:\Tmp\Phares\Compare\Images 2022-09-15 - 7390c13 - III - Results\E) Distance\2022-09-15\7680 x 4320\7680x4320 - Hog - Large\()"; + // directories = Directory.GetDirectories(sourceDirectory, "*", SearchOption.TopDirectoryOnly); + // foreach (string directory in directories) + // { + // directoryName = Path.GetDirectoryName(directory); + // if (directoryName is null) + // continue; + // name = Path.GetFileName(directory); + // if (name.Length is 1 or 20) + // continue; + // checkDirectory = Path.Combine(directoryName, "b", name); + // Directory.Move(directory, checkDirectory); + // } + // directories = Directory.GetDirectories(Path.Combine(sourceDirectory, "b"), "*", SearchOption.TopDirectoryOnly); + // foreach (string directory in directories) + // { + // directoryName = Path.GetDirectoryName(directory); + // if (directoryName is null) + // continue; + // name = Path.GetFileName(directory); + // if (name.Length is 1 or 20) + // continue; + // checkDirectory = Path.Combine(directoryName, $"{name[..^4]})"); + // if (Directory.Exists(checkDirectory)) + // continue; + // Directory.Move(directory, checkDirectory); + // } + // Assert.IsTrue(true); } [TestMethod] @@ -164,8 +164,8 @@ public class UnitTestCalculations Assert.IsTrue(names.Length == 3); names = IPath.GetDirectoryNames(@"C:\Tmp\phares\"); Assert.IsTrue(names.Length == 3); - names = IPath.GetDirectoryNames(@"C:\Tmp\phares\Pictures - Results\E) Distance\2022-09-15\7680 x 4320\7680x4320 - Hog - Large\()\(637991752537712052)\1976-03-08_00\#2019\K\-735727008.520765.jpg"); - Assert.IsTrue(names.Length == 13); + // names = IPath.GetDirectoryNames(@"C:\Tmp\phares\Pictures - Results\E) Distance\2022-09-15\7680 x 4320\7680x4320 - Hog - Large\()\(637991752537712052)\1976-03-08_00\#2019\K\-735727008.520765.jpg"); + // Assert.IsTrue(names.Length == 13); // Length = 13 // [0] [string]: // "C:\\" @@ -193,112 +193,193 @@ public class UnitTestCalculations double confidence = 0.1D; int left, top, right, bottom, width, height; left = 20; - top = 40; right = 60; + top = 40; bottom = 80; width = 100; height = 100; - Location location = new(bottom, confidence, left, null, right, top); + Location location = new(bottom, confidence, left, right, top); _ = new Location(confidence, height, location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, width, 1); _ = new Location(bottom, confidence, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width, 1); } [TestMethod] - public void TestGetPixelPercentage() - { - int normalizedPixelPercentage; - int bottom, height, left, right, top, width; - left = 1; - top = 1; - right = 10; - bottom = 10; - width = 100; - height = 100; - normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); - Assert.IsTrue(normalizedPixelPercentage == 055005502); - left = 50; - top = 50; - right = 60; - bottom = 60; - width = 100; - height = 100; - normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); - Assert.IsTrue(normalizedPixelPercentage == 550055002); - } - - [TestMethod] - public void TestGetPixelPercentageB() - { - int normalizedPixelPercentage; - int bottom, height, left, right, top, width; - left = 240; - top = 240; - right = 260; - bottom = 260; - width = 500; - height = 500; - normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); - Assert.IsTrue(normalizedPixelPercentage == 500050002); - left = 490; - top = 490; - right = 510; - bottom = 510; - width = 1000; - height = 1000; - normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); - Assert.IsTrue(normalizedPixelPercentage == 500050002); - left++; - normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); - Assert.IsTrue(normalizedPixelPercentage == 500550001); - left++; - normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); - Assert.IsTrue(normalizedPixelPercentage == 501050001); - } - - [TestMethod] - public void TestGetPixelPercentageC() - { - int normalizedPixelPercentage; - int bottom, height, left, right, top, width; - left = 20; - top = 40; - right = 60; - bottom = 80; - width = 100; - height = 100; - normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); - Assert.IsTrue(normalizedPixelPercentage == 400060002); - left = 20; - top = 40; - right = 60; - bottom = 80; - width = 100; - height = 100; - normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); - Assert.IsTrue(normalizedPixelPercentage == 400060002); - } - - [TestMethod] - public void TestGetPixelPercentageD() + public void TestGetPixelPercentageA() { + int? x, y; int normalizedPixelPercentage; int bottom, height, left, right, top, width; + string normalizedPixelPercentagePadded; left = 7678; - top = 4318; right = 7680; + top = 4318; bottom = 4320; width = 7680; height = 4320; normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); Assert.IsTrue(normalizedPixelPercentage == 999999981); + normalizedPixelPercentagePadded = ILocation.GetLeftPadded(Shared.Models.Stateless.ILocation.Digits, normalizedPixelPercentage); + (x, y) = ILocation.GetXY(Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, width, height, normalizedPixelPercentagePadded); + Assert.IsTrue(x.HasValue && x.Value == 7679); + Assert.IsTrue(y.HasValue && y.Value == 4319); left = 7680; - top = 4320; right = 7680; + top = 4320; bottom = 4320; width = 7680; height = 4320; normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); Assert.IsTrue(normalizedPixelPercentage == 999999991); + normalizedPixelPercentagePadded = ILocation.GetLeftPadded(Shared.Models.Stateless.ILocation.Digits, normalizedPixelPercentage); + (x, y) = ILocation.GetXY(Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, width, height, normalizedPixelPercentagePadded); + Assert.IsTrue(x.HasValue && x.Value == 7679); + Assert.IsTrue(y.HasValue && y.Value == 4320); + } + + [TestMethod] + public void TestGetPixelPercentageB() + { + int? x, y; + int normalizedPixelPercentage; + int bottom, height, left, right, top, width; + string normalizedPixelPercentagePadded; + left = 20; + right = 60; + top = 40; + bottom = 80; + width = 100; + height = 100; + normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); + Assert.IsTrue(normalizedPixelPercentage == 400060002); + normalizedPixelPercentagePadded = ILocation.GetLeftPadded(Shared.Models.Stateless.ILocation.Digits, normalizedPixelPercentage); + (x, y) = ILocation.GetXY(Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, width, height, normalizedPixelPercentagePadded); + Assert.IsTrue(x.HasValue && x.Value == 40); + Assert.IsTrue(y.HasValue && y.Value == 60); + left = 45; + right = 55; + top = 45; + bottom = 55; + width = 100; + height = 100; + normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); + Assert.IsTrue(normalizedPixelPercentage == 500050002); + normalizedPixelPercentagePadded = ILocation.GetLeftPadded(Shared.Models.Stateless.ILocation.Digits, normalizedPixelPercentage); + (x, y) = ILocation.GetXY(Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, width, height, normalizedPixelPercentagePadded); + Assert.IsTrue(x.HasValue && x.Value == 50); + Assert.IsTrue(y.HasValue && y.Value == 50); + } + + [TestMethod] + public void TestGetPixelPercentageC() + { + int? x, y; + int normalizedPixelPercentage; + string normalizedPixelPercentagePadded; + int bottom, height, left, right, top, width; + left = 1; + right = 3; + top = 1; + bottom = 3; + width = 100; + height = 100; + normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); + Assert.IsTrue(normalizedPixelPercentage == 20002002); + normalizedPixelPercentagePadded = ILocation.GetLeftPadded(Shared.Models.Stateless.ILocation.Digits, normalizedPixelPercentage); + (x, y) = ILocation.GetXY(Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, width, height, normalizedPixelPercentagePadded); + Assert.IsTrue(x.HasValue && x.Value == 2); + Assert.IsTrue(y.HasValue && y.Value == 2); + left = 50; + right = 60; + top = 50; + bottom = 60; + width = 100; + height = 100; + normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); + Assert.IsTrue(normalizedPixelPercentage == 550055002); + normalizedPixelPercentagePadded = ILocation.GetLeftPadded(Shared.Models.Stateless.ILocation.Digits, normalizedPixelPercentage); + (x, y) = ILocation.GetXY(Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, width, height, normalizedPixelPercentagePadded); + Assert.IsTrue(x.HasValue && x.Value == 55); + Assert.IsTrue(y.HasValue && y.Value == 55); + } + + [TestMethod] + public void TestGetPixelPercentageD() + { + int? x, y; + int normalizedPixelPercentage; + int bottom, height, left, right, top, width; + string normalizedPixelPercentagePadded; + left = 240; + right = 260; + top = 240; + bottom = 260; + width = 500; + height = 500; + normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); + Assert.IsTrue(normalizedPixelPercentage == 500050002); + normalizedPixelPercentagePadded = ILocation.GetLeftPadded(Shared.Models.Stateless.ILocation.Digits, normalizedPixelPercentage); + (x, y) = ILocation.GetXY(Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, width, height, normalizedPixelPercentagePadded); + Assert.IsTrue(x.HasValue && x.Value == 250); + Assert.IsTrue(y.HasValue && y.Value == 250); + left = 490; + right = 510; + top = 490; + bottom = 510; + width = 1000; + height = 1000; + normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); + Assert.IsTrue(normalizedPixelPercentage == 500050002); + normalizedPixelPercentagePadded = ILocation.GetLeftPadded(Shared.Models.Stateless.ILocation.Digits, normalizedPixelPercentage); + (x, y) = ILocation.GetXY(Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, width, height, normalizedPixelPercentagePadded); + Assert.IsTrue(x.HasValue && x.Value == 500); + Assert.IsTrue(y.HasValue && y.Value == 500); + left++; + normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); + Assert.IsTrue(normalizedPixelPercentage == 500550001); + normalizedPixelPercentagePadded = ILocation.GetLeftPadded(Shared.Models.Stateless.ILocation.Digits, normalizedPixelPercentage); + (x, y) = ILocation.GetXY(Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, width, height, normalizedPixelPercentagePadded); + Assert.IsTrue(x.HasValue && x.Value == 500); + Assert.IsTrue(y.HasValue && y.Value == 500); + left++; + normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); + Assert.IsTrue(normalizedPixelPercentage == 501050001); + normalizedPixelPercentagePadded = ILocation.GetLeftPadded(Shared.Models.Stateless.ILocation.Digits, normalizedPixelPercentage); + (x, y) = ILocation.GetXY(Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, width, height, normalizedPixelPercentagePadded); + Assert.IsTrue(x.HasValue && x.Value == 501); + Assert.IsTrue(y.HasValue && y.Value == 500); + } + + [TestMethod] + public void TestGetPixelPercentageE() + { + int? x, y; + int normalizedPixelPercentage; + int bottom, height, left, right, top, width; + string normalizedPixelPercentagePadded; + left = 1477; + right = 1477; + top = 641; + bottom = 641; + width = 2408; + height = 2077; + normalizedPixelPercentage = ILocation.GetNormalizedPixelPercentage(bottom, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width); + Assert.IsTrue(normalizedPixelPercentage == 613430861); + normalizedPixelPercentagePadded = ILocation.GetLeftPadded(Shared.Models.Stateless.ILocation.Digits, normalizedPixelPercentage); + (x, y) = ILocation.GetXY(Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, width, height, normalizedPixelPercentagePadded); + Assert.IsTrue(x.HasValue && x.Value == 1477); + Assert.IsTrue(y.HasValue && y.Value == 641); + } + + [TestMethod] + public void TestGetDistance() + { + double x1, x2, y1, y2; + x1 = 12f; + x2 = 13f; + y1 = 11f; + y2 = 10f; + double distance = Math.Sqrt(Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2)); + Assert.IsTrue(distance == 1.4142135623730951); } } \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs b/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs index 0cc0afc..ad0c0d0 100644 --- a/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs +++ b/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs @@ -14,6 +14,8 @@ public class Configuration [Display(Name = "Check Json For Distance Results"), Required] public bool? CheckJsonForDistanceResults { get; set; } [Display(Name = "CrossDirectory Max Items In Distance Collection"), Required] public int? CrossDirectoryMaxItemsInDistanceCollection { get; set; } [Display(Name = "Distance Factor"), Required] public int? DistanceFactor { get; set; } + [Display(Name = "Distance Move Unable to Match by 1 Tick"), Required] public bool? DistanceMoveUnableToMatch { get; set; } + [Display(Name = "Distance Pixel Distance Tolerance"), Required] public int? DistancePixelDistanceTolerance { get; set; } [Display(Name = "Face Distance Hidden Image Factor"), Required] public int? FaceDistanceHiddenImageFactor { get; set; } [Display(Name = "Location Minimum Confidence"), Required] public double? FaceDistanceMinimumConfidence { get; set; } [Display(Name = "Face Distance Permyriad"), Required] public int? FaceDistancePermyriad { get; set; } @@ -33,7 +35,6 @@ public class Configuration [Display(Name = "Map Logic Sigma"), Required] public int? MapLogicSigma { get; set; } [Display(Name = "Mapped Max Index"), Required] public int? MappedMaxIndex { get; set; } [Display(Name = "Mapping Default Name"), Required] public string MappingDefaultName { get; set; } - [Display(Name = "Mapping Move Unable to Match by 1 Tick"), Required] public bool? MappingMoveUnableToMatch { get; set; } [Display(Name = "Mapping Save Mapped"), Required] public bool? MappingSaveMapped { get; set; } [Display(Name = "Mapping Save Not Mapped"), Required] public bool? MappingSaveNotMapped { get; set; } [Display(Name = "Mapping Use Deterministic Hash Code Unknown Face Key Value Pairs for Add to Mapping"), Required] public bool? MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping { get; set; } @@ -61,6 +62,7 @@ public class Configuration [Display(Name = "Properties Changed For Metadata"), Required] public bool? PropertiesChangedForMetadata { get; set; } [Display(Name = "Properties Changed For Resize"), Required] public bool? PropertiesChangedForResize { get; set; } [Display(Name = "Property Configuration"), Required] public Property.Models.Configuration PropertyConfiguration { get; set; } + [Display(Name = "Retry Images Without a Face"), Required] public bool? RetryImagesWithoutAFace { get; set; } [Display(Name = "Reverse"), Required] public bool? Reverse { get; set; } [Display(Name = "Save Face Landmark For Output Resolutions"), Required] public string[] SaveFaceLandmarkForOutputResolutions { get; set; } [Display(Name = "Save Full Year Of Random Files"), Required] public bool? SaveFullYearOfRandomFiles { get; set; } @@ -93,6 +95,10 @@ public class Configuration throw new NullReferenceException(nameof(configuration.CrossDirectoryMaxItemsInDistanceCollection)); if (configuration.DistanceFactor is null) throw new NullReferenceException(nameof(configuration.DistanceFactor)); + if (configuration.DistanceMoveUnableToMatch is null) + throw new NullReferenceException(nameof(configuration.DistanceMoveUnableToMatch)); + if (configuration.DistancePixelDistanceTolerance is null) + throw new NullReferenceException(nameof(configuration.DistancePixelDistanceTolerance)); if (configuration.FaceDistanceHiddenImageFactor is null) throw new NullReferenceException(nameof(configuration.FaceDistanceHiddenImageFactor)); if (configuration.FaceDistanceMinimumConfidence is null) @@ -127,8 +133,6 @@ public class Configuration throw new NullReferenceException(nameof(configuration.MapLogicSigma)); if (configuration.MappingDefaultName is null) throw new NullReferenceException(nameof(configuration.MappingDefaultName)); - if (configuration.MappingMoveUnableToMatch is null) - throw new NullReferenceException(nameof(configuration.MappingMoveUnableToMatch)); if (configuration.MappingSaveNotMapped is null) throw new NullReferenceException(nameof(configuration.MappingSaveNotMapped)); if (configuration.MappingSaveMapped is null) @@ -173,6 +177,8 @@ public class Configuration throw new NullReferenceException(nameof(configuration.PropertiesChangedForMetadata)); if (configuration.PropertiesChangedForResize is null) throw new NullReferenceException(nameof(configuration.PropertiesChangedForResize)); + if (configuration.RetryImagesWithoutAFace is null) + throw new NullReferenceException(nameof(configuration.RetryImagesWithoutAFace)); if (configuration.Reverse is null) throw new NullReferenceException(nameof(configuration.Reverse)); if (configuration.SaveFaceLandmarkForOutputResolutions is null) @@ -212,6 +218,8 @@ public class Configuration configuration.CheckJsonForDistanceResults.Value, configuration.CrossDirectoryMaxItemsInDistanceCollection.Value, configuration.DistanceFactor.Value, + configuration.DistanceMoveUnableToMatch.Value, + configuration.DistancePixelDistanceTolerance.Value, configuration.FaceDistanceHiddenImageFactor.Value, configuration.FaceDistanceMinimumConfidence.Value, configuration.FaceDistancePermyriad.Value, @@ -231,7 +239,6 @@ public class Configuration configuration.MapLogicSigma.Value, configuration.MappedMaxIndex, configuration.MappingDefaultName, - configuration.MappingMoveUnableToMatch.Value, configuration.MappingSaveNotMapped.Value, configuration.MappingSaveMapped.Value, configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping.Value, @@ -258,6 +265,7 @@ public class Configuration configuration.PropertiesChangedForIndex.Value, configuration.PropertiesChangedForMetadata.Value, configuration.PropertiesChangedForResize.Value, + configuration.RetryImagesWithoutAFace.Value, configuration.Reverse.Value, configuration.SaveFaceLandmarkForOutputResolutions, configuration.SaveFullYearOfRandomFiles.Value, diff --git a/TestsWithFaceRecognitionDotNet/Models/Configuration.cs b/TestsWithFaceRecognitionDotNet/Models/Configuration.cs index d649e79..270a15c 100644 --- a/TestsWithFaceRecognitionDotNet/Models/Configuration.cs +++ b/TestsWithFaceRecognitionDotNet/Models/Configuration.cs @@ -13,6 +13,8 @@ public class Configuration public bool CheckJsonForDistanceResults { init; get; } public int CrossDirectoryMaxItemsInDistanceCollection { init; get; } public int DistanceFactor { init; get; } + public bool DistanceMoveUnableToMatch { init; get; } + public int DistancePixelDistanceTolerance { init; get; } public int FaceDistanceHiddenImageFactor { init; get; } public double FaceDistanceMinimumConfidence { init; get; } public int FaceDistancePermyriad { init; get; } @@ -32,7 +34,6 @@ public class Configuration public int MapLogicSigma { init; get; } public int? MappedMaxIndex { init; get; } public string MappingDefaultName { init; get; } - public bool MappingMoveUnableToMatch { init; get; } public bool MappingSaveNotMapped { init; get; } public bool MappingSaveMapped { init; get; } public bool MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping { init; get; } @@ -59,6 +60,7 @@ public class Configuration public bool PropertiesChangedForIndex { init; get; } public bool PropertiesChangedForMetadata { init; get; } public bool PropertiesChangedForResize { init; get; } + public bool RetryImagesWithoutAFace { init; get; } public bool Reverse { init; get; } public string[] SaveFaceLandmarkForOutputResolutions { init; get; } public bool SaveFullYearOfRandomFiles { init; get; } @@ -78,6 +80,8 @@ public class Configuration bool checkJsonForDistanceResults, int crossDirectoryMaxItemsInDistanceCollection, int distanceFactor, + bool distanceMoveUnableToMatch, + int distancePixelDistanceTolerance, int faceDistanceHiddenImageFactor, double faceDistanceMinimumConfidence, int faceDistancePermyriad, @@ -97,7 +101,6 @@ public class Configuration int mapLogicSigma, int? mappedMaxIndex, string mappingDefaultName, - bool mappingMoveUnableToMatch, bool mappingSaveNotMapped, bool mappingSaveMapped, bool mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping, @@ -124,6 +127,7 @@ public class Configuration bool propertiesChangedForIndex, bool propertiesChangedForMetadata, bool propertiesChangedForResize, + bool retryImagesWithoutAFace, bool reverse, string[] saveFaceLandmarkForOutputResolutions, bool saveFullYearOfRandomFiles, @@ -142,6 +146,8 @@ public class Configuration CheckJsonForDistanceResults = checkJsonForDistanceResults; CrossDirectoryMaxItemsInDistanceCollection = crossDirectoryMaxItemsInDistanceCollection; DistanceFactor = distanceFactor; + DistanceMoveUnableToMatch = distanceMoveUnableToMatch; + DistancePixelDistanceTolerance = distancePixelDistanceTolerance; FaceDistanceHiddenImageFactor = faceDistanceHiddenImageFactor; FaceDistanceMinimumConfidence = faceDistanceMinimumConfidence; FaceDistancePermyriad = faceDistancePermyriad; @@ -161,7 +167,6 @@ public class Configuration MapLogicSigma = mapLogicSigma; MappedMaxIndex = mappedMaxIndex; MappingDefaultName = mappingDefaultName; - MappingMoveUnableToMatch = mappingMoveUnableToMatch; MappingSaveNotMapped = mappingSaveNotMapped; MappingSaveMapped = mappingSaveMapped; MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping = mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping; @@ -188,6 +193,7 @@ public class Configuration PropertiesChangedForIndex = propertiesChangedForIndex; PropertiesChangedForMetadata = propertiesChangedForMetadata; PropertiesChangedForResize = propertiesChangedForResize; + RetryImagesWithoutAFace = retryImagesWithoutAFace; Reverse = reverse; SaveFaceLandmarkForOutputResolutions = saveFaceLandmarkForOutputResolutions; SaveFullYearOfRandomFiles = saveFullYearOfRandomFiles; diff --git a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs index eee20b0..ac0498b 100644 --- a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs +++ b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs @@ -241,8 +241,8 @@ public class UnitTestFace Image image = FaceRecognition.LoadImageFile(item.ResizedFileHolder.FullName); Assert.IsNotNull(image); FaceRecognition faceRecognition = new(_Configuration.NumberOfTimesToUpsample, _Configuration.NumberOfJitters, predictorModel, model, modelParameter); - List<(int, Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary? FaceParts)> collection; - collection = faceRecognition.GetCollection(image, includeFaceEncoding: true, includeFaceParts: true, sortByNormalizedPixelPercentage: true); + List<(Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary? FaceParts)> collection; + collection = faceRecognition.GetCollection(image, includeFaceEncoding: true, includeFaceParts: true); Assert.IsTrue(collection.Count == 2); List faceDistanceEncodings = (from l in collection where l.FaceEncoding is not null select new FaceDistance(l.FaceEncoding)).ToList(); List faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncodings[0]);