diff --git a/Distance/Models/DistanceLimits.cs b/Distance/Models/DistanceLimits.cs new file mode 100644 index 0000000..31f6b29 --- /dev/null +++ b/Distance/Models/DistanceLimits.cs @@ -0,0 +1,69 @@ +using View_by_Distance.Shared.Models.Methods; + +namespace View_by_Distance.Distance.Models; + +public class DistanceLimits : IDistanceLimits +{ + + private int _Area; + private int _Days; + private int _Distance; + private int _Confidence; + + public double FaceAreaPermille { init; get; } + public double RangeDaysDeltaTolerance { init; get; } + public double FaceConfidencePercent { init; get; } + public double FaceDistancePermyriad { init; get; } + public int SortingMaximumPerFaceShouldBeHigh { init; get; } + public bool RangeDaysDeltaTargetLessThenUpper { init; get; } + + public DistanceLimits(int faceConfidencePercent, + int faceDistancePermyriad, + int[] rangeDaysDeltaTolerance, + double[] rangeDistanceTolerance, + int[] rangeFaceAreaPermilleTolerance, + double[] rangeFaceConfidence, + int sortingMaximumPerFaceShouldBeHigh, + int? useFiltersCounter = null) + { + SortingMaximumPerFaceShouldBeHigh = sortingMaximumPerFaceShouldBeHigh; + RangeDaysDeltaTargetLessThenUpper = rangeDaysDeltaTolerance[1] > rangeDaysDeltaTolerance[2]; + if (useFiltersCounter is null) + { + FaceAreaPermille = rangeFaceAreaPermilleTolerance[1]; + RangeDaysDeltaTolerance = rangeDaysDeltaTolerance[1]; + FaceConfidencePercent = faceConfidencePercent * rangeFaceConfidence[1]; + FaceDistancePermyriad = faceDistancePermyriad * rangeDistanceTolerance[1]; + } + else + { + RangeDaysDeltaTolerance = ((rangeDaysDeltaTolerance[2] - rangeDaysDeltaTolerance[0]) * 0.01 * useFiltersCounter.Value) + rangeDaysDeltaTolerance[1]; + FaceConfidencePercent = faceConfidencePercent * ((rangeFaceConfidence[2] - rangeFaceConfidence[0]) * 0.01 * useFiltersCounter.Value) + rangeFaceConfidence[1]; + FaceAreaPermille = ((rangeFaceAreaPermilleTolerance[2] - rangeFaceAreaPermilleTolerance[0]) * 0.01 * useFiltersCounter.Value) + rangeFaceAreaPermilleTolerance[1]; + FaceDistancePermyriad = faceDistancePermyriad * ((rangeDistanceTolerance[2] - rangeDistanceTolerance[0]) * 0.01 * useFiltersCounter.Value) + rangeDistanceTolerance[1]; + } + } + + string IDistanceLimits.GetCounts() + { + string result; + List<(int Value, string Name)> results = new() + { + new(_Area, nameof(_Area)), + new(_Confidence, nameof(_Confidence)), + new(_Days, nameof(_Days)), + new(_Distance, nameof(_Distance)) + }; + result = string.Join(' ', from l in results orderby l.Value descending select $"{l.Name}_{l.Value};"); + return result; + } + + void IDistanceLimits.AddCounts(int area, int days, int distance, int confidence) + { + _Area += area; + _Days += days; + _Distance += distance; + _Confidence += confidence; + } + +} \ No newline at end of file diff --git a/Distance/Models/MapLogicSupport.cs b/Distance/Models/MapLogicSupport.cs deleted file mode 100644 index 467f5e2..0000000 --- a/Distance/Models/MapLogicSupport.cs +++ /dev/null @@ -1,254 +0,0 @@ -using ShellProgressBar; -using View_by_Distance.FaceRecognitionDotNet; -using View_by_Distance.Map.Models; -using View_by_Distance.Shared.Models; - -namespace View_by_Distance.Distance.Models; - -public class MapLogicSupport : Shared.Models.Methods.IMapLogicSupport -{ - - private int _Area; - private int _Days; - private int _Distance; - private int _Confidence; - - private readonly double _FaceAreaPermille; - private readonly double _RangeDaysDeltaTolerance; - private readonly double _FaceConfidencePercent; - private readonly double _FaceDistancePermyriad; - private readonly int _SortingMaximumPerFaceShouldBeHigh; - private readonly bool _RangeDaysDeltaTargetLessThenUpper; - - public MapLogicSupport(int faceConfidencePercent, - int faceDistancePermyriad, - int[] rangeDaysDeltaTolerance, - double[] rangeDistanceTolerance, - int[] rangeFaceAreaPermilleTolerance, - double[] rangeFaceConfidence, - int sortingMaximumPerFaceShouldBeHigh, - int? useFiltersCounter = null) - { - _SortingMaximumPerFaceShouldBeHigh = sortingMaximumPerFaceShouldBeHigh; - _RangeDaysDeltaTargetLessThenUpper = rangeDaysDeltaTolerance[1] > rangeDaysDeltaTolerance[2]; - if (useFiltersCounter is null) - { - _FaceAreaPermille = rangeFaceAreaPermilleTolerance[1]; - _RangeDaysDeltaTolerance = rangeDaysDeltaTolerance[1]; - _FaceConfidencePercent = faceConfidencePercent * rangeFaceConfidence[1]; - _FaceDistancePermyriad = faceDistancePermyriad * rangeDistanceTolerance[1]; - } - else - { - _RangeDaysDeltaTolerance = ((rangeDaysDeltaTolerance[2] - rangeDaysDeltaTolerance[0]) * 0.01 * useFiltersCounter.Value) + rangeDaysDeltaTolerance[1]; - _FaceConfidencePercent = faceConfidencePercent * ((rangeFaceConfidence[2] - rangeFaceConfidence[0]) * 0.01 * useFiltersCounter.Value) + rangeFaceConfidence[1]; - _FaceAreaPermille = ((rangeFaceAreaPermilleTolerance[2] - rangeFaceAreaPermilleTolerance[0]) * 0.01 * useFiltersCounter.Value) + rangeFaceAreaPermilleTolerance[1]; - _FaceDistancePermyriad = faceDistancePermyriad * ((rangeDistanceTolerance[2] - rangeDistanceTolerance[0]) * 0.01 * useFiltersCounter.Value) + rangeDistanceTolerance[1]; - } - } - - 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 l.ToString()).ToArray(); -#pragma warning restore - string eDistanceContentFileName = Path.Combine(eDistanceContentCollectionDirectory, $"{configuration.ResultAllInOne}.tvs"); - File.WriteAllLines(eDistanceContentFileName, results); - } - - private List GetSortingContainers(Configuration mapConfiguration, Face face, FaceDistance faceDistanceEncoding, List sortingCollection) - { - List results = new(); - SortingContainer sortingContainer; - Sorting[] collection = Shared.Models.Stateless.Methods.ISorting.Sort(sortingCollection); - foreach (Sorting sorting in collection) - { - if (face.Mapping?.MappingFromLocation is null || faceDistanceEncoding.NormalizedRectangle is null) - throw new NotSupportedException(); - if (!mapConfiguration.SaveSortingWithoutPerson && face.Mapping.MappingFromPerson is null) - continue; - if (sorting.DaysDelta > _RangeDaysDeltaTolerance) - { - _Days += 1; - continue; - } - if (sorting.DistancePermyriad > _FaceDistancePermyriad) - { - _Distance += 1; - continue; - } - if (face.Mapping.MappingFromLocation.ConfidencePercent < _FaceConfidencePercent) - { - _Confidence += 1; - continue; - } - if (face.Mapping.MappingFromLocation.AreaPermille < _FaceAreaPermille) - { - _Area += 1; - continue; - } - sortingContainer = new(face.Mapping, sorting); - results.Add(sortingContainer); - if (results.Count >= _SortingMaximumPerFaceShouldBeHigh) - break; - } - return results; - } - - private static List GetSortingCollection(MapLogic mapLogic, List faceDistanceEncodings, int i, FaceDistance faceDistanceEncoding) - { - List results; - List faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncoding); - results = mapLogic.GetSortingCollection(i, faceDistanceEncoding, faceDistanceLengths); - return results; - } - - private static FaceDistanceContainer[] GetFaceDistanceContainers(List distinctFilteredFaces) - { - FaceDistanceContainer[] results; - FaceDistance faceDistance; - FaceDistanceContainer faceDistanceContainer; - List collection = new(); - foreach (Face face in distinctFilteredFaces) - { - if (face.Mapping?.MappingFromLocation is null) - throw new NotSupportedException(); - if (face.FaceDistance?.Encoding is not FaceRecognitionDotNet.FaceEncoding faceEncoding) - continue; - faceDistance = new(face.Mapping.MappingFromLocation.ConfidencePercent, faceEncoding, face.Mapping.MappingFromItem.Id, face.Mapping.MappingFromItem.IsWrongYear, face.Mapping.MappingFromItem.MinimumDateTime, face.Mapping.MappingFromLocation.NormalizedRectangle); - faceDistanceContainer = new(face, faceDistance); - collection.Add(faceDistanceContainer); - } - results = collection.ToArray(); - return results; - } - - private static List GetFaceDistanceEncodings(FaceDistanceContainer[] faceDistanceContainers, List missingFaceDistanceContainers) - { - List faceDistanceEncodings = new(); - foreach (FaceDistanceContainer faceDistanceContainer in faceDistanceContainers) - { - if (faceDistanceContainer.FaceDistance.Encoding is null) - continue; - faceDistanceEncodings.Add(faceDistanceContainer.FaceDistance); - } - foreach (FaceDistanceContainer faceDistanceContainer in missingFaceDistanceContainers) - { - if (faceDistanceContainer.FaceDistance.Encoding is null) - continue; - faceDistanceEncodings.Add(faceDistanceContainer.FaceDistance); - } - return faceDistanceEncodings; - } - - public SortingContainer[] SetFaceMappingSortingCollectionThenGetSortingContainers(int maxDegreeOfParallelism, Configuration mapConfiguration, long ticks, MapLogic mapLogic, List distinctFilteredFaces, List missingFaceDistanceContainers) - { - 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(distinctFilteredFaces); - List faceDistanceEncodings = GetFaceDistanceEncodings(faceDistanceContainers, missingFaceDistanceContainers); - 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 }; - using ProgressBar progressBar = new(faceDistanceContainers.Length, message, options); - _ = Parallel.For(0, faceDistanceContainers.Length, parallelOptions, (i, state) => - { - progressBar.Tick(); - FaceDistance faceDistanceEncoding = faceDistanceContainers[i].FaceDistance; - if (mapLogic.Used(faceDistanceEncoding)) - return; - Face face = faceDistanceContainers[i].Face; - if (face.Mapping is null) - throw new NotSupportedException(); - List sortingCollection = GetSortingCollection(mapLogic, faceDistanceEncodings, i, faceDistanceEncoding); - if (!sortingCollection.Any()) - return; - List sortingContainers = GetSortingContainers(mapConfiguration, face, faceDistanceEncoding, sortingCollection); - if (sortingContainers.Any()) - { - lock (collection) - collection.AddRange(sortingContainers); - } - }); - if (!collection.Any()) - results = Array.Empty(); - else - { - if (_RangeDaysDeltaTargetLessThenUpper) - results = Shared.Models.Stateless.Methods.ISortingContainer.Sort(collection); - else - results = Shared.Models.Stateless.Methods.ISortingContainer.SortUsingDaysDelta(collection); - } - return results; - } - - public static Mapping[] GetSelectedMappingCollection(List distinctFilteredFaces) - { - Mapping[] results; - IEnumerable collection = from l in distinctFilteredFaces orderby l.Mapping?.MappingFromItem.Id select l.Mapping; - results = (from l in collection where l is not null select l).ToArray(); - return results; - } - - public static void SetFaceDistances(int maxDegreeOfParallelism, long ticks, List distinctFilteredFaces) - { - int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); - ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; - string message = $") {distinctFilteredFaces.Count:000} Load Face Encoding - {totalSeconds} total second(s)"; - ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - using ProgressBar progressBar = new(distinctFilteredFaces.Count, message, options); - _ = Parallel.For(0, distinctFilteredFaces.Count, parallelOptions, (i, state) => - { - Face face = distinctFilteredFaces[i]; - if (face.FaceEncoding is null || face.Mapping?.MappingFromLocation 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 faceDistance = new(face.Mapping.MappingFromLocation.ConfidencePercent, faceEncoding, face.Mapping.MappingFromItem.Id, face.Mapping.MappingFromItem.IsWrongYear, face.Mapping.MappingFromItem.MinimumDateTime, face.Mapping.MappingFromLocation.NormalizedRectangle); - lock (face) - face.SetFaceDistance(faceDistance); - }); - } - - public static Dictionary> GetIdToNormalizedRectangleToFace(Mapping[] mappingCollection) - { - Dictionary> results = new(); - Dictionary? keyValuePairs; - foreach (Mapping mapping in mappingCollection) - { - if (mapping.MappingFromLocation is null) - continue; - if (!results.TryGetValue(mapping.MappingFromItem.Id, out keyValuePairs)) - { - results.Add(mapping.MappingFromItem.Id, new()); - if (!results.TryGetValue(mapping.MappingFromItem.Id, out keyValuePairs)) - throw new Exception(); - } - if (keyValuePairs.ContainsKey(mapping.MappingFromLocation.NormalizedRectangle)) - continue; - keyValuePairs.Add(mapping.MappingFromLocation.NormalizedRectangle, mapping); - } - return results; - } - - string Shared.Models.Methods.IMapLogicSupport.GetCounts() - { - string result; - List<(int Value, string Name)> results = new() - { - new(_Area, nameof(_Area)), - new(_Confidence, nameof(_Confidence)), - new(_Days, nameof(_Days)), - new(_Distance, nameof(_Distance)) - }; - result = string.Join(' ', from l in results orderby l.Value descending select $"{l.Name}_{l.Value};"); - return result; - } - -} \ No newline at end of file diff --git a/Distance/Models/_E_Distance.cs b/Distance/Models/_E_Distance.cs index e61c9e4..53d149b 100644 --- a/Distance/Models/_E_Distance.cs +++ b/Distance/Models/_E_Distance.cs @@ -362,4 +362,167 @@ public partial class E_Distance return results; } + 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 l.ToString()).ToArray(); +#pragma warning restore + string eDistanceContentFileName = Path.Combine(eDistanceContentCollectionDirectory, $"{configuration.ResultAllInOne}.tvs"); + File.WriteAllLines(eDistanceContentFileName, results); + } + + public static void SetFaceDistances(int maxDegreeOfParallelism, long ticks, List distinctFilteredFaces) + { + int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; + string message = $") {distinctFilteredFaces.Count:000} Load Face Encoding - {totalSeconds} total second(s)"; + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + using ProgressBar progressBar = new(distinctFilteredFaces.Count, message, options); + _ = Parallel.For(0, distinctFilteredFaces.Count, parallelOptions, (i, state) => + { + Face face = distinctFilteredFaces[i]; + if (face.FaceEncoding is null || face.Mapping?.MappingFromLocation 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 faceDistance = new(face.Mapping.MappingFromLocation.ConfidencePercent, faceEncoding, face.Mapping.MappingFromItem.Id, face.Mapping.MappingFromItem.IsWrongYear, face.Mapping.MappingFromItem.MinimumDateTime, face.Mapping.MappingFromLocation.NormalizedRectangle); + lock (face) + face.SetFaceDistance(faceDistance); + }); + } + + private static List GetSortingContainers(Map.Models.Configuration mapConfiguration, Shared.Models.Methods.IDistanceLimits distanceLimits, Face face, FaceDistance faceDistanceEncoding, List sortingCollection) + { + List results = new(); + SortingContainer sortingContainer; + int area = 0, days = 0, distance = 0, confidence = 0; + Sorting[] collection = Shared.Models.Stateless.Methods.ISorting.Sort(sortingCollection); + foreach (Sorting sorting in collection) + { + if (face.Mapping?.MappingFromLocation is null || faceDistanceEncoding.NormalizedRectangle is null) + throw new NotSupportedException(); + if (!mapConfiguration.SaveSortingWithoutPerson && face.Mapping.MappingFromPerson is null) + continue; + if (sorting.DaysDelta > distanceLimits.RangeDaysDeltaTolerance) + { + days += 1; + continue; + } + if (sorting.DistancePermyriad > distanceLimits.FaceDistancePermyriad) + { + distance += 1; + continue; + } + if (face.Mapping.MappingFromLocation.ConfidencePercent < distanceLimits.FaceConfidencePercent) + { + confidence += 1; + continue; + } + if (face.Mapping.MappingFromLocation.AreaPermille < distanceLimits.FaceAreaPermille) + { + area += 1; + continue; + } + sortingContainer = new(face.Mapping, sorting); + results.Add(sortingContainer); + if (results.Count >= distanceLimits.SortingMaximumPerFaceShouldBeHigh) + break; + } + distanceLimits.AddCounts(area, days, distance, confidence); + return results; + } + + private static List GetSortingCollection(Map.Models.MapLogic mapLogic, List faceDistanceEncodings, int i, FaceDistance faceDistanceEncoding) + { + List results; + List faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncoding); + results = mapLogic.GetSortingCollection(i, faceDistanceEncoding, faceDistanceLengths); + return results; + } + + private static FaceDistanceContainer[] GetFaceDistanceContainers(Map.Models.MapLogic mapLogic, List distinctFilteredFaces) + { + FaceDistanceContainer[] results; + FaceDistance faceDistance; + FaceDistanceContainer faceDistanceContainer; + List collection = new(); + foreach (Face face in distinctFilteredFaces) + { + if (face.Mapping?.MappingFromLocation is null) + throw new NotSupportedException(); + if (face.Mapping.MappingFromItem.IsIgnoreRelativePath) + continue; + if (face.FaceDistance?.Encoding is not FaceRecognitionDotNet.FaceEncoding faceEncoding) + continue; + if (mapLogic.Used(face.FaceDistance)) + continue; + faceDistance = new(face.Mapping.MappingFromLocation.ConfidencePercent, faceEncoding, face.Mapping.MappingFromItem.Id, face.Mapping.MappingFromItem.IsWrongYear, face.Mapping.MappingFromItem.MinimumDateTime, face.Mapping.MappingFromLocation.NormalizedRectangle); + faceDistanceContainer = new(face, faceDistance); + collection.Add(faceDistanceContainer); + } + results = collection.ToArray(); + return results; + } + + private static List GetFaceDistanceEncodings(FaceDistanceContainer[] faceDistanceContainers, List missingFaceDistanceContainers) + { + List faceDistanceEncodings = new(); + foreach (FaceDistanceContainer faceDistanceContainer in faceDistanceContainers) + { + if (faceDistanceContainer.FaceDistance.Encoding is null) + continue; + faceDistanceEncodings.Add(faceDistanceContainer.FaceDistance); + } + foreach (FaceDistanceContainer faceDistanceContainer in missingFaceDistanceContainers) + { + if (faceDistanceContainer.FaceDistance.Encoding is null) + continue; + faceDistanceEncodings.Add(faceDistanceContainer.FaceDistance); + } + return faceDistanceEncodings; + } + + public static SortingContainer[] SetFaceMappingSortingCollectionThenGetSortingContainers(int maxDegreeOfParallelism, Map.Models.Configuration mapConfiguration, long ticks, Map.Models.MapLogic mapLogic, Shared.Models.Methods.IDistanceLimits distanceLimits, List distinctFilteredFaces, List missingFaceDistanceContainers) + { + 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(mapLogic, distinctFilteredFaces); + List faceDistanceEncodings = GetFaceDistanceEncodings(faceDistanceContainers, missingFaceDistanceContainers); + 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 }; + using ProgressBar progressBar = new(faceDistanceContainers.Length, message, options); + _ = Parallel.For(0, faceDistanceContainers.Length, parallelOptions, (i, state) => + { + progressBar.Tick(); + FaceDistance faceDistanceEncoding = faceDistanceContainers[i].FaceDistance; + Face face = faceDistanceContainers[i].Face; + List sortingCollection = GetSortingCollection(mapLogic, faceDistanceEncodings, i, faceDistanceEncoding); + if (!sortingCollection.Any()) + return; + List sortingContainers = GetSortingContainers(mapConfiguration, distanceLimits, face, faceDistanceEncoding, sortingCollection); + if (sortingContainers.Any()) + { + lock (collection) + collection.AddRange(sortingContainers); + } + }); + if (!collection.Any()) + results = Array.Empty(); + else + { + if (distanceLimits.RangeDaysDeltaTargetLessThenUpper) + results = Shared.Models.Stateless.Methods.ISortingContainer.Sort(collection); + else + results = Shared.Models.Stateless.Methods.ISortingContainer.SortUsingDaysDelta(collection); + } + return results; + } + } \ No newline at end of file diff --git a/Duplicate-Search/DuplicateSearch.cs b/Duplicate-Search/DuplicateSearch.cs index f1a4be0..0b61af3 100644 --- a/Duplicate-Search/DuplicateSearch.cs +++ b/Duplicate-Search/DuplicateSearch.cs @@ -36,7 +36,7 @@ public class DuplicateSearch Container[] containers = GetContainers(appSettings, ticks, argZero, configuration, argZeroIsConfigurationRootDirectory); string destinationRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(configuration, "Z) Moved"); List preloadIds = GetPreloadIds(destinationRoot); - Dictionary> idToCollection = GetIdToCollection(appSettings, argZero, configuration, argZeroIsConfigurationRootDirectory, containers, destinationRoot, preloadIds); + Dictionary> idToCollection = GetIdToCollection(argZero, configuration, argZeroIsConfigurationRootDirectory, containers, destinationRoot, preloadIds); int duplicates = (from l in idToCollection where l.Value.Count > 1 select 1).Sum(); if (duplicates == 0) log.Information($"Found {duplicates} duplicate file(s)"); @@ -144,17 +144,17 @@ public class DuplicateSearch return containers; } - private static Dictionary> GetIdToCollection(AppSettings appSettings, string argZero, Configuration configuration, bool argZeroIsConfigurationRootDirectory, Container[] containers, string destinationRoot, List preloadIds) + private static Dictionary> GetIdToCollection(string argZero, Configuration configuration, bool argZeroIsConfigurationRootDirectory, Container[] containers, string destinationRoot, List preloadIds) { Dictionary> results = new(); string directory; const int zero = 0; Item[] filteredItems; - bool isIgnoreRelativePath; FileHolder resizedFileHolder; DateTime[] containerDateTimes; MappingFromItem? mappingFromItem; List? collection; + const bool isIgnoreRelativePath = false; const string duplicates = "-Duplicate(s)"; if (containers.Any()) { @@ -170,7 +170,6 @@ public class DuplicateSearch filteredItems = Shared.Models.Stateless.Methods.IContainer.GetFilterItems(configuration, container); if (!filteredItems.Any()) continue; - isIgnoreRelativePath = appSettings.IgnoreRelativePaths.Any(l => container.SourceDirectory.Contains(l)) && Shared.Models.Stateless.Methods.IContainer.IsIgnoreRelativePath(configuration, appSettings.IgnoreRelativePaths, container.SourceDirectory); containerDateTimes = Shared.Models.Stateless.Methods.IContainer.GetContainerDateTimes(filteredItems); foreach (Item item in filteredItems) { @@ -194,11 +193,11 @@ public class DuplicateSearch if (mappingFromItem is not null) { resizedFileHolder = new(mappingFromItem.ResizedFileHolder.FullName.Replace($"0{duplicates}", $"1{duplicates}")); - collection[0] = new(mappingFromItem.ContainerDateTimes, mappingFromItem.Id, mappingFromItem.ImageFileHolder, mappingFromItem.IsWrongYear, mappingFromItem.MinimumDateTime, mappingFromItem.RelativePath, resizedFileHolder); + collection[0] = new(mappingFromItem.ContainerDateTimes, mappingFromItem.Id, mappingFromItem.ImageFileHolder, mappingFromItem.IsIgnoreRelativePath, mappingFromItem.IsWrongYear, mappingFromItem.MinimumDateTime, mappingFromItem.RelativePath, resizedFileHolder); } } resizedFileHolder = new(string.Concat(Path.Combine(destinationRoot, directory), item.RelativePath)); - mappingFromItem = Shared.Models.Stateless.Methods.IMappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder); + mappingFromItem = Shared.Models.Stateless.Methods.IMappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder, isIgnoreRelativePath); collection.Add(mappingFromItem); } } diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index de4c275..9cfee8f 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -252,6 +252,7 @@ public partial class DlibDotNet configuration.RangeDaysDeltaTolerance, configuration.RangeDistanceTolerance, configuration.SaveSortingWithoutPerson, + configuration.SkipNotSkipDirectories, configuration.SortingMaximumPerKey, configuration.SortingMinimumToUseSigma, facesFileNameExtension, @@ -325,7 +326,8 @@ public partial class DlibDotNet item.SetResizedFileHolder(_Resize.FileNameExtension, resizedFileHolder); string facesDirectory = _Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution) ? _Faces.GetFacesDirectory(dResultsFullGroupDirectory, item) : string.Empty; string facePartsDirectory = _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution) ? _FaceParts.GetFacePartsDirectory(_Configuration.PropertyConfiguration, dResultsFullGroupDirectory, item) : string.Empty; - MappingFromItem mappingFromItem = Shared.Models.Stateless.Methods.IMappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder); + bool isIgnoreRelativePath = _Configuration.IgnoreRelativePaths.Any(l => container.SourceDirectory.Contains(l)) && Shared.Models.Stateless.Methods.IContainer.IsIgnoreRelativePath(_Configuration.PropertyConfiguration, _Configuration.IgnoreRelativePaths, container.SourceDirectory); + MappingFromItem mappingFromItem = Shared.Models.Stateless.Methods.IMappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder, isIgnoreRelativePath); (int metadataGroups, metadataCollection) = metadata.GetMetadataCollection(subFileTuples, parseExceptions, mappingFromItem); if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(B_Metadata.GetMetadataCollection)); @@ -595,6 +597,7 @@ public partial class DlibDotNet Item[] filteredItems; int confidencePercent; int normalizedRectangle; + bool isIgnoreRelativePath; DateTime[] containerDateTimes; string deterministicHashCodeKey; MappingFromItem mappingFromItem; @@ -610,11 +613,12 @@ public partial class DlibDotNet if (!filteredItems.Any()) continue; containerDateTimes = Shared.Models.Stateless.Methods.IContainer.GetContainerDateTimes(filteredItems); + isIgnoreRelativePath = _Configuration.IgnoreRelativePaths.Any(l => container.SourceDirectory.Contains(l)) && Shared.Models.Stateless.Methods.IContainer.IsIgnoreRelativePath(_Configuration.PropertyConfiguration, _Configuration.IgnoreRelativePaths, container.SourceDirectory); foreach (Item item in filteredItems) { if (item.Property?.Id is null || item.ResizedFileHolder is null) continue; - mappingFromItem = Shared.Models.Stateless.Methods.IMappingFromItem.GetMappingFromItem(containerDateTimes, item); + mappingFromItem = Shared.Models.Stateless.Methods.IMappingFromItem.GetMappingFromItem(containerDateTimes, item, isIgnoreRelativePath); foreach (Shared.Models.Face face in item.Faces) { if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null) @@ -641,7 +645,6 @@ public partial class DlibDotNet List resultIds = new(); List resultFaces = new(); Item[] filteredItems; - bool isIgnoreRelativePath; foreach (Container container in containers) { if (!container.Items.Any()) @@ -651,7 +654,6 @@ public partial class DlibDotNet filteredItems = Shared.Models.Stateless.Methods.IContainer.GetFilterItems(_Configuration.PropertyConfiguration, container); if (!filteredItems.Any()) continue; - isIgnoreRelativePath = _Configuration.IgnoreRelativePaths.Any(l => container.SourceDirectory.Contains(l)) && Shared.Models.Stateless.Methods.IContainer.IsIgnoreRelativePath(_Configuration.PropertyConfiguration, _Configuration.IgnoreRelativePaths, container.SourceDirectory); foreach (Item item in filteredItems) { if (item.Property?.Id is null || item.ResizedFileHolder is null) @@ -659,8 +661,6 @@ public partial class DlibDotNet if (resultIds.Contains(item.Property.Id.Value)) continue; resultIds.Add(item.Property.Id.Value); - if (isIgnoreRelativePath) - continue; foreach (Shared.Models.Face face in item.Faces) { if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null) @@ -676,8 +676,6 @@ public partial class DlibDotNet { List items = new(); Item[] filteredItems; - bool isIgnoreRelativePath; - List collection = new(); foreach (Container container in containers) { if (!container.Items.Any()) @@ -687,7 +685,6 @@ public partial class DlibDotNet filteredItems = Shared.Models.Stateless.Methods.IContainer.GetFilterItems(_Configuration.PropertyConfiguration, container); if (!filteredItems.Any()) continue; - isIgnoreRelativePath = _Configuration.IgnoreRelativePaths.Any(l => container.SourceDirectory.Contains(l)) && Shared.Models.Stateless.Methods.IContainer.IsIgnoreRelativePath(_Configuration.PropertyConfiguration, _Configuration.IgnoreRelativePaths, container.SourceDirectory); foreach (Item item in filteredItems) { if (item.Property?.Id is null || item.ResizedFileHolder is null) @@ -705,7 +702,7 @@ public partial class DlibDotNet string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, "()"); string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, "()"); string dFacesCollectionDirectory = Path.Combine(dResultsFullGroupDirectory, "[]", _Configuration.PropertyConfiguration.ResultAllInOne); - Dictionary> idToNormalizedRectangleToMapping = MapLogicSupport.GetIdToNormalizedRectangleToFace(mappingCollection); + Dictionary> idToNormalizedRectangleToMapping = Map.Models.Stateless.Methods.IMapLogic.GetIdToNormalizedRectangleToFace(mappingCollection); if (Directory.Exists(fPhotoPrismContentDirectory)) F_PhotoPrism.WriteMatches(fPhotoPrismContentDirectory, _Configuration.PersonBirthdayFormat, ticks, distinctFilteredFaces, mapLogic); if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) @@ -720,27 +717,26 @@ public partial class DlibDotNet mapLogic.SaveMapped(dFacesContentDirectory, d2FacePartsContentDirectory, personKeyToIds, mappingCollection, idToNormalizedRectangleToMapping, totalNotMapped); if (_Configuration.SaveFaceDistancesForOutputResolutions.Contains(outputResolution)) { - MapLogicSupport mapLogicSupport; - MapLogicSupport.SetFaceDistances(_AppSettings.MaxDegreeOfParallelism, ticks, distinctFilteredFaces); - List distinctFurtherFilteredFaces = mapLogic.GetFurtherFilterBySkipCollection(distinctFilteredFaces); + DistanceLimits distanceLimits; + E_Distance.SetFaceDistances(_AppSettings.MaxDegreeOfParallelism, ticks, distinctFilteredFaces); Dictionary> missingIdThenNormalizedRectangleToPersonContainers = mapLogic.GetMissing(idToNormalizedRectangleToMapping); List missingFaceDistanceContainers = _Distance.GetMissingFaceDistanceContainer(_AppSettings.MaxDegreeOfParallelism, ticks, dFacesCollectionDirectory, missingIdThenNormalizedRectangleToPersonContainers); - mapLogicSupport = new(_Configuration.FaceConfidencePercent, _Configuration.FaceDistancePermyriad, _Configuration.RangeDaysDeltaTolerance, _Configuration.RangeDistanceTolerance, _Configuration.RangeFaceAreaPermilleTolerance, _Configuration.RangeFaceConfidence, _Configuration.SortingMaximumPerFaceShouldBeHigh); - sortingContainers = mapLogicSupport.SetFaceMappingSortingCollectionThenGetSortingContainers(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, ticks, mapLogic, distinctFurtherFilteredFaces, missingFaceDistanceContainers); + distanceLimits = new(_Configuration.FaceConfidencePercent, _Configuration.FaceDistancePermyriad, _Configuration.RangeDaysDeltaTolerance, _Configuration.RangeDistanceTolerance, _Configuration.RangeFaceAreaPermilleTolerance, _Configuration.RangeFaceConfidence, _Configuration.SortingMaximumPerFaceShouldBeHigh); + sortingContainers = E_Distance.SetFaceMappingSortingCollectionThenGetSortingContainers(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, ticks, mapLogic, distanceLimits, distinctFilteredFaces, missingFaceDistanceContainers); if (!sortingContainers.Any()) { - for (useFiltersCounter = 1; useFiltersCounter < 17; useFiltersCounter++) + for (useFiltersCounter = 1; useFiltersCounter < _Configuration.UseFilterTries; useFiltersCounter++) { - mapLogicSupport = new(_Configuration.FaceConfidencePercent, _Configuration.FaceDistancePermyriad, _Configuration.RangeDaysDeltaTolerance, _Configuration.RangeDistanceTolerance, _Configuration.RangeFaceAreaPermilleTolerance, _Configuration.RangeFaceConfidence, _Configuration.SortingMaximumPerFaceShouldBeHigh, useFiltersCounter); - sortingContainers = mapLogicSupport.SetFaceMappingSortingCollectionThenGetSortingContainers(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, ticks, mapLogic, distinctFurtherFilteredFaces, missingFaceDistanceContainers); + distanceLimits = new(_Configuration.FaceConfidencePercent, _Configuration.FaceDistancePermyriad, _Configuration.RangeDaysDeltaTolerance, _Configuration.RangeDistanceTolerance, _Configuration.RangeFaceAreaPermilleTolerance, _Configuration.RangeFaceConfidence, _Configuration.SortingMaximumPerFaceShouldBeHigh, useFiltersCounter); + sortingContainers = E_Distance.SetFaceMappingSortingCollectionThenGetSortingContainers(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, ticks, mapLogic, distanceLimits, distinctFilteredFaces, missingFaceDistanceContainers); if (sortingContainers.Any()) break; } } - MapLogicSupport.SaveFaceDistances(_Configuration.PropertyConfiguration, sortingContainers); + E_Distance.SaveFaceDistances(_Configuration.PropertyConfiguration, sortingContainers); if (totalNotMapped > 0) { - int updated = mapLogic.UpdateFromSortingContainers(mapLogicSupport, sortingContainers); + int updated = mapLogic.UpdateFromSortingContainers(distanceLimits, sortingContainers); List saveContainers = mapLogic.GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, mappingCollection, idToNormalizedRectangleToMapping, useFiltersCounter, sortingContainers.Any()); mapLogic.SaveContainers(totalNotMapped, updated, saveContainers); } @@ -1061,7 +1057,7 @@ public partial class DlibDotNet personKeyToIds = mapLogic.GetPersonKeyToIds(); (List distinctFilteredIds, List distinctFilteredFaces) = GetFilteredDistinct(argZero, containers); LookForAbandoned(idToLocationContainers, distinctFilteredIds); - Mapping[] mappingCollection = MapLogicSupport.GetSelectedMappingCollection(distinctFilteredFaces); + Mapping[] mappingCollection = Map.Models.Stateless.Methods.IMapLogic.GetSelectedMappingCollection(distinctFilteredFaces); int totalNotMapped = mapLogic.UpdateMappingFromPerson(mappingCollection); string json = System.Text.Json.JsonSerializer.Serialize(mappingCollection); File.WriteAllText(Path.Combine(eDistanceContentDirectory, $"{ticks}.json"), json); diff --git a/Instance/Models/Binder/Configuration.cs b/Instance/Models/Binder/Configuration.cs index 012db03..c98eafd 100644 --- a/Instance/Models/Binder/Configuration.cs +++ b/Instance/Models/Binder/Configuration.cs @@ -72,11 +72,13 @@ public class Configuration [Display(Name = "Save Resized Subfiles"), Required] public bool? SaveResizedSubfiles { get; set; } [Display(Name = "Save Shortcuts"), Required] public string[] SaveShortcutsForOutputResolutions { get; set; } [Display(Name = "Save Sorting Without Person"), Required] public bool? SaveSortingWithoutPerson { get; set; } + [Display(Name = "Skip Not Skip Directories"), Required] public string[] SkipNotSkipDirectories { get; set; } [Display(Name = "Skip Search"), Required] public bool? SkipSearch { get; set; } [Display(Name = "SortingMaximumPerFaceShould be High"), Required] public int? SortingMaximumPerFaceShouldBeHigh { get; set; } [Display(Name = "Sorting Maximum Per Key"), Required] public int? SortingMaximumPerKey { get; set; } [Display(Name = "Sorting Minimum to use Sigma"), Required] public int? SortingMinimumToUseSigma { get; set; } [Display(Name = "Test Distance Results"), Required] public bool? TestDistanceResults { get; set; } + [Display(Name = "Use Filter Tries"), Required] public int? UseFilterTries { get; set; } [Display(Name = "Valid Resolutions"), Required] public string[] ValidResolutions { get; set; } #nullable restore @@ -195,6 +197,7 @@ public class Configuration throw new NullReferenceException(nameof(configuration.SaveResizedSubfiles)); configuration.SaveShortcutsForOutputResolutions ??= Array.Empty(); configuration.SaveShortcutsForOutputResolutions ??= Array.Empty(); + configuration.SkipNotSkipDirectories ??= Array.Empty(); if (configuration.SaveSortingWithoutPerson is null) throw new NullReferenceException(nameof(configuration.SaveSortingWithoutPerson)); if (configuration.SkipSearch is null) @@ -207,6 +210,8 @@ public class Configuration throw new NullReferenceException(nameof(configuration.SortingMinimumToUseSigma)); if (configuration.TestDistanceResults is null) throw new NullReferenceException(nameof(configuration.TestDistanceResults)); + if (configuration.UseFilterTries is null) + throw new NullReferenceException(nameof(configuration.UseFilterTries)); if (configuration.ValidResolutions is null) throw new NullReferenceException(nameof(configuration.ValidResolutions)); _ = DateTime.Now.AddDays(-configuration.RangeDaysDeltaTolerance[1]); @@ -270,11 +275,13 @@ public class Configuration configuration.SaveResizedSubfiles.Value, configuration.SaveShortcutsForOutputResolutions, configuration.SaveSortingWithoutPerson.Value, + configuration.SkipNotSkipDirectories, configuration.SkipSearch.Value, configuration.SortingMaximumPerFaceShouldBeHigh.Value, configuration.SortingMaximumPerKey.Value, configuration.SortingMinimumToUseSigma.Value, configuration.TestDistanceResults.Value, + configuration.UseFilterTries.Value, configuration.ValidResolutions); return result; } diff --git a/Instance/Models/Configuration.cs b/Instance/Models/Configuration.cs index ac2412e..ee64ef6 100644 --- a/Instance/Models/Configuration.cs +++ b/Instance/Models/Configuration.cs @@ -68,11 +68,13 @@ public class Configuration public bool SaveResizedSubfiles { init; get; } public string[] SaveShortcutsForOutputResolutions { init; get; } public bool SaveSortingWithoutPerson { init; get; } + public string[] SkipNotSkipDirectories { init; get; } public bool SkipSearch { init; get; } public int SortingMaximumPerFaceShouldBeHigh { init; get; } public int SortingMaximumPerKey { init; get; } public int SortingMinimumToUseSigma { init; get; } public bool TestDistanceResults { init; get; } + public int UseFilterTries { init; get; } public string[] ValidResolutions { init; get; } [JsonConstructor] @@ -136,11 +138,13 @@ public class Configuration bool saveResizedSubfiles, string[] saveShortcutsForOutputResolutions, bool saveSortingWithoutPerson, + string[] skipNotSkipDirectories, bool skipSearch, int sortingMaximumPerFaceShouldBeHigh, int sortingMaximumPerKey, int sortingSigma, bool testDistanceResults, + int useFilterTries, string[] validResolutions) { _PropertyConfiguration = propertyConfiguration; @@ -203,11 +207,13 @@ public class Configuration SaveRandomForOutputResolutions = saveRandomForOutputResolutions; SaveShortcutsForOutputResolutions = saveShortcutsForOutputResolutions; SaveSortingWithoutPerson = saveSortingWithoutPerson; + SkipNotSkipDirectories = skipNotSkipDirectories; SkipSearch = skipSearch; SortingMaximumPerFaceShouldBeHigh = sortingMaximumPerFaceShouldBeHigh; SortingMaximumPerKey = sortingMaximumPerKey; SortingMinimumToUseSigma = sortingSigma; TestDistanceResults = testDistanceResults; + UseFilterTries = useFilterTries; ValidResolutions = validResolutions; } diff --git a/Instance/Models/_F_Random.cs b/Instance/Models/_F_Random.cs index bbfd818..3303ea6 100644 --- a/Instance/Models/_F_Random.cs +++ b/Instance/Models/_F_Random.cs @@ -25,24 +25,6 @@ internal class F_Random return result; } - private bool IsIgnoreRelativePath(string directory) - { - bool result = false; - string? checkDirectory = Path.GetFullPath(directory); - for (int i = 0; i < int.MaxValue; i++) - { - if (_Configuration.IgnoreRelativePaths.Contains(Path.GetFileName(checkDirectory))) - { - result = true; - break; - } - checkDirectory = Path.GetDirectoryName(checkDirectory); - if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == _Configuration.PropertyConfiguration.RootDirectory) - break; - } - return result; - } - private static Dictionary> Get(Dictionary> personKeyToIds, Shared.Models.Mapping[] mappingCollection, string dateFormat) { Dictionary> results = new(); @@ -95,7 +77,7 @@ internal class F_Random { if (mapping.MappingFromItem.ImageFileHolder.DirectoryName is null) continue; - if (_Configuration.IgnoreRelativePaths.Any(l => mapping.MappingFromItem.ImageFileHolder.DirectoryName.Contains(l)) && IsIgnoreRelativePath(mapping.MappingFromItem.ImageFileHolder.DirectoryName)) + if (mapping.MappingFromItem.IsIgnoreRelativePath) continue; relativePaths.Add(mapping.MappingFromItem.RelativePath); } diff --git a/Instance/appsettings.Development.json b/Instance/appsettings.Development.json index 99938f1..6f680b2 100644 --- a/Instance/appsettings.Development.json +++ b/Instance/appsettings.Development.json @@ -65,6 +65,25 @@ "SaveMappedForOutputResolutions": [], "SaveRandomForOutputResolutions": [], "SaveShortcutsForOutputResolutions": [], + "SkipNotSkipDirectories": [], + "xSkipNotSkipDirectories": [ + "/!/_ Images-To-Do", + "/!/_ Test", + "/!/Disney", + "/!/Chelsea's Friends", + "/!/Jason's Friends", + "/!/Johnny's Friends", + "/!/Julie's Friends", + "/!/Kristy's Family", + "/!/Kristy's Friends", + "/!/Logan Friends", + "/!/Mackenzie Friends", + "/!/Mike's Family", + "/!/Mike's Friends", + "/!/Statue", + "/!/Tracy's Friend", + "/!/Wax" + ], "IgnoreRelativePaths": [ "3757 W Whitman 2017", "501 Playful Meadows 2006", diff --git a/Instance/appsettings.json b/Instance/appsettings.json index d902eb2..b1e64e5 100644 --- a/Instance/appsettings.json +++ b/Instance/appsettings.json @@ -111,6 +111,7 @@ "SortingMaximumPerKey": 7, "SortingMinimumToUseSigma": 10, "TestDistanceResults": true, + "UseFilterTries": 0, "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", @@ -155,6 +156,7 @@ "SaveMappedForOutputResolutions": [], "SaveRandomForOutputResolutions": [], "SaveShortcutsForOutputResolutions": [], + "SkipNotSkipDirectories": [], "VerifyToSeason": [], "ValidImageFormatExtensions": [ ".bmp", diff --git a/Map/Models/Configuration.cs b/Map/Models/Configuration.cs index 270d9d3..2eb06fd 100644 --- a/Map/Models/Configuration.cs +++ b/Map/Models/Configuration.cs @@ -19,6 +19,7 @@ public class Configuration public int RangeDaysDeltaTolerance { init; get; } public double RangeDistanceTolerance { init; get; } public bool SaveSortingWithoutPerson { init; get; } + public string[] SkipNotSkipDirectories { init; get; } public int SortingMaximumPerKey { init; get; } public int SortingMinimumToUseSigma { init; get; } @@ -33,6 +34,7 @@ public class Configuration int[] rangeDaysDeltaTolerance, double[] rangeDistanceTolerance, bool saveSortingWithoutPerson, + string[] skipNotSkipDirectories, int sortingMaximumPerKey, int sortingMinimumToUseSigma, string facesFileNameExtension, @@ -46,6 +48,7 @@ public class Configuration FaceConfidencePercent = faceConfidencePercent; FaceDistancePermyriad = faceDistancePermyriad; FacesFileNameExtension = facesFileNameExtension; + SkipNotSkipDirectories = skipNotSkipDirectories; PersonBirthdayFirstYear = personBirthdayFirstYear; RangeDistanceTolerance = rangeDistanceTolerance[1]; SaveSortingWithoutPerson = saveSortingWithoutPerson; diff --git a/Map/Models/MapLogic.cs b/Map/Models/MapLogic.cs index c51d2af..d60f87b 100644 --- a/Map/Models/MapLogic.cs +++ b/Map/Models/MapLogic.cs @@ -14,6 +14,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic protected readonly List _NotMappedPersonContainers; protected readonly ReadOnlyDictionary> _SkipCollection; + protected readonly ReadOnlyDictionary> _SkipNotSkipCollection; protected readonly ReadOnlyDictionary _PersonKeyToPersonContainer; protected readonly ReadOnlyDictionary> _IdThenNormalizedRectangleToPersonContainers; @@ -45,6 +46,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic List>? collection; Dictionary> skipCollection = new(); List notMappedPersonContainers = new(); + Dictionary> skipNotSkipCollection = new(); Dictionary personKeyToPersonContainer = new(); string? rootDirectoryParent = Path.GetDirectoryName(propertyConfiguration.RootDirectory); string eDistanceContentTicksDirectory = Path.Combine(eDistanceContentDirectory, $"({ticks})"); @@ -69,6 +71,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic personKeyToPersonContainer, notMappedPersonContainers, skipCollection, + skipNotSkipCollection, idThenNormalizedRectangleToPersonContainers); if (personContainerCollection.Count == personContainers.Length) throw new NotSupportedException(); @@ -86,6 +89,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic throw new NullReferenceException(nameof(collection)); } _SkipCollection = new(skipCollection); + _SkipNotSkipCollection = new(skipNotSkipCollection); _PersonKeyToPersonContainer = new(personKeyToPersonContainer); _EDistanceContentTicksDirectory = eDistanceContentTicksDirectory; _NotMappedPersonContainers = notMappedPersonContainers.OrderByDescending(l => l.Key).ToList(); @@ -441,6 +445,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic FileHolder hiddenFaceFileHolder; List? normalizedRectangles; Dictionary? normalizedRectangleToMapping; + bool skipNotSkipDirectoriesAny = _Configuration.SkipNotSkipDirectories.Any(); string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title); foreach (Mapping mapping in mappingCollection) { @@ -451,6 +456,8 @@ public class MapLogic : Shared.Models.Methods.IMapLogic throw new NotSupportedException(); if (_SkipCollection.TryGetValue(mapping.MappingFromItem.Id, out normalizedRectangles) && normalizedRectangles.Contains(mapping.MappingFromLocation.NormalizedRectangle)) continue; + if (mapping.By is null && skipNotSkipDirectoriesAny) + continue; (by, isByMapping, isBySorting) = Get(useFiltersCounter, sortingContainersAny, forceSingleImageHumanized, mapping); if (isByMapping && !saveMapped) continue; @@ -593,6 +600,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic Sorting sorting; FaceDistance faceDistanceLength; List? normalizedRectangles; + bool skipNotSkipCollectionAny = _SkipNotSkipCollection.Any(); Dictionary? normalizedRectangleToPersonContainers; for (int j = 0; j < faceDistanceLengths.Count; j++) { @@ -602,6 +610,8 @@ public class MapLogic : Shared.Models.Methods.IMapLogic continue; if (_SkipCollection.TryGetValue(faceDistanceEncoding.Id, out normalizedRectangles) && normalizedRectangles.Contains(faceDistanceEncoding.NormalizedRectangle.Value)) continue; + if (skipNotSkipCollectionAny && (!_SkipNotSkipCollection.TryGetValue(faceDistanceEncoding.Id, out normalizedRectangles) || !normalizedRectangles.Contains(faceDistanceEncoding.NormalizedRectangle.Value))) + continue; if (_IdThenNormalizedRectangleToPersonContainers.TryGetValue(faceDistanceEncoding.Id, out normalizedRectangleToPersonContainers)) { if (normalizedRectangleToPersonContainers.ContainsKey(faceDistanceEncoding.NormalizedRectangle.Value)) @@ -626,13 +636,13 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return results; } - public int UpdateFromSortingContainers(Shared.Models.Methods.IMapLogicSupport mapLogicSupport, SortingContainer[] sortingContainers) + public int UpdateFromSortingContainers(Shared.Models.Methods.IDistanceLimits distanceLimits, SortingContainer[] sortingContainers) { if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); - if (mapLogicSupport is not null) + if (distanceLimits is not null) { - string counts = mapLogicSupport.GetCounts(); + string counts = distanceLimits.GetCounts(); _ = Directory.CreateDirectory(Path.Combine(_EDistanceContentTicksDirectory, counts)); } int result = 0; @@ -1319,19 +1329,4 @@ public class MapLogic : Shared.Models.Methods.IMapLogic return results; } - public List GetFurtherFilterBySkipCollection(List distinctFilteredFaces) - { - List results = new(); - List? normalizedRectangles; - foreach (Face face in distinctFilteredFaces) - { - if (face.Mapping?.MappingFromLocation is null) - continue; - if (_SkipCollection.TryGetValue(face.Mapping.MappingFromItem.Id, out normalizedRectangles) && normalizedRectangles.Contains(face.Mapping.MappingFromLocation.NormalizedRectangle)) - continue; - results.Add(face); - } - return results; - } - } \ No newline at end of file diff --git a/Map/Models/Stateless/MapLogic.cs b/Map/Models/Stateless/MapLogic.cs index d76db7d..b58dc95 100644 --- a/Map/Models/Stateless/MapLogic.cs +++ b/Map/Models/Stateless/MapLogic.cs @@ -36,13 +36,15 @@ internal abstract class MapLogic return results; } - private static void SetPersonCollections(Configuration configuration, List personContainers, List personKeys, Dictionary personKeyFormattedToNewestPersonKeyFormatted, List personKeyFormattedCollection, Dictionary> skipCollection) + private static void SetPersonCollections(Configuration configuration, List personContainers, string? a2PeopleSingletonDirectory, List personKeys, Dictionary personKeyFormattedToNewestPersonKeyFormatted, List personKeyFormattedCollection, Dictionary> skipCollection, Dictionary> skipNotSkipCollection) { int? id; long personKey; - string personKeyFormatted; int? normalizedRectangle; + string personKeyFormatted; string newestPersonKeyFormatted; + bool skipNotSkipDirectoriesAny = configuration.SkipNotSkipDirectories.Any(); + string[] checkDirectories = (from l in configuration.SkipNotSkipDirectories select Path.GetFullPath(string.Concat(a2PeopleSingletonDirectory, l))).ToArray(); foreach (PersonContainer personContainer in personContainers) { foreach (string personDisplayDirectoryAllFile in personContainer.DisplayDirectoryAllFiles) @@ -52,9 +54,18 @@ internal abstract class MapLogic (id, normalizedRectangle) = IMapping.GetConverted(configuration.FacesFileNameExtension, personDisplayDirectoryAllFile); if (id is null || normalizedRectangle is null) continue; - if (!skipCollection.ContainsKey(id.Value)) - skipCollection.Add(id.Value, new()); - skipCollection[id.Value].Add(normalizedRectangle.Value); + if (!skipNotSkipDirectoriesAny || !checkDirectories.Any(l => personDisplayDirectoryAllFile.StartsWith(l))) + { + if (!skipCollection.ContainsKey(id.Value)) + skipCollection.Add(id.Value, new()); + skipCollection[id.Value].Add(normalizedRectangle.Value); + } + else + { + if (!skipNotSkipCollection.ContainsKey(id.Value)) + skipNotSkipCollection.Add(id.Value, new()); + skipNotSkipCollection[id.Value].Add(normalizedRectangle.Value); + } } if (personContainer.Person is null || personContainer.Key is null || personContainer.Birthdays is null || !personContainer.Birthdays.Any()) continue; @@ -266,7 +277,7 @@ internal abstract class MapLogic return results.ToArray(); } - private static void SetKeyValuePairs(Configuration configuration, List personContainers, Dictionary> personKeyToPersonContainerCollection, Dictionary personKeyFormattedToPersonContainer, List<(string, string[], int, int)> personKeyFormattedIdThenNormalizedRectangleCollection, Dictionary personKeyToPersonContainer, Dictionary> idThenNormalizedRectangleToPersonContainers, List<(string[], PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer, Dictionary> incorrectIdThenNormalizedRectangleToPersonContainers) + private static void SetKeyValuePairs(Configuration configuration, List personContainers, Dictionary> personKeyToPersonContainerCollection, Dictionary personKeyFormattedToPersonContainer, List<(string, string[], int, int)> personKeyFormattedIdThenNormalizedRectangleCollection, Dictionary personKeyToPersonContainer, Dictionary> idThenNormalizedRectangleToPersonContainers, List<(string[], PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer) { PersonBirthday? personBirthday; PersonContainer[] distinctPersonContainers; @@ -274,7 +285,6 @@ internal abstract class MapLogic foreach ((long personKey, PersonContainer personContainer) in collection) personKeyToPersonContainer.Add(personKey, personContainer); Dictionary>> idThenNormalizedRectangleToPersonContainerCollection = new(); - Dictionary>> incorrectIdThenNormalizedRectangleToPersonContainerCollection = new(); if (personKeyFormattedIdThenNormalizedRectangleCollection.Any()) { string personDisplayDirectory; @@ -313,15 +323,6 @@ internal abstract class MapLogic idThenNormalizedRectangleToPersonContainers[keyValuePair.Key].Add(innerKeyValuePair.Key, distinctPersonContainers); } }; - foreach (KeyValuePair>> keyValuePair in incorrectIdThenNormalizedRectangleToPersonContainerCollection) - { - incorrectIdThenNormalizedRectangleToPersonContainers.Add(keyValuePair.Key, new()); - foreach (KeyValuePair> innerKeyValuePair in keyValuePair.Value) - { - distinctPersonContainers = GetDistinctPersonContainers(innerKeyValuePair.Value); - incorrectIdThenNormalizedRectangleToPersonContainers[keyValuePair.Key].Add(innerKeyValuePair.Key, distinctPersonContainers); - } - } } private static List<(long, PersonContainer)> GetDistinctCollection(Configuration configuration, IEnumerable personContainers, Dictionary> personKeyToPersonContainerCollection, Dictionary personKeyFormattedToPersonContainer) @@ -443,22 +444,6 @@ internal abstract class MapLogic return results; } - private static void AppendToSkipCollection(Dictionary> skipCollection, Dictionary> idThenNormalizedRectangleToPersonContainers, Dictionary> incorrectIdThenNormalizedRectangleToPersonContainers) - { - Dictionary? keyValuePairs; - foreach (KeyValuePair> keyValuePair in incorrectIdThenNormalizedRectangleToPersonContainers) - { - if (!skipCollection.ContainsKey(keyValuePair.Key)) - skipCollection.Add(keyValuePair.Key, new()); - if (idThenNormalizedRectangleToPersonContainers.TryGetValue(keyValuePair.Key, out keyValuePairs)) - { - if (keyValuePairs.ContainsKey(keyValuePair.Value.ElementAt(0).Key)) - continue; - } - skipCollection[keyValuePair.Key].AddRange(from l in keyValuePair.Value.Keys select l); - } - } - private static string? GetDisplayDirectoryName(Dictionary personKeyToPersonContainer, long key) { string? result = null; @@ -554,7 +539,7 @@ internal abstract class MapLogic } } - internal static void Set(Configuration? configuration, long ticks, List personContainers, string? a2PeopleContentDirectory, string eDistanceContentDirectory, Dictionary personKeyToPersonContainer, List notMappedPersonContainers, Dictionary> skipCollection, Dictionary> idThenNormalizedRectangleToPersonContainers) + internal static void Set(Configuration? configuration, long ticks, List personContainers, string? a2PeopleSingletonDirectory, string eDistanceContentDirectory, Dictionary personKeyToPersonContainer, List notMappedPersonContainers, Dictionary> skipCollection, Dictionary> skipNotSkipCollection, Dictionary> idThenNormalizedRectangleToPersonContainers) { if (configuration is null) throw new NullReferenceException(nameof(configuration)); @@ -568,15 +553,14 @@ internal abstract class MapLogic Dictionary> personKeyToPersonContainerCollection = new(); List<(string, string[], int, int)> personKeyFormattedIdThenNormalizedRectangleCollection = new(); List<(string[], PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer = new(); - Dictionary> incorrectIdThenNormalizedRectangleToPersonContainers = new(); - SetPersonCollections(configuration, personContainers, personKeys, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedCollection, skipCollection); + SetPersonCollections(configuration, personContainers, a2PeopleSingletonDirectory, personKeys, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedCollection, skipCollection, skipNotSkipCollection); personContainers.AddRange(GetNonSpecificPeopleCollection(configuration, ticks, personKeys)); 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, personKeyFormattedCollection, ticksDirectories, message); (int unableToMatchCount, int duplicateCount) = SetCollectionsAndGetUnableToConvertCount(configuration, ticks, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedIdThenNormalizedRectangleCollection, collection); - SetKeyValuePairs(configuration, personContainers, personKeyToPersonContainerCollection, personKeyFormattedToPersonContainer, personKeyFormattedIdThenNormalizedRectangleCollection, personKeyToPersonContainer, idThenNormalizedRectangleToPersonContainers, possiblyNewPersonDisplayDirectoryNamesAndPersonContainer, incorrectIdThenNormalizedRectangleToPersonContainers); + SetKeyValuePairs(configuration, personContainers, personKeyToPersonContainerCollection, personKeyFormattedToPersonContainer, personKeyFormattedIdThenNormalizedRectangleCollection, personKeyToPersonContainer, idThenNormalizedRectangleToPersonContainers, possiblyNewPersonDisplayDirectoryNamesAndPersonContainer); 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 }; @@ -592,9 +576,8 @@ internal abstract class MapLogic long[] personKeyCollection = (from l in nullablePersonKeyCollection where l is not null select l.Value).Distinct().ToArray(); SetPersonKeyToPersonContainer(configuration, personContainers, personKeyCollection, personKeyToPersonContainer, personKeyToPersonContainerCollection); notMappedPersonContainers.AddRange(GetNotMappedPersonContainers(configuration, personContainers, personKeys, personKeyCollection)); - AppendToSkipCollection(skipCollection, idThenNormalizedRectangleToPersonContainers, incorrectIdThenNormalizedRectangleToPersonContainers); if (possiblyNewPersonDisplayDirectoryNamesAndPersonContainer.Any()) - SavePossiblyNewPersonContainers(configuration.PersonBirthdayFormat, configuration.PersonCharacters.ToArray(), configuration.FacesFileNameExtension, a2PeopleContentDirectory, possiblyNewPersonDisplayDirectoryNamesAndPersonContainer); + SavePossiblyNewPersonContainers(configuration.PersonBirthdayFormat, configuration.PersonCharacters.ToArray(), configuration.FacesFileNameExtension, a2PeopleSingletonDirectory, possiblyNewPersonDisplayDirectoryNamesAndPersonContainer); } private static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, long minimumDateTimeTicks, bool? isWrongYear) @@ -754,4 +737,33 @@ internal abstract class MapLogic return results; } + internal static Mapping[] GetSelectedMappingCollection(List distinctFilteredFaces) + { + Mapping[] results; + IEnumerable collection = from l in distinctFilteredFaces orderby l.Mapping?.MappingFromItem.Id select l.Mapping; + results = (from l in collection where l is not null select l).ToArray(); + return results; + } + + internal static Dictionary> GetIdToNormalizedRectangleToFace(Mapping[] mappingCollection) + { + Dictionary> results = new(); + Dictionary? keyValuePairs; + foreach (Mapping mapping in mappingCollection) + { + if (mapping.MappingFromLocation is null) + continue; + if (!results.TryGetValue(mapping.MappingFromItem.Id, out keyValuePairs)) + { + results.Add(mapping.MappingFromItem.Id, new()); + if (!results.TryGetValue(mapping.MappingFromItem.Id, out keyValuePairs)) + throw new Exception(); + } + if (keyValuePairs.ContainsKey(mapping.MappingFromLocation.NormalizedRectangle)) + continue; + keyValuePairs.Add(mapping.MappingFromLocation.NormalizedRectangle, mapping); + } + return results; + } + } \ No newline at end of file diff --git a/Map/Models/Stateless/Methods/IMapLogic.cs b/Map/Models/Stateless/Methods/IMapLogic.cs index dd15a90..0c37ecb 100644 --- a/Map/Models/Stateless/Methods/IMapLogic.cs +++ b/Map/Models/Stateless/Methods/IMapLogic.cs @@ -13,6 +13,16 @@ public interface IMapLogic static List<(long, string)> GetDisplayDirectoryAllFiles(Shared.Models.PersonContainer[] personContainers) => MapLogic.GetDisplayDirectoryAllFiles(personContainers); + Shared.Models.Mapping[] TestStatic_GetSelectedMappingCollection(List distinctFilteredFaces) => + GetSelectedMappingCollection(distinctFilteredFaces); + static Shared.Models.Mapping[] GetSelectedMappingCollection(List distinctFilteredFaces) => + MapLogic.GetSelectedMappingCollection(distinctFilteredFaces); + + Dictionary> TestStatic_GetIdToNormalizedRectangleToFace(Shared.Models.Mapping[] mappingCollection) => + GetIdToNormalizedRectangleToFace(mappingCollection); + static Dictionary> GetIdToNormalizedRectangleToFace(Shared.Models.Mapping[] mappingCollection) => + MapLogic.GetIdToNormalizedRectangleToFace(mappingCollection); + List<(long, string)> TestStatic_DeleteEmptyDirectoriesAndGetMappedFaceFiles(Configuration configuration, Shared.Models.PersonContainer[] personContainers, long ticks, string? a2PeopleContentDirectory, string eDistanceContentDirectory) => DeleteEmptyDirectoriesAndGetMappedFaceFiles(configuration, personContainers, ticks, a2PeopleContentDirectory, eDistanceContentDirectory); static List<(long, string)> DeleteEmptyDirectoriesAndGetMappedFaceFiles(Configuration configuration, Shared.Models.PersonContainer[] personContainers, long ticks, string? a2PeopleContentDirectory, string eDistanceContentDirectory) => diff --git a/Metadata/Models/B_Metadata.cs b/Metadata/Models/B_Metadata.cs index 6d1c89d..e517760 100644 --- a/Metadata/Models/B_Metadata.cs +++ b/Metadata/Models/B_Metadata.cs @@ -27,10 +27,12 @@ public class B_Metadata _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; string checkDirectory; List collection = new(); - for (int i = 0; i < 11; i++) + for (int i = 0; i < 12; i++) { if (i == 10) checkDirectory = Path.Combine(aResultsFullGroupDirectory, "{}", configuration.ResultAllInOne, "-"); + else if (i == 11) + checkDirectory = Path.Combine(aResultsFullGroupDirectory, "{}", configuration.ResultAllInOne, "_"); else checkDirectory = Path.Combine(aResultsFullGroupDirectory, "{}", configuration.ResultAllInOne, i.ToString()); if (!Directory.Exists(checkDirectory)) diff --git a/Property/Models/A_Property.cs b/Property/Models/A_Property.cs index 296d8e2..b0d4e1d 100644 --- a/Property/Models/A_Property.cs +++ b/Property/Models/A_Property.cs @@ -46,10 +46,12 @@ public class A_Property _VerifyToSeason = configuration.VerifyToSeason.Select(l => Path.Combine(configuration.RootDirectory, l)).ToArray(); string checkDirectory; List collection = new(); - for (int i = 0; i < 11; i++) + for (int i = 0; i < 12; i++) { if (i == 10) checkDirectory = Path.Combine(aResultsFullGroupDirectory, "{}", configuration.ResultAllInOne, "-"); + else if (i == 11) + checkDirectory = Path.Combine(aResultsFullGroupDirectory, "{}", configuration.ResultAllInOne, "_"); else checkDirectory = Path.Combine(aResultsFullGroupDirectory, "{}", configuration.ResultAllInOne, i.ToString()); if (!Directory.Exists(checkDirectory)) diff --git a/Shared/Models/Mapping.cs b/Shared/Models/Mapping.cs index e20dbcd..eebabf4 100644 --- a/Shared/Models/Mapping.cs +++ b/Shared/Models/Mapping.cs @@ -10,16 +10,18 @@ public class MappingFromItem : Properties.IMappingFromItem public int Id { init; get; } public FileHolder ImageFileHolder { init; get; } public bool? IsWrongYear { init; get; } + public bool IsIgnoreRelativePath { init; get; } public DateTime MinimumDateTime { init; get; } public string RelativePath { init; get; } public FileHolder ResizedFileHolder { init; get; } [JsonConstructor] - public MappingFromItem(DateTime[] containerDateTimes, int id, FileHolder imageFileHolder, bool? isWrongYear, DateTime minimumDateTime, string relativePath, FileHolder resizedFileHolder) + public MappingFromItem(DateTime[] containerDateTimes, int id, FileHolder imageFileHolder, bool isIgnoreRelativePath, bool? isWrongYear, DateTime minimumDateTime, string relativePath, FileHolder resizedFileHolder) { ContainerDateTimes = containerDateTimes; Id = id; ImageFileHolder = imageFileHolder; + IsIgnoreRelativePath = isIgnoreRelativePath; IsWrongYear = isWrongYear; MinimumDateTime = minimumDateTime; RelativePath = relativePath; @@ -32,7 +34,7 @@ public class MappingFromItem : Properties.IMappingFromItem return result; } - internal static MappingFromItem GetMappingFromItem(DateTime[] containerDateTimes, Item item, FileHolder? resizedFileHolder) + internal static MappingFromItem GetMappingFromItem(DateTime[] containerDateTimes, Item item, FileHolder? resizedFileHolder, bool isIgnoreRelativePath) { MappingFromItem result; bool? isWrongYear; @@ -43,7 +45,7 @@ public class MappingFromItem : Properties.IMappingFromItem throw new NotSupportedException(); minimumDateTime = Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); (isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder, minimumDateTime); - result = new(containerDateTimes, item.Property.Id.Value, item.ImageFileHolder, isWrongYear, minimumDateTime, item.RelativePath, resizedFileHolder); + result = new(containerDateTimes, item.Property.Id.Value, item.ImageFileHolder, isIgnoreRelativePath, isWrongYear, minimumDateTime, item.RelativePath, resizedFileHolder); return result; } diff --git a/Shared/Models/Methods/IDistanceLimits.cs b/Shared/Models/Methods/IDistanceLimits.cs new file mode 100644 index 0000000..ef9df9b --- /dev/null +++ b/Shared/Models/Methods/IDistanceLimits.cs @@ -0,0 +1,16 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IDistanceLimits +{ + + public double FaceAreaPermille { init; get; } + public double RangeDaysDeltaTolerance { init; get; } + public double FaceConfidencePercent { init; get; } + public double FaceDistancePermyriad { init; get; } + public int SortingMaximumPerFaceShouldBeHigh { init; get; } + public bool RangeDaysDeltaTargetLessThenUpper { init; get; } + + string GetCounts(); + void AddCounts(int area, int days, int distance, int confidence); + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IMapLogicSupport.cs b/Shared/Models/Methods/IMapLogicSupport.cs deleted file mode 100644 index 7620b41..0000000 --- a/Shared/Models/Methods/IMapLogicSupport.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace View_by_Distance.Shared.Models.Methods; - -public interface IMapLogicSupport -{ - - string GetCounts(); - -} \ No newline at end of file diff --git a/Shared/Models/Properties/IMapping.cs b/Shared/Models/Properties/IMapping.cs index 6adee17..f23df16 100644 --- a/Shared/Models/Properties/IMapping.cs +++ b/Shared/Models/Properties/IMapping.cs @@ -6,6 +6,7 @@ public interface IMappingFromItem public DateTime[] ContainerDateTimes { init; get; } public int Id { init; get; } public FileHolder ImageFileHolder { init; get; } + public bool IsIgnoreRelativePath { init; get; } public bool? IsWrongYear { init; get; } public DateTime MinimumDateTime { init; get; } public string RelativePath { init; get; } diff --git a/Shared/Models/Stateless/Methods/Container.cs b/Shared/Models/Stateless/Methods/Container.cs index 2f3e560..8649ab0 100644 --- a/Shared/Models/Stateless/Methods/Container.cs +++ b/Shared/Models/Stateless/Methods/Container.cs @@ -94,7 +94,10 @@ internal abstract class Container filePairs = IDirectory.GetFiles(filesCollection, fileNamesToFiles, extension, compareFileNamesToFiles); renamed += IDirectory.MaybeMove(propertyConfiguration.RootDirectory, propertyConfiguration.ResultAllInOne, filePairs, aPropertySingletonDirectory, extension); if (renamed == 0) + { + _ = IPath.DeleteEmptyDirectories(aPropertySingletonDirectory); break; + } } if (filePairs is null || jsonFilesCollection is null || compareFileNamesToFiles is null) throw new NullReferenceException(nameof(filePairs)); diff --git a/Shared/Models/Stateless/Methods/IDirectory.cs b/Shared/Models/Stateless/Methods/IDirectory.cs index a394e1f..66b6dbb 100644 --- a/Shared/Models/Stateless/Methods/IDirectory.cs +++ b/Shared/Models/Stateless/Methods/IDirectory.cs @@ -9,7 +9,7 @@ public interface IDirectory int TestStatic_GetDirectory(char directory) => GetDirectory(directory); - static int GetDirectory(char directory) => directory == '-' ? 10 : int.Parse(directory.ToString()); + static int GetDirectory(char directory) => directory == '-' ? 10 : int.TryParse(directory.ToString(), out int value) ? value : 11; List TestStatic_GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter) => GetFilesCollection(directory, directorySearchFilter, fileSearchFilter); diff --git a/Shared/Models/Stateless/Methods/IMappingFromItem.cs b/Shared/Models/Stateless/Methods/IMappingFromItem.cs index 0ed6a86..4726e06 100644 --- a/Shared/Models/Stateless/Methods/IMappingFromItem.cs +++ b/Shared/Models/Stateless/Methods/IMappingFromItem.cs @@ -3,19 +3,19 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods; public interface IMappingFromItem { // ... - MappingFromItem TestStatic_GetMappingFromItem(DateTime[] containerDateTimes, Models.Item item, Models.FileHolder? resizedFileHolder) - => GetMappingFromItem(containerDateTimes, item, resizedFileHolder); - static MappingFromItem GetMappingFromItem(DateTime[] containerDateTimes, Models.Item item, Models.FileHolder? resizedFileHolder) - => MappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder); + MappingFromItem TestStatic_GetMappingFromItem(DateTime[] containerDateTimes, Models.Item item, Models.FileHolder? resizedFileHolder, bool isIgnoreRelativePath) + => GetMappingFromItem(containerDateTimes, item, resizedFileHolder, isIgnoreRelativePath); + static MappingFromItem GetMappingFromItem(DateTime[] containerDateTimes, Models.Item item, Models.FileHolder? resizedFileHolder, bool isIgnoreRelativePath) + => MappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder, isIgnoreRelativePath); - MappingFromItem TestStatic_GetMappingFromItem(DateTime[] containerDateTimes, Models.Item item) - => GetMappingFromItem(containerDateTimes, item); - static MappingFromItem GetMappingFromItem(DateTime[] containerDateTimes, Models.Item item) - => GetMappingFromItem(containerDateTimes, item, item.ResizedFileHolder); + MappingFromItem TestStatic_GetMappingFromItem(DateTime[] containerDateTimes, Models.Item item, bool isIgnoreRelativePath) + => GetMappingFromItem(containerDateTimes, item, isIgnoreRelativePath); + static MappingFromItem GetMappingFromItem(DateTime[] containerDateTimes, Models.Item item, bool isIgnoreRelativePath) + => GetMappingFromItem(containerDateTimes, item, item.ResizedFileHolder, isIgnoreRelativePath); - MappingFromItem TestStatic_GetMappingFromItem(Models.Item item) - => GetMappingFromItem(item); - static MappingFromItem GetMappingFromItem(Models.Item item) - => GetMappingFromItem(containerDateTimes: Array.Empty(), item, item.ResizedFileHolder); + MappingFromItem TestStatic_GetMappingFromItem(Models.Item item, bool isIgnoreRelativePath) + => GetMappingFromItem(item, isIgnoreRelativePath); + static MappingFromItem GetMappingFromItem(Models.Item item, bool isIgnoreRelativePath) + => GetMappingFromItem(containerDateTimes: Array.Empty(), item, item.ResizedFileHolder, isIgnoreRelativePath); } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/XDirectory.cs b/Shared/Models/Stateless/Methods/XDirectory.cs index 6e05cfa..6f94fb1 100644 --- a/Shared/Models/Stateless/Methods/XDirectory.cs +++ b/Shared/Models/Stateless/Methods/XDirectory.cs @@ -68,19 +68,25 @@ internal abstract partial class XDirectory internal static int LookForAbandoned(List jsonFilesCollection, IReadOnlyDictionary> fileNamesToFiles, string extension) { string fileName; + string fileNameWith; List? collection; + string fileNameUpperExtension; int length = extension.Length; List<(string, string)> rename = new(); foreach (string[] files in jsonFilesCollection) { foreach (string file in files) { - fileName = Path.GetFileName(file); - if (fileName.Length < length || !fileName.EndsWith(extension)) + fileNameWith = Path.GetFileName(file); + if (fileNameWith.Length < length || !fileNameWith.EndsWith(extension)) throw new Exception(); - if (!fileNamesToFiles.TryGetValue(fileName[..^length], out collection)) - rename.Add(new(file, string.Concat(file, ".del"))); - + fileName = fileNameWith[..^length]; + if (!fileNamesToFiles.TryGetValue(fileName, out collection)) + { + fileNameUpperExtension = string.Concat(Path.GetFileNameWithoutExtension(fileName), Path.GetExtension(fileName).ToUpper()); + if (fileName == fileNameUpperExtension || !fileNamesToFiles.TryGetValue(fileNameUpperExtension, out collection)) + rename.Add(new(file, string.Concat(file, ".del"))); + } } } foreach ((string from, string to) in rename) @@ -236,7 +242,6 @@ internal abstract partial class XDirectory } File.Move(from, checkDirectory); } - _ = IPath.DeleteEmptyDirectories(jsonGroupDirectory); return rename.Count; } diff --git a/Tests/UnitTestResize.cs b/Tests/UnitTestResize.cs index ae50c5e..6277c04 100644 --- a/Tests/UnitTestResize.cs +++ b/Tests/UnitTestResize.cs @@ -137,8 +137,9 @@ public class UnitTestResize bool reverse = false; FileHolder resizedFileHolder; List parseExceptions = new(); - bool isValidImageFormatExtension = true; + const bool isIgnoreRelativePath = false; Shared.Models.Property? property = null; + const bool isValidImageFormatExtension = true; Dictionary outputResolutionToResize; List> subFileTuples = new(); List> metadataCollection; @@ -175,7 +176,7 @@ public class UnitTestResize throw new NullReferenceException(nameof(property)); resizedFileHolder = resize.GetResizedFileHolder(item); item.SetResizedFileHolder(resize.FileNameExtension, resizedFileHolder); - MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(item); + MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(item, isIgnoreRelativePath); (int _, metadataCollection) = metadata.GetMetadataCollection(subFileTuples, parseExceptions, mappingFromItem); outputResolutionToResize = resize.GetResizeKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, subFileTuples, parseExceptions, metadataCollection, item.Property, mappingFromItem); Assert.IsNotNull(mappingFromItem.ResizedFileHolder); diff --git a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs index c427027..a1f20a7 100644 --- a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs +++ b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs @@ -212,8 +212,9 @@ public class UnitTestFace bool reverse = false; FileHolder resizedFileHolder; List parseExceptions = new(); - bool isValidImageFormatExtension = true; + const bool isIgnoreRelativePath = false; Shared.Models.Property? property = null; + const bool isValidImageFormatExtension = true; Dictionary outputResolutionToResize; List> subFileTuples = new(); List> metadataCollection; @@ -251,7 +252,7 @@ public class UnitTestFace throw new NullReferenceException(nameof(property)); resizedFileHolder = resize.GetResizedFileHolder(item); item.SetResizedFileHolder(resize.FileNameExtension, resizedFileHolder); - MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(item); + MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(item, isIgnoreRelativePath); (int _, metadataCollection) = metadata.GetMetadataCollection(subFileTuples, parseExceptions, mappingFromItem); outputResolutionToResize = resize.GetResizeKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, subFileTuples, parseExceptions, metadataCollection, item.Property, mappingFromItem); Assert.IsNotNull(mappingFromItem.ResizedFileHolder);