From c86ad3845542293bdd2e6f42d763a32ccd7bf1e3 Mon Sep 17 00:00:00 2001 From: Mike Phares Date: Fri, 16 Sep 2022 21:05:34 -0700 Subject: [PATCH] Change to support 7680 x 4320 and Configuration additions --- .vscode/launch.json | 16 +- FaceRecognitionDotNet/FaceRecognition.cs | 28 +-- Instance/DlibDotNet.cs | 153 +++++++----- Instance/Models/Binder/Configuration.cs | 88 +++++++ Instance/Models/Configuration.cs | 103 +++++++- Instance/Models/_A2_People.cs | 2 +- Instance/Models/_D2_FaceParts.cs | 2 +- Instance/Models/_D_Face.cs | 10 +- Instance/Models/_E_Distance.cs | 121 ++++++---- Instance/Models/_G2_Identify.cs | 2 +- Instance/appsettings.Development.json | 41 +++- Instance/appsettings.Staging.json | 24 ++ Instance/appsettings.json | 24 ++ Map/Models/Configuration.cs | 80 +++++++ Map/Models/MapLogic.cs | 164 ++++++------- ...SetByDeterministicHashCode.cs => ByRef.cs} | 219 +++++++++++++----- Metadata/Models/B_Metadata.cs | 4 +- Property/Models/A_Property.cs | 6 +- Property/Models/Binder/Configuration.cs | 16 ++ Property/Models/Configuration.cs | 27 ++- Property/Models/Stateless/Container.cs | 3 +- Property/Models/Stateless/IResult.cs | 5 - Property/Models/Stateless/Result.cs | 24 +- Resize/Models/_C_Resize.cs | 4 +- Shared/Models/Mapping.cs | 4 +- Shared/Models/Methods/IFaceDistance.cs | 8 + Shared/Models/Properties/IMapping.cs | 2 +- Shared/Models/Stateless/IFaceDistance.cs | 15 -- Shared/Models/Stateless/IMapping.cs | 9 - Shared/Models/Stateless/IPerson.cs | 7 - Shared/Models/Stateless/IPersonBirthday.cs | 9 - Shared/Models/Stateless/ISorting.cs | 16 -- Shared/Models/Stateless/Methods/ILocation.cs | 14 ++ Shared/Models/Stateless/Methods/IMapping.cs | 9 +- Shared/Models/Stateless/Methods/Mapping.cs | 98 ++++---- Tests/UnitTestCalculations.cs | 21 -- Tests/UnitTestResize.cs | 4 +- .../Models/Binder/Configuration.cs | 88 +++++++ .../Models/Configuration.cs | 103 +++++++- .../UnitTestFace.cs | 34 ++- 40 files changed, 1153 insertions(+), 454 deletions(-) create mode 100644 Map/Models/Configuration.cs rename Map/Models/Stateless/{SetByDeterministicHashCode.cs => ByRef.cs} (62%) create mode 100644 Shared/Models/Methods/IFaceDistance.cs delete mode 100644 Shared/Models/Stateless/IFaceDistance.cs delete mode 100644 Shared/Models/Stateless/IMapping.cs delete mode 100644 Shared/Models/Stateless/IPerson.cs delete mode 100644 Shared/Models/Stateless/IPersonBirthday.cs delete mode 100644 Shared/Models/Stateless/ISorting.cs diff --git a/.vscode/launch.json b/.vscode/launch.json index 11e9fc0..421c7c7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -42,18 +42,4 @@ // Get id in normal fashion // If id is in collection update collection to new path/name // If not save and add to collection -// Nicéphore Niépce in 1826 or 182 -// Stateless.ILocation.Digits -// locationDigits -// Stateless.ILocation.Factor -// locationFactor -// Stateless.IFaceDistance.Tolerance -// faceDistanceTolerance -// Stateless.IFaceDistance.Permyriad -// faceDistancePermyriad -// Stateless.IPersonBirthday.FirstYear -// personBirthdayFirstYear -// Stateless.IPersonBirthday.Format -// personBirthdayFormat -// Stateless.IPerson.KeyFormat -// personKeyFormat \ No newline at end of file +// Nicéphore Niépce in 1826 or 182 \ No newline at end of file diff --git a/FaceRecognitionDotNet/FaceRecognition.cs b/FaceRecognitionDotNet/FaceRecognition.cs index ddcae4e..b0daac8 100644 --- a/FaceRecognitionDotNet/FaceRecognition.cs +++ b/FaceRecognitionDotNet/FaceRecognition.cs @@ -76,20 +76,6 @@ public class FaceRecognition : DisposableObject return results.ToArray(); } - private static Location TrimBound(double detectionConfidence, DlibDotNet.Rectangle rectangle, int width, int height, int facesCount) => - new( - Math.Min(rectangle.Bottom, height), - detectionConfidence, - height, - Math.Max(rectangle.Left, 0), - ILocation.Digits, - ILocation.Factor, - Math.Min(rectangle.Right, width), - Math.Max(rectangle.Top, 0), - width, - facesCount - ); - private List<(FacePart, FacePoint[])> GetFaceParts(FullObjectDetection fullObjectDetection) { List<(FacePart, FacePoint[])> results = new(); @@ -155,11 +141,13 @@ public class FaceRecognition : DisposableObject image.ThrowIfDisposed(); ThrowIfDisposed(); List results = new(); - IEnumerable faces = GetMModRects(image); - foreach (MModRect? face in faces) + System.Drawing.Rectangle rectangle; + IEnumerable mModRects = GetMModRects(image); + foreach (MModRect? mModRect in mModRects) { - Location location = TrimBound(face.DetectionConfidence, face.Rect, image.Width, image.Height, faces.Count()); - face.Dispose(); + rectangle = new(mModRect.Rect.Left, mModRect.Rect.Top, (int)mModRect.Rect.Width, (int)mModRect.Rect.Height); + Location location = Shared.Models.Stateless.Methods.ILocation.TrimBound(mModRect.DetectionConfidence, rectangle, image.Width, image.Height, mModRects.Count()); + mModRect.Dispose(); results.Add(location); } if (sortByNormalizedPixelPercentage) @@ -206,9 +194,11 @@ public class FaceRecognition : DisposableObject if (mModRects.Any()) { Location location; + System.Drawing.Rectangle rectangle; foreach (MModRect? mModRect in mModRects) { - location = TrimBound(mModRect.DetectionConfidence, mModRect.Rect, image.Width, image.Height, mModRects.Length); + rectangle = new(mModRect.Rect.Left, mModRect.Rect.Top, (int)mModRect.Rect.Width, (int)mModRect.Rect.Height); + location = Shared.Models.Stateless.Methods.ILocation.TrimBound(mModRect.DetectionConfidence, rectangle, image.Width, image.Height, mModRects.Length); mModRect.Dispose(); results.Add(location); } diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index be81169..d2d0e22 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -93,7 +93,7 @@ public partial class DlibDotNet _Resize = new C_Resize(configuration.ForceResizeLastWriteTimeToCreationTime, configuration.OverrideForResizeImages, configuration.PropertiesChangedForResize, configuration.ValidResolutions, imageCodecInfo, encoderParameters, filenameExtension); } if (!configuration.SkipSearch) - Search(propertyConfiguration, model, predictorModel, argZero, propertyRoot, people); + Search(model, predictorModel, argZero, propertyRoot, people); if (!_FirstRun && _Exceptions.Count == 0 && _ArgZeroIsConfigurationRootDirectory) { long ticks = DateTime.Now.Ticks; @@ -248,6 +248,10 @@ public partial class DlibDotNet string[] resizeMatch = (from l in sourceDirectoryNames where configuration.ValidResolutions.Contains(l) select l).ToArray(); if (resizeMatch.Any()) throw new Exception("Input directory should be the source and not a resized directory!"); + if (configuration.LocationDigits != Shared.Models.Stateless.ILocation.Digits) + throw new Exception("Configuration has to match interface!"); + if (configuration.LocationFactor != Shared.Models.Stateless.ILocation.Factor) + throw new Exception("Configuration has to match interface!"); } 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) @@ -280,10 +284,10 @@ public partial class DlibDotNet sourceDirectoryChanges.Add(new Tuple(nameof(A_Property), (from l in subFileTuples select l.Item2).Max())); } } - (int metadataGroups, metadataCollection) = _Metadata.GetMetadataCollection(bResultsFullGroupDirectory, subFileTuples, parseExceptions, item); + (int metadataGroups, metadataCollection) = _Metadata.GetMetadataCollection(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, subFileTuples, parseExceptions, item); if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(B_Metadata.GetMetadataCollection)); - imageResizeKeyValuePairs = _Resize.GetResizeKeyValuePairs(cResultsFullGroupDirectory, subFileTuples, parseExceptions, original, metadataCollection, item); + imageResizeKeyValuePairs = _Resize.GetResizeKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, subFileTuples, parseExceptions, original, metadataCollection, item); if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(C_Resize.GetResizeKeyValuePairs)); if (_Configuration.SaveResizedSubfiles) @@ -338,12 +342,12 @@ public partial class DlibDotNet } } - private int FullParallelWork(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 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) { if (_Log is null) throw new NullReferenceException(nameof(_Log)); int result = 0; - ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism }; + ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; if (imageFaceCollections.Count != filteredItems.Length || metadataCollection.Count != filteredItems.Length || resizeKeyValuePairs.Count != filteredItems.Length || propertyCollection.Count != filteredItems.Length) { @@ -411,7 +415,7 @@ public partial class DlibDotNet } } - private void WriteGroup(Property.Models.Configuration configuration, A_Property propertyLogic, Shared.Models.Property[] propertyCollection, List>> metadataCollection, List> resizeKeyValuePairs, List?> imageFaceCollections, string outputResolution, Container container, Item[] filteredItems) + private void WriteGroup(A_Property propertyLogic, Shared.Models.Property[] propertyCollection, List>> metadataCollection, List> resizeKeyValuePairs, List?> imageFaceCollections, string outputResolution, Container container, Item[] filteredItems) { Item item; string key; @@ -428,8 +432,8 @@ public partial class DlibDotNet List> propertyCollectionKeyValuePairs = new(); List>> resizeKeyValuePairsCollections = new(); List>>> metadataCollectionKeyValuePairs = new(); - (int level, List directories) = Shared.Models.Stateless.Methods.IPath.Get(configuration.RootDirectory, container.SourceDirectory); - string fileName = string.Concat(string.Join(configuration.FileNameDirectorySeparator, directories), ".json"); + (int level, List directories) = Shared.Models.Stateless.Methods.IPath.Get(_Configuration.PropertyConfiguration.RootDirectory, container.SourceDirectory); + string fileName = string.Concat(string.Join(_Configuration.PropertyConfiguration.FileNameDirectorySeparator, directories), ".json"); for (int i = 0; i < filteredItems.Length; i++) { item = filteredItems[i]; @@ -491,44 +495,44 @@ public partial class DlibDotNet } } - private (string, string, string, string, string, string) GetResultsFullGroupDirectories(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string outputResolution) + private (string, string, string, string, string, string) GetResultsFullGroupDirectories(Model? model, PredictorModel? predictorModel, string outputResolution) { string aResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( - configuration, model, predictorModel, nameof(A_Property), outputResolution, includeResizeGroup: false, includeModel: false, includePredictorModel: false); + _Configuration.PropertyConfiguration, model, predictorModel, nameof(A_Property), outputResolution, includeResizeGroup: false, includeModel: false, includePredictorModel: false); string bResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( - configuration, model, predictorModel, nameof(B_Metadata), outputResolution, includeResizeGroup: false, includeModel: false, includePredictorModel: false); + _Configuration.PropertyConfiguration, model, predictorModel, nameof(B_Metadata), outputResolution, includeResizeGroup: false, includeModel: false, includePredictorModel: false); string cResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( - configuration, model, predictorModel, nameof(C_Resize), outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false); + _Configuration.PropertyConfiguration, model, predictorModel, nameof(C_Resize), outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false); string dResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( - configuration, model, predictorModel, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true); + _Configuration.PropertyConfiguration, model, predictorModel, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true); string d2ResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( - configuration, model, predictorModel, nameof(D2_FaceParts), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true); + _Configuration.PropertyConfiguration, model, predictorModel, nameof(D2_FaceParts), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true); string eResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( - configuration, model, predictorModel, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true); + _Configuration.PropertyConfiguration, model, predictorModel, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true); return new(aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, eResultsFullGroupDirectory); } - private void SetAngleBracketCollections(Property.Models.Configuration configuration, A_Property propertyLogic, string outputResolution, Container container, string aResultsFullGroupDirectory, string bResultsFullGroupDirectory, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, string eResultsFullGroupDirectory) + private void SetAngleBracketCollections(A_Property propertyLogic, string outputResolution, Container container, string aResultsFullGroupDirectory, string bResultsFullGroupDirectory, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, string eResultsFullGroupDirectory) { _Faces.AngleBracketCollection.Clear(); _Resize.AngleBracketCollection.Clear(); _Metadata.AngleBracketCollection.Clear(); propertyLogic.AngleBracketCollection.Clear(); - propertyLogic.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection(configuration, + propertyLogic.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection(_Configuration.PropertyConfiguration, container.SourceDirectory, aResultsFullGroupDirectory, contentDescription: string.Empty, singletonDescription: "Properties for each image", collectionDescription: string.Empty, converted: false)); - _Metadata.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection(configuration, + _Metadata.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection(_Configuration.PropertyConfiguration, container.SourceDirectory, bResultsFullGroupDirectory, contentDescription: string.Empty, singletonDescription: "Metadata as key value pairs", collectionDescription: string.Empty, converted: true)); - _Resize.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection(configuration, + _Resize.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection(_Configuration.PropertyConfiguration, container.SourceDirectory, cResultsFullGroupDirectory, contentDescription: "Resized image", @@ -536,7 +540,7 @@ public partial class DlibDotNet collectionDescription: string.Empty, converted: true)); if (_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution)) - _Faces.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection(configuration, + _Faces.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection(_Configuration.PropertyConfiguration, container.SourceDirectory, dResultsFullGroupDirectory, contentDescription: "n png file(s) for each face found", @@ -553,7 +557,7 @@ public partial class DlibDotNet collectionDescription: string.Empty, converted: false); if (_Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution)) - _ = Property.Models.Stateless.IResult.GetDirectoryInfoCollection(configuration, + _ = Property.Models.Stateless.IResult.GetDirectoryInfoCollection(_Configuration.PropertyConfiguration, container.SourceDirectory, eResultsFullGroupDirectory, contentDescription: string.Empty, @@ -585,6 +589,7 @@ public partial class DlibDotNet List> resizeKeyValuePairs = new(); List> sourceDirectoryChanges = 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) @@ -592,7 +597,7 @@ public partial class DlibDotNet total = 0; _FileKeyValuePairs.Clear(); _FilePropertiesKeyValuePairs.Clear(); - (aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, eResultsFullGroupDirectory) = GetResultsFullGroupDirectories(_Configuration.PropertyConfiguration, model, predictorModel, outputResolution); + (aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, eResultsFullGroupDirectory) = GetResultsFullGroupDirectories(model, predictorModel, outputResolution); for (int i = 0; i < containers.Length; i++) { container = containers[i]; @@ -610,9 +615,9 @@ public partial class DlibDotNet nullablePropertyCollection.Clear(); propertyFileHolderCollection.Clear(); totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); - message = $"{i:000}.{container.G} / {containersLength:000}) {filteredItems.Length:000} file(s) - {total} / {t} total file(s) - {totalSeconds} total second(s) - {outputResolution} - {container.SourceDirectory}"; - SetAngleBracketCollections(_Configuration.PropertyConfiguration, propertyLogic, outputResolution, container, aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, eResultsFullGroupDirectory); - exceptionCount = FullParallelWork(propertyLogic, outputResolution, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, sourceDirectoryChanges, propertyFileHolderCollection, nullablePropertyCollection, metadataCollection, resizeKeyValuePairs, imageFaceCollections, container, filteredItems, message); + 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, eResultsFullGroupDirectory); + exceptionCount = FullParallelWork(maxDegreeOfParallelism, propertyLogic, outputResolution, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, sourceDirectoryChanges, propertyFileHolderCollection, nullablePropertyCollection, metadataCollection, resizeKeyValuePairs, imageFaceCollections, container, filteredItems, message); if (metadataCollection.Count != filteredItems.Length || nullablePropertyCollection.Count != filteredItems.Length || resizeKeyValuePairs.Count != filteredItems.Length || imageFaceCollections.Count != filteredItems.Length) throw new Exception("Counts don't match!"); if (exceptionCount != 0) @@ -621,7 +626,7 @@ public partial class DlibDotNet filteredItems[f].Faces.AddRange(from l in imageFaceCollections[f] select l); propertyCollection = (from l in nullablePropertyCollection where l is not null select l).ToArray(); if (_ArgZeroIsConfigurationRootDirectory && exceptionCount == 0) - WriteGroup(_Configuration.PropertyConfiguration, propertyLogic, propertyCollection, metadataCollection, resizeKeyValuePairs, imageFaceCollections, outputResolution, container, filteredItems); + WriteGroup(propertyLogic, propertyCollection, metadataCollection, resizeKeyValuePairs, imageFaceCollections, outputResolution, container, filteredItems); if (Directory.GetFiles(propertyRoot, "*.txt", SearchOption.TopDirectoryOnly).Any()) { for (int y = 0; y < int.MaxValue; y++) @@ -649,12 +654,12 @@ public partial class DlibDotNet } } - private string GetMapLogicResultsFullGroupDirectory(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel) + private string GetMapLogicResultsFullGroupDirectory(Model? model, PredictorModel? predictorModel) { const int zero = 0; string outputResolution = _Configuration.OutputResolutions[zero]; string zResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( - configuration, model, predictorModel, $"Z_{nameof(Item)}", outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false); + _Configuration.PropertyConfiguration, model, predictorModel, $"Z_{nameof(Item)}", outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false); return zResultsFullGroupDirectory; } @@ -695,7 +700,7 @@ public partial class DlibDotNet (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.GetDeterministicHashCodeKeyDisplay(item.Property.Id.Value, face.Location.NormalizedPixelPercentage.Value); + 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); mapping = new(mappingFromItem, mappingFromLocation, mappingFromPerson); face.SetMapping(mapping); @@ -722,7 +727,55 @@ public partial class DlibDotNet return results; } - private void Search(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string argZero, string propertyRoot, Person[] people) + private void DistanceThenMapLogic(string argZero, long ticks, Person[] people, Container[] containers, MapLogic? mapLogic, string dResultsFullGroupDirectory, string eResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, string zResultsFullGroupDirectory, string peopleDateGroupDirectory, string outputResolution) + { + E_Distance distance = new(); + if (string.IsNullOrEmpty(eResultsFullGroupDirectory)) + throw new NullReferenceException(nameof(eResultsFullGroupDirectory)); + string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, "()"); + string eDistanceContentDirectory = Path.Combine(eResultsFullGroupDirectory, "([])"); + if (!Directory.Exists(eDistanceContentDirectory)) + _ = Directory.CreateDirectory(eDistanceContentDirectory); + Map.Models.Configuration configuration = new(_Configuration.FaceDistanceHiddenImageFactor, + _Configuration.FaceDistancePermyriad, + _Configuration.FaceDistanceMinimumConfidence, + _Configuration.FaceDistanceTolerance, + _Configuration.LocationDigits, + _Configuration.LocationFactor, + _Configuration.MapLogicSigma, + _Configuration.MappingSaveFaceEncoding, + _Configuration.MappingSaveMapped, + _Configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping, + _Configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping, + _Configuration.PersonBirthdayFirstYear, + _Configuration.PersonBirthdayFormat, + _Configuration.PersonKeyFormat, + _Configuration.SortingDaysDeltaTolerance, + _Configuration.SortingFacesToSkipAfterSortBeforeLoad, + _Configuration.SortingFacesToTakeAfterSortBeforeLoad, + _Configuration.SortingMaximumPerFaceShouldBeHigh, + _Configuration.SortingMaximumPerKey, + _Configuration.SortingSigma); + if (mapLogic is not null) + mapLogic.Update(configuration); + string eDistanceContentFileName = Path.Combine(eDistanceContentDirectory, $"{_Configuration.PropertyConfiguration.ResultAllInOne}.tvs"); + List distinctFilteredFaces = SetMappingThenGetDistinctFilteredFacesWithMapping(argZero, containers); + List selectedFilteredFaces = E_Distance.GetSelectedFilteredFaces(configuration, distinctFilteredFaces); + E_Distance.SetFaceDistances(_AppSettings.MaxDegreeOfParallelism, ticks, selectedFilteredFaces); + if (mapLogic is null) + mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FilenameExtension, _Faces.FilenameExtension, _Faces.HiddenFilenameExtension, _FaceParts.FilenameExtension, ticks, people, peopleDateGroupDirectory, zResultsFullGroupDirectory, configuration, distinctFilteredFaces, distance); + mapLogic.SetPersonTicks(distinctFilteredFaces); + SortingContainer[] sortingContainers = E_Distance.SetFaceMappingSortingCollectionThenGetSortingContainers(_AppSettings.MaxDegreeOfParallelism, configuration, ticks, mapLogic, selectedFilteredFaces); + E_Distance.SaveFaceDistances(eDistanceContentFileName, sortingContainers); + int totalNotMapped = mapLogic.AddToMapping(distinctFilteredFaces); + if (totalNotMapped > 0) + mapLogic.ForceSingleImageThenSaveMapping(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, dFacesContentDirectory, d2ResultsFullGroupDirectory, distinctFilteredFaces, sortingContainers, totalNotMapped); + mapLogic.SaveNotMappedTicks(_Configuration.PropertyConfiguration); + if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) + mapLogic.SaveShortcuts(_Configuration.JuliePhares, distinctFilteredFaces); + } + + private void Search(Model? model, PredictorModel? predictorModel, string argZero, string propertyRoot, Person[] people) { int j; int f; @@ -737,8 +790,8 @@ public partial class DlibDotNet string dResultsFullGroupDirectory; string eResultsFullGroupDirectory; string d2ResultsFullGroupDirectory; - string zResultsFullGroupDirectory = GetMapLogicResultsFullGroupDirectory(configuration, model, predictorModel); - string peopleDateGroupDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A2_People)); + string zResultsFullGroupDirectory = GetMapLogicResultsFullGroupDirectory(model, predictorModel); + string peopleDateGroupDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People)); if (!_FirstRun) { mapLogic = null; @@ -754,45 +807,33 @@ public partial class DlibDotNet ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; using (ProgressBar progressBar = new(1, message, options)) { - if (string.IsNullOrEmpty(configuration.RootDirectory)) - (j, f, t, containers) = A_Property.Get(configuration, propertyLogic); + progressBar.Tick(); + if (string.IsNullOrEmpty(_Configuration.PropertyConfiguration.RootDirectory)) + (j, f, t, containers) = A_Property.Get(_Configuration.PropertyConfiguration, propertyLogic); else - (j, f, t, containers) = Property.Models.Stateless.Container.GetContainers(configuration, _FirstRun, propertyLogic); + (j, f, t, containers) = Property.Models.Stateless.Container.GetContainers(_Configuration.PropertyConfiguration, _FirstRun, propertyLogic); } FullDoWork(argZero, model, predictorModel, propertyRoot, ticks, propertyLogic, t, containers); foreach (string outputResolution in _Configuration.OutputResolutions) { if (_FirstRun) break; - (aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, eResultsFullGroupDirectory) = GetResultsFullGroupDirectories(configuration, model, predictorModel, outputResolution); + (aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, eResultsFullGroupDirectory) = GetResultsFullGroupDirectories(model, predictorModel, outputResolution); if (_ArgZeroIsConfigurationRootDirectory && _Configuration.SaveResizedSubfiles && outputResolution == _Configuration.OutputResolutions[0] && _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution) && _Exceptions.Count == 0) { - if (string.IsNullOrEmpty(eResultsFullGroupDirectory)) - throw new NullReferenceException(nameof(eResultsFullGroupDirectory)); - string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, "()"); - string eDistanceContentDirectory = Path.Combine(eResultsFullGroupDirectory, "([])"); - if (!Directory.Exists(eDistanceContentDirectory)) - _ = Directory.CreateDirectory(eDistanceContentDirectory); - string eDistanceContentFileName = Path.Combine(eDistanceContentDirectory, $"{Property.Models.Stateless.IResult.AllInOne}.tvs"); - List distinctFilteredFaces = SetMappingThenGetDistinctFilteredFacesWithMapping(argZero, containers); - if (mapLogic is null) - mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FilenameExtension, _Faces.FilenameExtension, _Faces.HiddenFilenameExtension, _FaceParts.FilenameExtension, ticks, people, peopleDateGroupDirectory, zResultsFullGroupDirectory); - SortingContainer[] sortingContainers = E_Distance.SetPersonTicksAndSetFaceDistancesAndSetFaceMappingSortingCollectionThenGetSortingContainers(_AppSettings.MaxDegreeOfParallelism, ticks, mapLogic, outputResolution, eDistanceContentFileName, distinctFilteredFaces); - mapLogic.CommonWork(_AppSettings.MaxDegreeOfParallelism, dFacesContentDirectory, d2ResultsFullGroupDirectory, distinctFilteredFaces, sortingContainers); - if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) - mapLogic.SaveShortcuts(_Configuration.JuliePhares, distinctFilteredFaces); + DistanceThenMapLogic(argZero, ticks, people, containers, mapLogic, dResultsFullGroupDirectory, eResultsFullGroupDirectory, d2ResultsFullGroupDirectory, zResultsFullGroupDirectory, peopleDateGroupDirectory, outputResolution); if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Any()) break; if (_FileKeyValuePairs.Any()) - _Random.Random(configuration, _Configuration.OutputResolutions[0], _FileKeyValuePairs); + _Random.Random(_Configuration.PropertyConfiguration, _Configuration.OutputResolutions[0], _FileKeyValuePairs); if (_IsEnvironment.Development) continue; G2_Identify identify = new(_Configuration); - List identifiedCollection = identify.GetIdentifiedCollection(configuration, _IsEnvironment, _People); - _People.WriteAllText(configuration, _Configuration.OutputResolutions[0], identifiedCollection); - identify.WriteAllText(configuration, _Configuration.OutputResolutions[0], identifiedCollection); + List identifiedCollection = identify.GetIdentifiedCollection(_Configuration.PropertyConfiguration, _IsEnvironment, _People); + _People.WriteAllText(_Configuration.PropertyConfiguration, _Configuration.OutputResolutions[0], identifiedCollection); + identify.WriteAllText(_Configuration.PropertyConfiguration, _Configuration.OutputResolutions[0], identifiedCollection); if (_Configuration.LoadOrCreateThenSaveIndex && _FilePropertiesKeyValuePairs.Any()) - _Index.SetIndex(configuration, model, predictorModel, _Configuration.OutputResolutions[0], _FilePropertiesKeyValuePairs); + _Index.SetIndex(_Configuration.PropertyConfiguration, model, predictorModel, _Configuration.OutputResolutions[0], _FilePropertiesKeyValuePairs); } _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(aResultsFullGroupDirectory, "{}")); _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(bResultsFullGroupDirectory, "{}")); @@ -806,6 +847,6 @@ public partial class DlibDotNet } } - internal void RenameQueue(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel) => _Rename.RenameQueue(configuration, model, predictorModel); + internal void RenameQueue(Model? model, PredictorModel? predictorModel) => _Rename.RenameQueue(_Configuration.PropertyConfiguration, model, predictorModel); } \ No newline at end of file diff --git a/Instance/Models/Binder/Configuration.cs b/Instance/Models/Binder/Configuration.cs index 22f6512..dfc41d0 100644 --- a/Instance/Models/Binder/Configuration.cs +++ b/Instance/Models/Binder/Configuration.cs @@ -13,6 +13,10 @@ 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 = "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; } + [Display(Name = "Face Distance Tolerance"), Required] public double? FaceDistanceTolerance { get; set; } [Display(Name = "Force Face Last Write Time to Creation Time"), Required] public bool? ForceFaceLastWriteTimeToCreationTime { get; set; } [Display(Name = "Force Metadata Last Write Time to Creation Time"), Required] public bool? ForceMetadataLastWriteTimeToCreationTime { get; set; } [Display(Name = "Force Resize Last Write Time to Creation Time"), Required] public bool? ForceResizeLastWriteTimeToCreationTime { get; set; } @@ -23,7 +27,14 @@ public class Configuration [Display(Name = "Load Or Create Then Save Image Faces Results"), Required] public string[] LoadOrCreateThenSaveImageFacesResultsForOutputResolutions { get; set; } [Display(Name = "Load Or Create Then Save Index"), Required] public bool? LoadOrCreateThenSaveIndex { get; set; } [Display(Name = "Location Confidence Factor"), Required] public int? LocationConfidenceFactor { get; set; } + [Display(Name = "Location Digits"), Required] public int? LocationDigits { get; set; } + [Display(Name = "Location Factor"), Required] public int? LocationFactor { get; set; } + [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 Save Face Encoding"), Required] public bool? MappingSaveFaceEncoding { get; set; } + [Display(Name = "MappingSaveMapped"), Required] public bool? MappingSaveMapped { get; set; } + [Display(Name = "Mapping Use Deterministic Hash Code Unknown Face Key Value Pairs for Add to Mapping"), Required] public bool? MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping { get; set; } + [Display(Name = "Mapping Use Deterministic Hash Code Unknown Face Key Value Pairs for Save Mapping"), Required] public bool? MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping { get; set; } [Display(Name = "Max Items In Distance Collection"), Required] public int? MaxItemsInDistanceCollection { get; set; } [Display(Name = "Mixed Year Relative Paths"), Required] public string[] MixedYearRelativePaths { get; set; } [Display(Name = "Model Directory"), Required] public string ModelDirectory { get; set; } @@ -37,6 +48,9 @@ public class Configuration [Display(Name = "Override For Face Landmark Images"), Required] public bool? OverrideForFaceLandmarkImages { get; set; } [Display(Name = "Override For Resize Images"), Required] public bool? OverrideForResizeImages { get; set; } [Display(Name = "Padding Loops"), Required] public int? PaddingLoops { get; set; } + [Display(Name = "Person Birthday First Year"), Required] public int? PersonBirthdayFirstYear { get; set; } + [Display(Name = "Person Birthday Format"), Required] public string PersonBirthdayFormat { get; set; } + [Display(Name = "PersonKey Format"), Required] public string PersonKeyFormat { get; set; } [Display(Name = "Predictor Model Name"), Required] public string PredictorModelName { get; set; } [Display(Name = "Properties Changed For Distance"), Required] public bool? PropertiesChangedForDistance { get; set; } [Display(Name = "Properties Changed For Faces"), Required] public bool? PropertiesChangedForFaces { get; set; } @@ -50,6 +64,12 @@ 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 = "Skip Search"), Required] public bool? SkipSearch { get; set; } + [Display(Name = "Sorting Days Delta Tolerance"), Required] public int? SortingDaysDeltaTolerance { get; set; } + [Display(Name = "Sorting Faces To Skip After Sort Before Load"), Required] public int? SortingFacesToSkipAfterSortBeforeLoad { get; set; } + [Display(Name = "Sorting Faces To Take After Sort Before Load"), Required] public int? SortingFacesToTakeAfterSortBeforeLoad { 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 Sigma"), Required] public int? SortingSigma { get; set; } [Display(Name = "Test Distance Results"), Required] public bool? TestDistanceResults { get; set; } [Display(Name = "Valid Resolutions"), Required] public string[] ValidResolutions { get; set; } @@ -70,6 +90,14 @@ public class Configuration throw new NullReferenceException(nameof(configuration.CrossDirectoryMaxItemsInDistanceCollection)); if (configuration.DistanceFactor is null) throw new NullReferenceException(nameof(configuration.DistanceFactor)); + if (configuration.FaceDistanceHiddenImageFactor is null) + throw new NullReferenceException(nameof(configuration.FaceDistanceHiddenImageFactor)); + if (configuration.FaceDistanceMinimumConfidence is null) + throw new NullReferenceException(nameof(configuration.FaceDistanceMinimumConfidence)); + if (configuration.FaceDistancePermyriad is null) + throw new NullReferenceException(nameof(configuration.FaceDistancePermyriad)); + if (configuration.FaceDistanceTolerance is null) + throw new NullReferenceException(nameof(configuration.FaceDistanceTolerance)); if (configuration.ForceFaceLastWriteTimeToCreationTime is null) throw new NullReferenceException(nameof(configuration.ForceFaceLastWriteTimeToCreationTime)); if (configuration.ForceMetadataLastWriteTimeToCreationTime is null) @@ -80,10 +108,28 @@ public class Configuration throw new NullReferenceException(nameof(configuration.IgnoreExtensions)); if (configuration.IgnoreRelativePaths is null) throw new NullReferenceException(nameof(configuration.IgnoreRelativePaths)); + if (configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions is null) + configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions = Array.Empty(); + if (configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions is null) + configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = Array.Empty(); if (configuration.LoadOrCreateThenSaveIndex is null) throw new NullReferenceException(nameof(configuration.LoadOrCreateThenSaveIndex)); if (configuration.LocationConfidenceFactor is null) throw new NullReferenceException(nameof(configuration.LocationConfidenceFactor)); + if (configuration.LocationDigits is null) + throw new NullReferenceException(nameof(configuration.LocationDigits)); + if (configuration.LocationFactor is null) + throw new NullReferenceException(nameof(configuration.LocationFactor)); + if (configuration.MapLogicSigma is null) + throw new NullReferenceException(nameof(configuration.MapLogicSigma)); + if (configuration.MappingSaveFaceEncoding is null) + throw new NullReferenceException(nameof(configuration.MappingSaveFaceEncoding)); + if (configuration.MappingSaveMapped is null) + throw new NullReferenceException(nameof(configuration.MappingSaveMapped)); + if (configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping is null) + throw new NullReferenceException(nameof(configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping)); + if (configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping is null) + throw new NullReferenceException(nameof(configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping)); if (configuration.MaxItemsInDistanceCollection is null) throw new NullReferenceException(nameof(configuration.MaxItemsInDistanceCollection)); if (configuration.MixedYearRelativePaths is null) @@ -104,6 +150,12 @@ public class Configuration throw new NullReferenceException(nameof(configuration.OverrideForResizeImages)); if (configuration.PaddingLoops is null) throw new NullReferenceException(nameof(configuration.PaddingLoops)); + if (configuration.PersonBirthdayFirstYear is null) + throw new NullReferenceException(nameof(configuration.PersonBirthdayFirstYear)); + if (configuration.PersonBirthdayFormat is null) + throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat)); + if (configuration.PersonKeyFormat is null) + throw new NullReferenceException(nameof(configuration.PersonKeyFormat)); if (configuration.PropertiesChangedForDistance is null) throw new NullReferenceException(nameof(configuration.PropertiesChangedForDistance)); if (configuration.PropertiesChangedForFaces is null) @@ -116,14 +168,30 @@ public class Configuration throw new NullReferenceException(nameof(configuration.PropertiesChangedForResize)); if (configuration.Reverse is null) throw new NullReferenceException(nameof(configuration.Reverse)); + if (configuration.SaveFaceLandmarkForOutputResolutions is null) + configuration.SaveFaceLandmarkForOutputResolutions = Array.Empty(); if (configuration.SaveFaceLandmarkForOutputResolutions is null) throw new NullReferenceException(nameof(configuration.SaveFaceLandmarkForOutputResolutions)); if (configuration.SaveFullYearOfRandomFiles is null) throw new NullReferenceException(nameof(configuration.SaveFullYearOfRandomFiles)); if (configuration.SaveResizedSubfiles is null) throw new NullReferenceException(nameof(configuration.SaveResizedSubfiles)); + if (configuration.SaveShortcutsForOutputResolutions is null) + configuration.SaveShortcutsForOutputResolutions = Array.Empty(); if (configuration.SkipSearch is null) throw new NullReferenceException(nameof(configuration.SkipSearch)); + if (configuration.SortingDaysDeltaTolerance is null) + throw new NullReferenceException(nameof(configuration.SortingDaysDeltaTolerance)); + if (configuration.SortingFacesToSkipAfterSortBeforeLoad is null) + throw new NullReferenceException(nameof(configuration.SortingFacesToSkipAfterSortBeforeLoad)); + if (configuration.SortingFacesToTakeAfterSortBeforeLoad is null) + throw new NullReferenceException(nameof(configuration.SortingFacesToTakeAfterSortBeforeLoad)); + if (configuration.SortingMaximumPerFaceShouldBeHigh is null) + throw new NullReferenceException(nameof(configuration.SortingMaximumPerFaceShouldBeHigh)); + if (configuration.SortingMaximumPerKey is null) + throw new NullReferenceException(nameof(configuration.SortingMaximumPerKey)); + if (configuration.SortingSigma is null) + throw new NullReferenceException(nameof(configuration.SortingSigma)); if (configuration.TestDistanceResults is null) throw new NullReferenceException(nameof(configuration.TestDistanceResults)); if (configuration.ValidResolutions is null) @@ -140,6 +208,10 @@ public class Configuration configuration.CheckJsonForDistanceResults.Value, configuration.CrossDirectoryMaxItemsInDistanceCollection.Value, configuration.DistanceFactor.Value, + configuration.FaceDistanceHiddenImageFactor.Value, + configuration.FaceDistanceMinimumConfidence.Value, + configuration.FaceDistancePermyriad.Value, + configuration.FaceDistanceTolerance.Value, configuration.ForceFaceLastWriteTimeToCreationTime.Value, configuration.ForceMetadataLastWriteTimeToCreationTime.Value, configuration.ForceResizeLastWriteTimeToCreationTime.Value, @@ -150,7 +222,14 @@ public class Configuration configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions, configuration.LoadOrCreateThenSaveIndex.Value, configuration.LocationConfidenceFactor.Value, + configuration.LocationDigits.Value, + configuration.LocationFactor.Value, + configuration.MapLogicSigma.Value, configuration.MappedMaxIndex, + configuration.MappingSaveFaceEncoding.Value, + configuration.MappingSaveMapped.Value, + configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping.Value, + configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping.Value, configuration.MaxItemsInDistanceCollection.Value, configuration.MixedYearRelativePaths, configuration.ModelDirectory, @@ -164,6 +243,9 @@ public class Configuration configuration.OverrideForFaceLandmarkImages.Value, configuration.OverrideForResizeImages.Value, configuration.PaddingLoops.Value, + configuration.PersonBirthdayFirstYear.Value, + configuration.PersonBirthdayFormat, + configuration.PersonKeyFormat, configuration.PredictorModelName, configuration.PropertiesChangedForDistance.Value, configuration.PropertiesChangedForFaces.Value, @@ -176,6 +258,12 @@ public class Configuration configuration.SaveResizedSubfiles.Value, configuration.SaveShortcutsForOutputResolutions, configuration.SkipSearch.Value, + configuration.SortingDaysDeltaTolerance.Value, + configuration.SortingFacesToSkipAfterSortBeforeLoad.Value, + configuration.SortingFacesToTakeAfterSortBeforeLoad.Value, + configuration.SortingMaximumPerFaceShouldBeHigh.Value, + configuration.SortingMaximumPerKey.Value, + configuration.SortingSigma.Value, configuration.TestDistanceResults.Value, configuration.ValidResolutions); return result; diff --git a/Instance/Models/Configuration.cs b/Instance/Models/Configuration.cs index 6095e5f..fc554e2 100644 --- a/Instance/Models/Configuration.cs +++ b/Instance/Models/Configuration.cs @@ -12,6 +12,10 @@ public class Configuration public bool CheckJsonForDistanceResults { init; get; } public int CrossDirectoryMaxItemsInDistanceCollection { init; get; } public int DistanceFactor { init; get; } + public int FaceDistanceHiddenImageFactor { init; get; } + public double FaceDistanceMinimumConfidence { init; get; } + public int FaceDistancePermyriad { init; get; } + public double FaceDistanceTolerance { init; get; } public bool ForceFaceLastWriteTimeToCreationTime { init; get; } public bool ForceMetadataLastWriteTimeToCreationTime { init; get; } public bool ForceResizeLastWriteTimeToCreationTime { init; get; } @@ -22,7 +26,14 @@ public class Configuration public string[] LoadOrCreateThenSaveImageFacesResultsForOutputResolutions { init; get; } public bool LoadOrCreateThenSaveIndex { init; get; } public int LocationConfidenceFactor { init; get; } + public int LocationDigits { init; get; } + public int LocationFactor { init; get; } + public int MapLogicSigma { init; get; } public int? MappedMaxIndex { init; get; } + public bool MappingSaveFaceEncoding { init; get; } + public bool MappingSaveMapped { init; get; } + public bool MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping { init; get; } + public bool MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping { init; get; } public int MaxItemsInDistanceCollection { init; get; } public string[] MixedYearRelativePaths { init; get; } public string ModelDirectory { init; get; } @@ -36,6 +47,9 @@ public class Configuration public bool OverrideForFaceLandmarkImages { init; get; } public bool OverrideForResizeImages { init; get; } public int PaddingLoops { init; get; } + public int PersonBirthdayFirstYear { init; get; } + public string PersonBirthdayFormat { init; get; } + public string PersonKeyFormat { init; get; } public string PredictorModelName { init; get; } public bool PropertiesChangedForDistance { init; get; } public bool PropertiesChangedForFaces { init; get; } @@ -48,16 +62,87 @@ public class Configuration public bool SaveResizedSubfiles { init; get; } public string[] SaveShortcutsForOutputResolutions { init; get; } public bool SkipSearch { init; get; } + public int SortingDaysDeltaTolerance { init; get; } + public int SortingFacesToSkipAfterSortBeforeLoad { init; get; } + public int SortingFacesToTakeAfterSortBeforeLoad { init; get; } + public int SortingMaximumPerFaceShouldBeHigh { init; get; } + public int SortingMaximumPerKey { init; get; } + public int SortingSigma { init; get; } public bool TestDistanceResults { init; get; } public string[] ValidResolutions { init; get; } [JsonConstructor] - public Configuration(Property.Models.Configuration propertyConfiguration, bool checkJsonForDistanceResults, int crossDirectoryMaxItemsInDistanceCollection, int distanceFactor, bool forceFaceLastWriteTimeToCreationTime, bool forceMetadataLastWriteTimeToCreationTime, bool forceResizeLastWriteTimeToCreationTime, string[] ignoreExtensions, string[] ignoreRelativePaths, string[] juliePhares, string[] loadOrCreateThenSaveDistanceResultsForOutputResolutions, string[] loadOrCreateThenSaveImageFacesResultsForOutputResolutions, bool loadOrCreateThenSaveIndex, int locationConfidenceFactor, int? mappedMaxIndex, int maxItemsInDistanceCollection, string[] mixedYearRelativePaths, string modelDirectory, string modelName, int numberOfJitters, int numberOfTimesToUpsample, string outputExtension, int outputQuality, string[] outputResolutions, bool overrideForFaceImages, bool overrideForFaceLandmarkImages, bool overrideForResizeImages, int paddingLoops, string predictorModelName, bool propertiesChangedForDistance, bool propertiesChangedForFaces, bool propertiesChangedForIndex, bool propertiesChangedForMetadata, bool propertiesChangedForResize, bool reverse, string[] saveFaceLandmarkForOutputResolutions, bool saveFullYearOfRandomFiles, bool saveResizedSubfiles, string[] saveShortcutsForOutputResolutions, bool skipSearch, bool testDistanceResults, string[] validResolutions) + public Configuration(Property.Models.Configuration propertyConfiguration, + bool checkJsonForDistanceResults, + int crossDirectoryMaxItemsInDistanceCollection, + int distanceFactor, + int faceDistanceHiddenImageFactor, + double faceDistanceMinimumConfidence, + int faceDistancePermyriad, + double faceDistanceTolerance, + bool forceFaceLastWriteTimeToCreationTime, + bool forceMetadataLastWriteTimeToCreationTime, + bool forceResizeLastWriteTimeToCreationTime, + string[] ignoreExtensions, + string[] ignoreRelativePaths, + string[] juliePhares, + string[] loadOrCreateThenSaveDistanceResultsForOutputResolutions, + string[] loadOrCreateThenSaveImageFacesResultsForOutputResolutions, + bool loadOrCreateThenSaveIndex, + int locationConfidenceFactor, + int locationDigits, + int locationFactor, + int mapLogicSigma, + int? mappedMaxIndex, + bool mappingSaveFaceEncoding, + bool mappingSaveMapped, + bool mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping, + bool mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping, + int maxItemsInDistanceCollection, + string[] mixedYearRelativePaths, + string modelDirectory, + string modelName, + int numberOfJitters, + int numberOfTimesToUpsample, + string outputExtension, + int outputQuality, + string[] outputResolutions, + bool overrideForFaceImages, + bool overrideForFaceLandmarkImages, + bool overrideForResizeImages, + int paddingLoops, + int personBirthdayFirstYear, + string personBirthdayFormat, + string personKeyFormat, + string predictorModelName, + bool propertiesChangedForDistance, + bool propertiesChangedForFaces, + bool propertiesChangedForIndex, + bool propertiesChangedForMetadata, + bool propertiesChangedForResize, + bool reverse, + string[] saveFaceLandmarkForOutputResolutions, + bool saveFullYearOfRandomFiles, + bool saveResizedSubfiles, + string[] saveShortcutsForOutputResolutions, + bool skipSearch, + int sortingDaysDeltaTolerance, + int sortingFacesToSkipAfterSortBeforeLoad, + int sortingFacesToTakeAfterSortBeforeLoad, + int sortingMaximumPerFaceShouldBeHigh, + int sortingMaximumPerKey, + int sortingSigma, + bool testDistanceResults, + string[] validResolutions) { _PropertyConfiguration = propertyConfiguration; CheckJsonForDistanceResults = checkJsonForDistanceResults; CrossDirectoryMaxItemsInDistanceCollection = crossDirectoryMaxItemsInDistanceCollection; DistanceFactor = distanceFactor; + FaceDistanceHiddenImageFactor = faceDistanceHiddenImageFactor; + FaceDistanceMinimumConfidence = faceDistanceMinimumConfidence; + FaceDistancePermyriad = faceDistancePermyriad; + FaceDistanceTolerance = faceDistanceTolerance; ForceFaceLastWriteTimeToCreationTime = forceFaceLastWriteTimeToCreationTime; ForceMetadataLastWriteTimeToCreationTime = forceMetadataLastWriteTimeToCreationTime; ForceResizeLastWriteTimeToCreationTime = forceResizeLastWriteTimeToCreationTime; @@ -68,7 +153,14 @@ public class Configuration LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = loadOrCreateThenSaveImageFacesResultsForOutputResolutions; LoadOrCreateThenSaveIndex = loadOrCreateThenSaveIndex; LocationConfidenceFactor = locationConfidenceFactor; + LocationDigits = locationDigits; + LocationFactor = locationFactor; + MapLogicSigma = mapLogicSigma; MappedMaxIndex = mappedMaxIndex; + MappingSaveFaceEncoding = mappingSaveFaceEncoding; + MappingSaveMapped = mappingSaveMapped; + MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping = mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping; + MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping = mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping; MaxItemsInDistanceCollection = maxItemsInDistanceCollection; MixedYearRelativePaths = mixedYearRelativePaths; ModelDirectory = modelDirectory; @@ -82,6 +174,9 @@ public class Configuration OverrideForFaceLandmarkImages = overrideForFaceLandmarkImages; OverrideForResizeImages = overrideForResizeImages; PaddingLoops = paddingLoops; + PersonBirthdayFirstYear = personBirthdayFirstYear; + PersonBirthdayFormat = personBirthdayFormat; + PersonKeyFormat = personKeyFormat; PredictorModelName = predictorModelName; PropertiesChangedForDistance = propertiesChangedForDistance; PropertiesChangedForFaces = propertiesChangedForFaces; @@ -94,6 +189,12 @@ public class Configuration SaveResizedSubfiles = saveResizedSubfiles; SaveShortcutsForOutputResolutions = saveShortcutsForOutputResolutions; SkipSearch = skipSearch; + SortingDaysDeltaTolerance = sortingDaysDeltaTolerance; + SortingFacesToSkipAfterSortBeforeLoad = sortingFacesToSkipAfterSortBeforeLoad; + SortingFacesToTakeAfterSortBeforeLoad = sortingFacesToTakeAfterSortBeforeLoad; + SortingMaximumPerFaceShouldBeHigh = sortingMaximumPerFaceShouldBeHigh; + SortingMaximumPerKey = sortingMaximumPerKey; + SortingSigma = sortingSigma; TestDistanceResults = testDistanceResults; ValidResolutions = validResolutions; } diff --git a/Instance/Models/_A2_People.cs b/Instance/Models/_A2_People.cs index 8eb94c6..1a74f86 100644 --- a/Instance/Models/_A2_People.cs +++ b/Instance/Models/_A2_People.cs @@ -69,7 +69,7 @@ internal class A2_People if (rootResultsDirectory is null) throw new Exception(); Storage storage = new(rootDirectory, rootResultsDirectory, peopleRootDirectory); - results = Shared.Models.Stateless.Methods.IPerson.GetPeople(storage, Shared.Models.Stateless.IPersonBirthday.FirstYear, Shared.Models.Stateless.IPersonBirthday.Format, Shared.Models.Stateless.IPerson.KeyFormat); + results = Shared.Models.Stateless.Methods.IPerson.GetPeople(storage, _Configuration.PersonBirthdayFirstYear, _Configuration.PersonBirthdayFormat, _Configuration.PersonKeyFormat); return results.ToArray(); } diff --git a/Instance/Models/_D2_FaceParts.cs b/Instance/Models/_D2_FaceParts.cs index 3fbaa4f..888490a 100644 --- a/Instance/Models/_D2_FaceParts.cs +++ b/Instance/Models/_D2_FaceParts.cs @@ -145,7 +145,7 @@ internal class D2_FaceParts collection.Add(new(face, string.Empty, string.Empty)); continue; } - deterministicHashCodeKeyDisplay = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKeyDisplay(item.Property.Id.Value, face.Location.NormalizedPixelPercentage.Value); + 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}")); if (!fileInfo.Exists) { diff --git a/Instance/Models/_D_Face.cs b/Instance/Models/_D_Face.cs index e1586cb..b4e144c 100644 --- a/Instance/Models/_D_Face.cs +++ b/Instance/Models/_D_Face.cs @@ -159,7 +159,7 @@ public class D_Face continue; if (face.FaceEncoding is null || face?.Location is null) continue; - location = Shared.Models.Stateless.Methods.ILocation.GetLocation(face.Location, ILocation.Digits, ILocation.Factor, source.Height, source.Width, collection.Count); + location = Shared.Models.Stateless.Methods.ILocation.GetLocation(face.Location, _Configuration.LocationDigits, _Configuration.LocationFactor, source.Height, source.Width, collection.Count); if (location is null) continue; width = location.Right - location.Left; @@ -173,7 +173,7 @@ public class D_Face } if (File.Exists(fileName)) File.Delete(fileName); - location = Shared.Models.Stateless.Methods.ILocation.GetLocation(IFaceDistance.HiddenImageFactor, face.Location, ILocation.Digits, ILocation.Factor, source.Height, source.Width, collection.Count); + location = Shared.Models.Stateless.Methods.ILocation.GetLocation(_Configuration.FaceDistanceHiddenImageFactor, face.Location, _Configuration.LocationDigits, _Configuration.LocationFactor, source.Height, source.Width, collection.Count); if (location is null) continue; width = location.Right - location.Left; @@ -259,7 +259,7 @@ public class D_Face 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"); - string dCollectionFile = Path.Combine(dResultsFullGroupDirectory, "[]", Property.Models.Stateless.IResult.AllInOne, $"{item.Property.Id.Value}{item.ImageFileHolder.ExtensionLowered}.json"); + string dCollectionFile = Path.Combine(dResultsFullGroupDirectory, "[]", _Configuration.PropertyConfiguration.ResultAllInOne, $"{item.Property.Id.Value}{item.ImageFileHolder.ExtensionLowered}.json"); FileInfo fileInfo = new(dCollectionFile); if (!fileInfo.Exists) { @@ -330,7 +330,7 @@ public class D_Face } if (_Configuration.ForceFaceLastWriteTimeToCreationTime) { - results = (from l in results select new Face(ILocation.Digits, ILocation.Factor, results.Count, l)).ToList(); + results = (from l in results select new Face(_Configuration.LocationDigits, _Configuration.LocationFactor, results.Count, l)).ToList(); normalizedPixelPercentageCollection = Shared.Models.Stateless.Methods.IFace.GetInts(results); normalizedPixelPercentageDistinctCount = normalizedPixelPercentageCollection.Distinct().Count(); if (normalizedPixelPercentageDistinctCount != normalizedPixelPercentageCollection.Length) @@ -372,7 +372,7 @@ public class D_Face collection.Add(new(face, null, string.Empty)); continue; } - deterministicHashCodeKeyDisplay = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKeyDisplay(item.Property.Id.Value, face.Location.NormalizedPixelPercentage.Value); + 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}")); if (!fileInfo.Exists) { diff --git a/Instance/Models/_E_Distance.cs b/Instance/Models/_E_Distance.cs index 7687d71..8b5191d 100644 --- a/Instance/Models/_E_Distance.cs +++ b/Instance/Models/_E_Distance.cs @@ -2,14 +2,13 @@ using ShellProgressBar; using View_by_Distance.FaceRecognitionDotNet; using View_by_Distance.Map.Models; using View_by_Distance.Shared.Models; -using View_by_Distance.Shared.Models.Stateless; namespace View_by_Distance.Instance.Models; -internal class E_Distance +internal class E_Distance : Shared.Models.Methods.IFaceDistance { - private static void SaveFaceDistances(string eDistanceContentFileName, SortingContainer[] sortingContainers) + internal static void SaveFaceDistances(string eDistanceContentFileName, SortingContainer[] sortingContainers) { #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(); @@ -17,18 +16,18 @@ internal class E_Distance File.WriteAllLines(eDistanceContentFileName, results); } - private static List GetSortingCollection(MapLogic mapLogic, List faceDistanceEncodings, int faceDistanceContainersLength, int i, FaceDistance faceDistanceEncoding) + private static List GetSortingCollection(Map.Models.Configuration configuration, 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 < IFaceDistance.Tolerance select true).Any(); + bool anyLowerThanTolerance = (from l in faceDistanceLengths where l.Length is not null && l.Length.Value != 0 && l.Length.Value < configuration.FaceDistanceTolerance select true).Any(); results = mapLogic.GetSortingCollection(i, faceDistanceEncoding, faceDistanceLengths, anyLowerThanTolerance); return results; } - private static List GetSortingContainers(Face face, FaceDistance faceDistanceEncoding, List sortingCollection) + private static List GetSortingContainers(Map.Models.Configuration configuration, Face face, FaceDistance faceDistanceEncoding, List sortingCollection) { List results = new(); SortingContainer sortingContainer; @@ -37,31 +36,39 @@ internal class E_Distance { if (face.Mapping is null || faceDistanceEncoding.NormalizedPixelPercentage is null) throw new NotSupportedException(); - if (face.Mapping.MappingFromLocation.Confidence < IFaceDistance.MinimumConfidence || sorting.DistancePermyriad > IFaceDistance.Permyriad || sorting.DaysDelta > ISorting.DaysDeltaTolerance) + if (face.Mapping.MappingFromLocation.Confidence < configuration.FaceDistanceMinimumConfidence || sorting.DistancePermyriad > configuration.FaceDistancePermyriad || sorting.DaysDelta > configuration.SortingDaysDeltaTolerance) continue; sortingContainer = new(face, sorting); results.Add(sortingContainer); - if (results.Count >= ISorting.MaximumPerFaceShouldBeHigh) + if (results.Count >= configuration.SortingMaximumPerFaceShouldBeHigh) break; } return results; } - private static SortingContainer[] GetSortingContainersThenSetFaceMappingSortingCollection(int maxDegreeOfParallelism, long ticks, MapLogic mapLogic, string outputResolution, FaceDistanceContainer[] faceDistanceContainers) + private static List GetFaceDistanceEncodings(FaceDistanceContainer[] faceDistanceContainers) { - SortingContainer[] results; - List collection = new(); List faceDistanceEncodings = new(); - int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); - ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; - string message = $") {faceDistanceContainers.Length:000} faceDistanceContainer(s) - {totalSeconds} total second(s) - {outputResolution}"; - ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; foreach (FaceDistanceContainer faceDistanceContainer in faceDistanceContainers) { if (faceDistanceContainer.FaceDistance.Encoding is null) continue; faceDistanceEncodings.Add(faceDistanceContainer.FaceDistance); } + return faceDistanceEncodings; + } + + internal static SortingContainer[] SetFaceMappingSortingCollectionThenGetSortingContainers(int maxDegreeOfParallelism, Map.Models.Configuration configuration, long ticks, MapLogic mapLogic, List 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); + 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(); using ProgressBar progressBar = new(faceDistanceContainers.Length, message, options); _ = Parallel.For(0, faceDistanceContainers.Length, parallelOptions, (i, state) => { @@ -70,8 +77,8 @@ internal class E_Distance if (face.Mapping is null) throw new NotSupportedException(); FaceDistance faceDistanceEncoding = faceDistanceContainers[i].FaceDistance; - List sortingCollection = GetSortingCollection(mapLogic, faceDistanceEncodings, faceDistanceContainers.Length, i, faceDistanceEncoding); - List sortingContainers = GetSortingContainers(face, faceDistanceEncoding, sortingCollection); + List sortingCollection = GetSortingCollection(configuration, mapLogic, faceDistanceEncodings, faceDistanceContainers.Length, i, faceDistanceEncoding); + List sortingContainers = GetSortingContainers(configuration, face, faceDistanceEncoding, sortingCollection); lock (collection) collection.AddRange(sortingContainers); lock (face) @@ -81,17 +88,15 @@ internal class E_Distance return results; } - private static FaceDistanceContainer[] GetFaceDistanceContainers(Face[] firstFilteredFaces) + private static FaceDistanceContainer[] GetFaceDistanceContainers(List selectedFilteredFaces) { FaceDistanceContainer[] results; FaceDistance faceDistance; FaceDistanceContainer faceDistanceContainer; List collection = new(); - foreach (Face face in firstFilteredFaces) + foreach (Face face in selectedFilteredFaces) { - if (face.Mapping is null) - throw new NotSupportedException(); - if (face.FaceDistance?.Encoding is not FaceRecognitionDotNet.FaceEncoding faceEncoding) + if (face.FaceDistance?.Encoding is not FaceRecognitionDotNet.FaceEncoding faceEncoding || face.Mapping is null) throw new NotSupportedException(); faceDistance = new(face.Mapping.MappingFromLocation.Confidence, faceEncoding, face.Mapping.MappingFromItem.Id, face.Mapping.MappingFromItem.IsWrongYear, face.Mapping.MappingFromItem.MinimumDateTime, face.Mapping.MappingFromLocation.NormalizedPixelPercentage); faceDistanceContainer = new(face, faceDistance); @@ -103,39 +108,73 @@ internal class E_Distance return results; } - private static void SetFaceDistances(int maxDegreeOfParallelism, long ticks, string outputResolution, Face[] selectedFilteredFaces) + internal static List GetSelectedFilteredFaces(Map.Models.Configuration configuration, 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.Skip(configuration.SortingFacesToSkipAfterSortBeforeLoad).Take(configuration.SortingFacesToTakeAfterSortBeforeLoad).ToList(); + return results; + } + + internal static void SetFaceDistances(int maxDegreeOfParallelism, long ticks, List selectedFilteredFaces) { int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; - string message = $") {selectedFilteredFaces.Length:000} Load Face Encoding - {totalSeconds} total second(s) - {outputResolution}"; - ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = false }; - using ProgressBar progressBar = new(selectedFilteredFaces.Length, message, options); - _ = Parallel.For(0, selectedFilteredFaces.Length, parallelOptions, (i, state) => + string message = $") {selectedFilteredFaces.Count: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) => { + progressBar.Tick(); FaceDistance faceDistance; - FaceRecognitionDotNet.FaceEncoding faceEncoding; Face face = selectedFilteredFaces[i]; - if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) - throw new NotSupportedException(); - if (face.Mapping is null) + FaceRecognitionDotNet.FaceEncoding faceEncoding; + if (face.FaceEncoding is null || face.Mapping is null) throw new NotSupportedException(); faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); - faceDistance = new(face.Location.Confidence, faceEncoding, face.Mapping.MappingFromItem.Id, face.Mapping.MappingFromItem.IsWrongYear, face.Mapping.MappingFromItem.MinimumDateTime, face.Location.NormalizedPixelPercentage.Value); + 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); }); } - internal static SortingContainer[] SetPersonTicksAndSetFaceDistancesAndSetFaceMappingSortingCollectionThenGetSortingContainers(int maxDegreeOfParallelism, long ticks, MapLogic mapLogic, string outputResolution, string eDistanceContentFileName, List distinctFilteredFaces) + List Shared.Models.Methods.IFaceDistance.GetMatchingFaces(double faceDistanceTolerance, string checkFile, List faces) { - SortingContainer[] results; - Face[] orderedFilteredFaces = (from l in distinctFilteredFaces orderby l.Mapping is not null, l.Mapping?.MappingFromItem.MinimumDateTime descending select l).ToArray(); - mapLogic.SetPersonTicks(outputResolution, orderedFilteredFaces); - Face[] selectedFilteredFaces = orderedFilteredFaces.Skip(ISorting.FacesToSkipAfterSortBeforeLoad).Take(ISorting.FacesToTakeAfterSortBeforeLoad).ToArray(); - SetFaceDistances(maxDegreeOfParallelism, ticks, outputResolution, selectedFilteredFaces); - FaceDistanceContainer[] faceDistanceContainers = GetFaceDistanceContainers(selectedFilteredFaces); - results = GetSortingContainersThenSetFaceMappingSortingCollection(maxDegreeOfParallelism, ticks, mapLogic, outputResolution, faceDistanceContainers); - SaveFaceDistances(eDistanceContentFileName, results); + List results = new(); + Face face; + FaceDistance faceDistanceLength; + string json = File.ReadAllText(checkFile); + List<(Face Face, double Length)> collection = new(); + Shared.Models.FaceEncoding? modelsFaceEncoding = System.Text.Json.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); + int faceDistanceContainersLength = faceDistanceContainers.Length; + if (faceDistanceContainersLength != faces.Count) + throw new NotSupportedException(); + List faceDistanceEncodings = GetFaceDistanceEncodings(faceDistanceContainers); + if (faceDistanceEncodings.Count != faces.Count) + throw new NotSupportedException(); + List faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncoding); + if (faceDistanceLengths.Count != faceDistanceContainersLength) + throw new NotSupportedException(); + for (int i = 0; i < faces.Count; i++) + { + face = faces[i]; + faceDistanceLength = faceDistanceLengths[i]; + if (face.Mapping is null || faceDistanceLength.Length is null) + throw new NotSupportedException(); + if (faceDistanceLength.Length.Value > faceDistanceTolerance) + continue; + collection.Add(new(face, faceDistanceLength.Length.Value)); + } + if (collection.Any()) + { + collection = (from l in collection orderby l.Length select l).ToList(); + results.Add(collection[0].Face); + } return results; } diff --git a/Instance/Models/_G2_Identify.cs b/Instance/Models/_G2_Identify.cs index 9f2d247..362cee2 100644 --- a/Instance/Models/_G2_Identify.cs +++ b/Instance/Models/_G2_Identify.cs @@ -89,7 +89,7 @@ public class G2_Identify : Shared.Models.Properties.IIdentify, IIdentify json = File.ReadAllText(named.FullName); Person[] people = a2People.GetPeople(configuration); Dictionary resultKeyValuePairs = new(); - string[] peopleBirthDates = (from l in people select Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(Shared.Models.Stateless.IPersonBirthday.Format, l.Birthday)).ToArray(); + string[] peopleBirthDates = (from l in people select Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, l.Birthday)).ToArray(); Dictionary sourceKeyValuePairs = JsonSerializer.Deserialize>(json); foreach (KeyValuePair keyValuePair in sourceKeyValuePairs) { diff --git a/Instance/appsettings.Development.json b/Instance/appsettings.Development.json index 7d38de5..fed7b63 100644 --- a/Instance/appsettings.Development.json +++ b/Instance/appsettings.Development.json @@ -52,8 +52,12 @@ "Configuration": { "CheckJsonForDistanceResults": false, "CrossDirectoryMaxItemsInDistanceCollection": 7, - "DateGroup": "2022-08-22", + "DateGroup": "2022-09-15", "DistanceFactor": 8, + "FaceDistanceHiddenImageFactor": 2, + "FaceDistanceMinimumConfidence": 0.8, + "FaceDistancePermyriad": 10000, + "FaceDistanceTolerance": 0.25, "FileNameDirectorySeparator": ".Z.", "ForceFaceLastWriteTimeToCreationTime": false, "ForceMetadataLastWriteTimeToCreationTime": false, @@ -61,7 +65,14 @@ "ForceResizeLastWriteTimeToCreationTime": false, "LoadOrCreateThenSaveIndex": false, "LocationConfidenceFactor": 2, + "LocationDigits": 6, + "LocationFactor": 1000000, + "MapLogicSigma": 3, "MappedMaxIndex": 1034720, + "MappingSaveFaceEncoding": false, + "MappingSaveMapped": false, + "MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping": false, + "MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping": false, "MaxImagesInDirectoryForTopLevelFirstPass": 10, "MaxItemsInDistanceCollection": 50, "ModelDirectory": "C:/GitHub/dlib-models", @@ -75,6 +86,9 @@ "OverrideForResizeImages": false, "PaddingLoops": 5, "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", + "PersonBirthdayFirstYear": 1500, + "PersonBirthdayFormat": "yyyy-MM-dd_HH", + "PersonKeyFormat": "yyyy-MM-dd_HH", "PopulatePropertyId": true, "PredictorModelName": "Large", "PropertiesChangedForDistance": false, @@ -83,12 +97,22 @@ "PropertiesChangedForMetadata": false, "PropertiesChangedForProperty": false, "PropertiesChangedForResize": false, + "ResultAllInOne": "_ _ _", + "ResultCollection": "[]", + "ResultContent": "()", + "ResultSingleton": "{}", "Reverse": false, "xRootDirectory": "C:/Tmp/phares/Pictures", - "RootDirectory": "C:/Tmp/Phares/Compare/Images 2022-08-22 - bc2174b - III", + "RootDirectory": "C:/Tmp/Phares/Compare/Images 2022-09-15 - 7390c13 - III", "SaveFullYearOfRandomFiles": true, "SaveResizedSubFiles": true, "SkipSearch": false, + "SortingDaysDeltaTolerance": 700, + "SortingFacesToSkipAfterSortBeforeLoad": 0, + "SortingFacesToTakeAfterSortBeforeLoad": 55000, + "SortingMaximumPerFaceShouldBeHigh": 1000, + "SortingMaximumPerKey": 27, + "SortingSigma": 3, "TestDistanceResults": true, "WriteBitmapDataBytes": false, "IgnoreExtensions": [ @@ -154,20 +178,16 @@ "1982-05-02_00" ], "LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions": [ - "1920 x 1080" + "7680 x 4320" ], "LoadOrCreateThenSaveDistanceResultsForOutputResolutions": [ - "1920 x 1080" + "7680 x 4320" ], "LoadOrCreateThenSaveImageFacesResultsForOutputResolutions": [ - "1920 x 1080" + "7680 x 4320" ], "OutputResolutions": [ - "176 x 176", - "256 x 256", - "353 x 353", - "1024 x 768", - "1920 x 1080" + "7680 x 4320" ], "PropertyContentCollectionFiles": [], "SaveFaceLandmarkForOutputResolutions": [ @@ -175,7 +195,6 @@ "256 x 256" ], "SaveShortcutsForOutputResolutions": [ - "1920 x 1080" ], "ValidImageFormatExtensions": [ ".bmp", diff --git a/Instance/appsettings.Staging.json b/Instance/appsettings.Staging.json index 0984e62..33cbee2 100644 --- a/Instance/appsettings.Staging.json +++ b/Instance/appsettings.Staging.json @@ -54,6 +54,10 @@ "CrossDirectoryMaxItemsInDistanceCollection": 7, "DateGroup": "2022-09-15", "DistanceFactor": 8, + "FaceDistanceHiddenImageFactor": 2, + "FaceDistanceMinimumConfidence": 0.8, + "FaceDistancePermyriad": 10000, + "FaceDistanceTolerance": 0.25, "FileNameDirectorySeparator": ".Z.", "ForceFaceLastWriteTimeToCreationTime": false, "ForceMetadataLastWriteTimeToCreationTime": false, @@ -61,7 +65,14 @@ "ForceResizeLastWriteTimeToCreationTime": false, "LoadOrCreateThenSaveIndex": false, "LocationConfidenceFactor": 2, + "LocationDigits": 6, + "LocationFactor": 1000000, + "MapLogicSigma": 3, "MappedMaxIndex": 1034720, + "MappingSaveFaceEncoding": false, + "MappingSaveMapped": false, + "MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping": false, + "MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping": false, "MaxImagesInDirectoryForTopLevelFirstPass": 10, "MaxItemsInDistanceCollection": 50, "ModelDirectory": "L:/GitHub/dlib-models", @@ -75,6 +86,9 @@ "OverrideForResizeImages": false, "PaddingLoops": 5, "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", + "PersonBirthdayFirstYear": 1500, + "PersonBirthdayFormat": "yyyy-MM-dd_HH", + "PersonKeyFormat": "yyyy-MM-dd_HH", "PopulatePropertyId": true, "PredictorModelName": "Large", "PropertiesChangedForDistance": false, @@ -83,11 +97,21 @@ "PropertiesChangedForMetadata": false, "PropertiesChangedForProperty": false, "PropertiesChangedForResize": false, + "ResultAllInOne": "_ _ _", + "ResultCollection": "[]", + "ResultContent": "()", + "ResultSingleton": "{}", "Reverse": false, "RootDirectory": "E:/Images", "SaveFullYearOfRandomFiles": true, "SaveResizedSubFiles": true, "SkipSearch": false, + "SortingDaysDeltaTolerance": 700, + "SortingFacesToSkipAfterSortBeforeLoad": 0, + "SortingFacesToTakeAfterSortBeforeLoad": 55000, + "SortingMaximumPerFaceShouldBeHigh": 1000, + "SortingMaximumPerKey": 27, + "SortingSigma": 3, "TestDistanceResults": true, "WriteBitmapDataBytes": false, "IgnoreExtensions": [ diff --git a/Instance/appsettings.json b/Instance/appsettings.json index 4718f6b..539a1d1 100644 --- a/Instance/appsettings.json +++ b/Instance/appsettings.json @@ -54,6 +54,10 @@ "CrossDirectoryMaxItemsInDistanceCollection": 7, "DateGroup": "2022-09-15", "DistanceFactor": 8, + "FaceDistanceHiddenImageFactor": 2, + "FaceDistanceMinimumConfidence": 0.8, + "FaceDistancePermyriad": 10000, + "FaceDistanceTolerance": 0.25, "FileNameDirectorySeparator": ".Z.", "ForceFaceLastWriteTimeToCreationTime": false, "ForceMetadataLastWriteTimeToCreationTime": false, @@ -61,7 +65,14 @@ "ForceResizeLastWriteTimeToCreationTime": false, "LoadOrCreateThenSaveIndex": false, "LocationConfidenceFactor": 2, + "LocationDigits": 6, + "LocationFactor": 1000000, + "MapLogicSigma": 3, "MappedMaxIndex": 1034720, + "MappingSaveFaceEncoding": false, + "MappingSaveMapped": false, + "MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping": false, + "MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping": false, "MaxImagesInDirectoryForTopLevelFirstPass": 10, "MaxItemsInDistanceCollection": 50, "ModelDirectory": "C:/GitHub/dlib-models", @@ -75,6 +86,9 @@ "OverrideForResizeImages": false, "PaddingLoops": 5, "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", + "PersonBirthdayFirstYear": 1500, + "PersonBirthdayFormat": "yyyy-MM-dd_HH", + "PersonKeyFormat": "yyyy-MM-dd_HH", "PopulatePropertyId": true, "PredictorModelName": "Large", "PropertiesChangedForDistance": false, @@ -83,11 +97,21 @@ "PropertiesChangedForMetadata": false, "PropertiesChangedForProperty": false, "PropertiesChangedForResize": false, + "ResultAllInOne": "_ _ _", + "ResultCollection": "[]", + "ResultContent": "()", + "ResultSingleton": "{}", "Reverse": false, "RootDirectory": "D:/Images", "SaveFullYearOfRandomFiles": true, "SaveResizedSubFiles": true, "SkipSearch": false, + "SortingDaysDeltaTolerance": 700, + "SortingFacesToSkipAfterSortBeforeLoad": 0, + "SortingFacesToTakeAfterSortBeforeLoad": 55000, + "SortingMaximumPerFaceShouldBeHigh": 1000, + "SortingMaximumPerKey": 27, + "SortingSigma": 3, "TestDistanceResults": true, "WriteBitmapDataBytes": false, "IgnoreExtensions": [ diff --git a/Map/Models/Configuration.cs b/Map/Models/Configuration.cs new file mode 100644 index 0000000..2e12279 --- /dev/null +++ b/Map/Models/Configuration.cs @@ -0,0 +1,80 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Map.Models; + +public class Configuration +{ + + public int FaceDistanceHiddenImageFactor { init; get; } + 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 bool MappingSaveFaceEncoding { init; get; } + public bool MappingSaveMapped { init; get; } + public bool MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping { init; get; } + public bool MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping { init; get; } + public int PersonBirthdayFirstYear { init; get; } + public string PersonBirthdayFormat { init; get; } + public string PersonKeyFormat { init; get; } + public int SortingDaysDeltaTolerance { init; get; } + public int SortingFacesToSkipAfterSortBeforeLoad { init; get; } + public int SortingFacesToTakeAfterSortBeforeLoad { init; get; } + public int SortingMaximumPerFaceShouldBeHigh { init; get; } + public int SortingMaximumPerKey { init; get; } + public int SortingSigma { init; get; } + + [JsonConstructor] + public Configuration(int faceDistanceHiddenImageFactor, + int faceDistancePermyriad, + double faceDistanceMinimumConfidence, + double faceDistanceTolerance, + int locationDigits, + int locationFactor, + int mapLogicSigma, + bool mappingSaveFaceEncoding, + bool mappingSaveMapped, + bool mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping, + bool mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping, + int personBirthdayFirstYear, + string personBirthdayFormat, + string personKeyFormat, + int sortingDaysDeltaTolerance, + int sortingFacesToSkipAfterSortBeforeLoad, + int sortingFacesToTakeAfterSortBeforeLoad, + int sortingMaximumPerFaceShouldBeHigh, + int sortingMaximumPerKey, + int sortingSigma) + { + FaceDistanceHiddenImageFactor = faceDistanceHiddenImageFactor; + FaceDistancePermyriad = faceDistancePermyriad; + FaceDistanceMinimumConfidence = faceDistanceMinimumConfidence; + FaceDistanceTolerance = faceDistanceTolerance; + LocationDigits = locationDigits; + LocationFactor = locationFactor; + MapLogicSigma = mapLogicSigma; + MappingSaveFaceEncoding = mappingSaveFaceEncoding; + MappingSaveMapped = mappingSaveMapped; + MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping = mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping; + MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping = mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping; + PersonBirthdayFirstYear = personBirthdayFirstYear; + PersonBirthdayFormat = personBirthdayFormat; + PersonKeyFormat = personKeyFormat; + SortingDaysDeltaTolerance = sortingDaysDeltaTolerance; + SortingFacesToSkipAfterSortBeforeLoad = sortingFacesToSkipAfterSortBeforeLoad; + SortingFacesToTakeAfterSortBeforeLoad = sortingFacesToTakeAfterSortBeforeLoad; + SortingMaximumPerFaceShouldBeHigh = sortingMaximumPerFaceShouldBeHigh; + SortingMaximumPerKey = sortingMaximumPerKey; + SortingSigma = sortingSigma; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Map/Models/MapLogic.cs b/Map/Models/MapLogic.cs index 4b7e1f9..b28fc49 100644 --- a/Map/Models/MapLogic.cs +++ b/Map/Models/MapLogic.cs @@ -1,6 +1,5 @@ using ShellProgressBar; using System.Text.Json; -using View_by_Distance.Property.Models; using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Stateless.Methods; using WindowsShortcutFactory; @@ -23,8 +22,12 @@ public class MapLogic public Dictionary IndicesFromNew => _IndicesFromNew; private readonly long _Ticks; + private const int _Mapping = 1; + private const int _Sorting = 2; + private Configuration? _Configuration; private readonly Serilog.ILogger? _Log; - private readonly Configuration _Configuration; + private const int _ForceSingleImage = 3; + private readonly int _MaxDegreeOfParallelism; private readonly string _FacesFilenameExtension; private readonly string _ResizeFilenameExtension; private readonly string _FacePartsFilenameExtension; @@ -32,18 +35,21 @@ public class MapLogic private readonly string _ZPropertyHolderContentDirectory; private readonly string _ZPropertyHolderContentTicksDirectory; private readonly string _ZPropertyHolderSingletonTicksDirectory; + private readonly Property.Models.Configuration _PropertyConfiguration; - public MapLogic(int maxDegreeOfParallelism, Configuration configuration, string resizeFilenameExtension, string facesFilenameExtension, string facesHiddenFilenameExtension, string facePartsFilenameExtension, long ticks, Person[] people, string peopleDateGroupDirectory, string zResultsFullGroupDirectory) + public MapLogic(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, string resizeFilenameExtension, string facesFilenameExtension, string facesHiddenFilenameExtension, string facePartsFilenameExtension, long ticks, Person[] people, string peopleDateGroupDirectory, string zResultsFullGroupDirectory, Configuration? configuration, List distinctFilteredFaces, Shared.Models.Methods.IFaceDistance? distance) { _Ticks = ticks; _PersonKeysRanges = new(); _Configuration = configuration; _Log = Serilog.Log.ForContext(); + _PropertyConfiguration = propertyConfiguration; _FacesFilenameExtension = facesFilenameExtension; + _MaxDegreeOfParallelism = maxDegreeOfParallelism; _ResizeFilenameExtension = resizeFilenameExtension; _FacePartsFilenameExtension = facePartsFilenameExtension; _FacesHiddenFilenameExtension = facesHiddenFilenameExtension; - if (configuration.VerifyToSeason is null || !configuration.VerifyToSeason.Any()) + if (propertyConfiguration.VerifyToSeason is null || !propertyConfiguration.VerifyToSeason.Any()) throw new Exception(); string json; string[] files; @@ -54,7 +60,7 @@ public class MapLogic Dictionary? keyValuePairs; List>? collection; Dictionary indicesFromNew = new(); - string? rootDirectoryParent = Path.GetDirectoryName(configuration.RootDirectory); + string? rootDirectoryParent = Path.GetDirectoryName(propertyConfiguration.RootDirectory); Dictionary peopleKeyValuePairs = new(); string zPropertyHolderContentDirectory = Path.Combine(zResultsFullGroupDirectory, "()"); string zPropertyHolderSingletonDirectory = Path.Combine(zResultsFullGroupDirectory, "{}"); @@ -72,7 +78,7 @@ public class MapLogic _ = Directory.CreateDirectory(zPropertyHolderContentDirectory); if (!Directory.Exists(zPropertyHolderPeopleContentDirectory)) _ = Directory.CreateDirectory(zPropertyHolderPeopleContentDirectory); - Stateless.ByDeterministicHashCode.SetByRef(maxDegreeOfParallelism, ticks, _ResizeFilenameExtension, people, skipCollection, peopleKeyValuePairs, notMappedTicks, idThenNormalizedPixelPercentageKeyValuePairs, incorrectIdThenNormalizedPixelPercentageKeyValuePairs, zPropertyHolderContentDirectory, zPropertyHolderPeopleContentDirectory); + Stateless.ByRef.Set(propertyConfiguration, configuration, ticks, _ResizeFilenameExtension, people, zPropertyHolderContentDirectory, zPropertyHolderPeopleContentDirectory, distinctFilteredFaces, distance, skipCollection, peopleKeyValuePairs, notMappedTicks, idThenNormalizedPixelPercentageKeyValuePairs, incorrectIdThenNormalizedPixelPercentageKeyValuePairs); if (!Directory.Exists(zPropertyHolderContentTicksDirectory)) _ = Directory.CreateDirectory(zPropertyHolderContentTicksDirectory); files = Directory.GetFiles(rootDirectoryParent, "*keyValuePairs-6*.json", SearchOption.TopDirectoryOnly); @@ -85,10 +91,10 @@ public class MapLogic if (keyValuePairs is null) throw new NullReferenceException(nameof(keyValuePairs)); } - foreach (string propertyContentCollectionFile in configuration.PropertyContentCollectionFiles) + foreach (string propertyContentCollectionFile in propertyConfiguration.PropertyContentCollectionFiles) { fullPath = Path.GetFullPath(string.Concat(rootDirectoryParent, propertyContentCollectionFile)); - if (fullPath.Contains(configuration.RootDirectory)) + if (fullPath.Contains(propertyConfiguration.RootDirectory)) continue; if (!File.Exists(fullPath)) continue; @@ -115,8 +121,12 @@ public class MapLogic _IncorrectIdThenNormalizedPixelPercentageKeyValuePairs = incorrectIdThenNormalizedPixelPercentageKeyValuePairs; } - public MapLogic(int maxDegreeOfParallelism, Configuration configuration, string outputExtension, long ticks, Person[] people, string peopleDateGroupDirectory, string zResultsFullGroupDirectory) : - this(maxDegreeOfParallelism, configuration, outputExtension, outputExtension, outputExtension, outputExtension, ticks, people, peopleDateGroupDirectory, zResultsFullGroupDirectory) + public MapLogic(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, string resizeFilenameExtension, string facesFilenameExtension, string facesHiddenFilenameExtension, string facePartsFilenameExtension, long ticks, Person[] people, string peopleDateGroupDirectory, string zResultsFullGroupDirectory) : + this(maxDegreeOfParallelism, propertyConfiguration, resizeFilenameExtension, facesFilenameExtension, facesHiddenFilenameExtension, facePartsFilenameExtension, ticks, people, peopleDateGroupDirectory, zResultsFullGroupDirectory, null, new(), null) + { } + + public MapLogic(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, string outputExtension, long ticks, Person[] people, string peopleDateGroupDirectory, string zResultsFullGroupDirectory) : + this(maxDegreeOfParallelism, propertyConfiguration, outputExtension, outputExtension, outputExtension, outputExtension, ticks, people, peopleDateGroupDirectory, zResultsFullGroupDirectory, null, new(), null) { } public override string ToString() @@ -125,6 +135,8 @@ public class MapLogic return result; } + public void Update(Configuration configuration) => _Configuration = configuration; + public bool Skip(double deterministicHashCodeKey) => _SkipCollection.Contains(deterministicHashCodeKey); private long LogDelta(long ticks, string? methodName) @@ -154,6 +166,8 @@ public class MapLogic public List GetSortingCollection(int i, FaceDistance faceDistanceEncoding, List faceDistanceLengths, bool anyLowerThanTolerance) { + if (_Configuration is null) + throw new NullReferenceException(nameof(_Configuration)); List results = new(); Sorting sorting; FaceDistance faceDistanceLength; @@ -180,7 +194,7 @@ public class MapLogic if (!keyValuePairs.ContainsKey(faceDistanceLength.NormalizedPixelPercentage.Value)) continue; personKeysRangesCollection = GetPersonKeysRangesCollection(keyValuePairs[faceDistanceLength.NormalizedPixelPercentage.Value]); - sorting = ISorting.Get(Shared.Models.Stateless.IFaceDistance.Permyriad, Shared.Models.Stateless.IFaceDistance.Tolerance, faceDistanceEncoding, faceDistanceLength, anyLowerThanTolerance, personKeysRangesCollection); + sorting = ISorting.Get(_Configuration.FaceDistancePermyriad, _Configuration.FaceDistanceTolerance, faceDistanceEncoding, faceDistanceLength, anyLowerThanTolerance, personKeysRangesCollection); if (sorting.DistancePermyriad == 0) continue; if (sorting.Id == faceDistanceEncoding.Id) @@ -196,6 +210,8 @@ public class MapLogic public void SaveShortcuts(string[] juliePhares, List distinctFilteredFaces) { + if (_Configuration is null) + throw new NullReferenceException(nameof(_Configuration)); string fileName; string fullName; string personKeyFormatted; @@ -210,7 +226,7 @@ public class MapLogic if (face.Mapping is null) throw new NotSupportedException(); personBirthday = IPersonBirthday.GetPersonBirthday(personKey.Value); - personKeyFormatted = IPersonBirthday.GetFormatted(Shared.Models.Stateless.IPersonBirthday.Format, personBirthday); + personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday); if (juliePhares.Contains(personKeyFormatted) && !string.IsNullOrEmpty(copyDirectory)) { if (!Directory.Exists(copyDirectory)) @@ -241,25 +257,6 @@ public class MapLogic } } - private void UseKeyValuePairsSaveFaceEncoding(int maxDegreeOfParallelism, SortingContainer[] sortingContainers) - { - Dictionary personKeyAliases = new(); - Dictionary> keyValuePairs = new(); - List<(PersonBirthday, int, int)> idThenNormalizedPixelPercentageCollection = new(); - List<(PersonBirthday, int, int)> incorrectIdThenNormalizedPixelPercentageCollection = new(); - foreach (SortingContainer sortingContainer in sortingContainers) - { - if (sortingContainer.Face.FaceEncoding is null || sortingContainer.Face.Location?.NormalizedPixelPercentage is null) - throw new NotSupportedException(); - if (sortingContainer.Face.Mapping is null) - throw new NotSupportedException(); - if (!keyValuePairs.ContainsKey(sortingContainer.Face.Mapping.MappingFromItem.Id)) - keyValuePairs.Add(sortingContainer.Face.Mapping.MappingFromItem.Id, new()); - keyValuePairs[sortingContainer.Face.Mapping.MappingFromItem.Id].Add(sortingContainer.Face); - } - Stateless.ByDeterministicHashCode.SetCollections(maxDegreeOfParallelism, _Ticks, _ZPropertyHolderContentDirectory, personKeyAliases, idThenNormalizedPixelPercentageCollection, incorrectIdThenNormalizedPixelPercentageCollection, keyValuePairs); - } - private static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, long minimumDateTimeTicks, bool? isWrongYear) { int years; @@ -298,8 +295,10 @@ public class MapLogic return result; } - private static Dictionary GetKeyValuePairs(string json) + private Dictionary GetKeyValuePairs(string json) { + if (_Configuration is null) + throw new NullReferenceException(nameof(_Configuration)); Dictionary results = new(); PersonBirthday? personBirthday; List personBirthdays; @@ -311,7 +310,7 @@ public class MapLogic personBirthdays = new(); foreach (string personKey in keyValuePair.Value) { - personBirthday = IPersonBirthday.GetPersonBirthday(Shared.Models.Stateless.IPersonBirthday.Format, personKey); + personBirthday = IPersonBirthday.GetPersonBirthday(_Configuration.PersonBirthdayFormat, personKey); if (personBirthday is null) continue; } @@ -322,10 +321,13 @@ public class MapLogic return results; } - private int AddToMapping(List distinctFilteredFaces) + public int AddToMapping(List distinctFilteredFaces) { + if (_Configuration is null) + throw new NullReferenceException(nameof(_Configuration)); int result = 0; long personKey; + int by = _Mapping; const int zero = 0; int? approximateYears; string mappingSegmentB; @@ -334,7 +336,6 @@ public class MapLogic PersonBirthday personBirthday; List personBirthdays = new(); Dictionary keyValuePairs; - int by = Shared.Models.Stateless.ISorting.Mapping; (string DisplayDirectoryName, int? ApproximateYears, PersonBirthday[] PersonBirthdays, long PersonKey) person; foreach (Face face in distinctFilteredFaces) { @@ -360,7 +361,7 @@ public class MapLogic approximateYears = person.ApproximateYears; personBirthday = person.PersonBirthdays[zero]; displayDirectoryName = person.DisplayDirectoryName; - personKeyFormatted = IPersonBirthday.GetFormatted(Shared.Models.Stateless.IPersonBirthday.Format, personBirthday); + personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday); mappingSegmentB = GetMappingSegmentB(_Ticks, personBirthday, approximateYears, face.Mapping.MappingFromItem); face.Mapping.UpdateMappingFromPerson(approximateYears, by, displayDirectoryName, personBirthday, mappingSegmentB); } @@ -374,7 +375,7 @@ public class MapLogic string[] directories = (from l in saveContainers select l.Directory).Distinct().ToArray(); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - _Ticks).TotalSeconds); string message = $") {saveContainers.Count:000} save(s) - {totalSeconds} total second(s)"; - ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = false }; + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; foreach (string directory in directories) { if (string.IsNullOrEmpty(directory)) @@ -424,19 +425,21 @@ public class MapLogic } } - private void SaveNotMappedTicks() + public void SaveNotMappedTicks(Property.Models.Configuration propertyConfiguration) { + if (_Configuration is null) + throw new NullReferenceException(nameof(_Configuration)); string directory; string personKeyFormatted; SaveContainer saveContainer; PersonBirthday personBirthday; List saveContainers = new(); - const string facePopulatedKey = nameof(Sorting); + const string facePopulatedKey = nameof(_Sorting); foreach (long personKey in _NotMappedPersonKeys) { personBirthday = IPersonBirthday.GetPersonBirthday(personKey); - personKeyFormatted = IPersonBirthday.GetFormatted(Shared.Models.Stateless.IPersonBirthday.Format, personBirthday); - directory = Path.Combine(_ZPropertyHolderContentTicksDirectory, $"{facePopulatedKey}NotMapped", personKeyFormatted, Property.Models.Stateless.IResult.AllInOne); + personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday); + directory = Path.Combine(_ZPropertyHolderContentTicksDirectory, $"{facePopulatedKey}NotMapped", personKeyFormatted, propertyConfiguration.ResultAllInOne); saveContainer = new(directory); saveContainers.Add(saveContainer); } @@ -445,6 +448,8 @@ public class MapLogic public List<(Face, long?, (string, string, string, string))> GetCollection(List distinctFilteredFaces) { + if (_Configuration is null) + throw new NullReferenceException(nameof(_Configuration)); List<(Face, long?, (string, string, string, string))> results = new(); int years; long? personKey; @@ -504,7 +509,7 @@ public class MapLogic subDirectoryName = $"^{years:000}"; } } - personKeyFormatted = IPersonBirthday.GetFormatted(Shared.Models.Stateless.IPersonBirthday.Format, personBirthday); + personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday); directory = Path.Combine(_ZPropertyHolderContentTicksDirectory, "Shortcuts", personKeyFormatted, subDirectoryName); if (face.FaceEncoding is not null && face.Location?.NormalizedPixelPercentage is not null) copyDirectory = Path.Combine(_ZPropertyHolderContentTicksDirectory, "Images", personKeyFormatted, subDirectoryName); @@ -550,6 +555,8 @@ public class MapLogic private int UpdateFromSortingContainers(SortingContainer[] sortingContainers) { + if (_Configuration is null) + throw new NullReferenceException(nameof(_Configuration)); int result = 0; Dictionary> results = new(); string key; @@ -557,22 +564,23 @@ public class MapLogic const int zero = 0; HashSet hashSet; string mappingSegmentB; + const int by = _Sorting; string personKeyFormatted; List checkCollection; PersonBirthday personBirthday; PersonBirthday[] personBirthdays; Dictionary keyValuePairs; - const int by = Shared.Models.Stateless.ISorting.Sorting; Dictionary> checkKeyValuePairs = new(); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - _Ticks).TotalSeconds); (string DisplayDirectoryName, int? ApproximateYears, PersonBirthday[] PersonBirthdays, long PersonKey) person; string message = $") {sortingContainers.Length:000} Update From Sorting Container(s) - {totalSeconds} total second(s)"; - ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = false }; + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; foreach (KeyValuePair> keyValuePair in _IdThenNormalizedPixelPercentageKeyValuePairs) results.Add(keyValuePair.Key, (from l in keyValuePair.Value select l.Key).ToHashSet()); using ProgressBar progressBar = new(sortingContainers.Length, message, options); foreach (SortingContainer sortingContainer in sortingContainers) { + progressBar.Tick(); if (sortingContainer.Face.Mapping is null) throw new NotSupportedException(); if (!_IdThenNormalizedPixelPercentageKeyValuePairs.ContainsKey(sortingContainer.Sorting.Id)) @@ -586,7 +594,7 @@ public class MapLogic if (!keyValuePairs.ContainsKey(sortingContainer.Sorting.NormalizedPixelPercentage)) throw new NotSupportedException(); personBirthdays = keyValuePairs[sortingContainer.Sorting.NormalizedPixelPercentage]; - if (sortingContainer.Face.Mapping.MappingFromLocation.Confidence < Shared.Models.Stateless.IFaceDistance.MinimumConfidence || sortingContainer.Sorting.DistancePermyriad > Shared.Models.Stateless.IFaceDistance.Permyriad || sortingContainer.Sorting.DaysDelta > Shared.Models.Stateless.ISorting.DaysDeltaTolerance) + if (sortingContainer.Face.Mapping.MappingFromLocation.Confidence < _Configuration.FaceDistanceMinimumConfidence || sortingContainer.Sorting.DistancePermyriad > _Configuration.FaceDistancePermyriad || sortingContainer.Sorting.DaysDelta > _Configuration.SortingDaysDeltaTolerance) continue; for (int i = 0; i < personBirthdays.Length; i++) { @@ -595,13 +603,13 @@ public class MapLogic continue; person = _PeopleKeyValuePairs[personKey]; personBirthday = person.PersonBirthdays[zero]; - personKeyFormatted = IPersonBirthday.GetFormatted(Shared.Models.Stateless.IPersonBirthday.Format, personBirthday); + personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday); mappingSegmentB = GetMappingSegmentB(_Ticks, personBirthday, person.ApproximateYears, sortingContainer.Face.Mapping.MappingFromItem); key = string.Concat(personKeyFormatted, '\t', mappingSegmentB); if (!checkKeyValuePairs.ContainsKey(key)) checkKeyValuePairs.Add(key, new()); checkCollection = checkKeyValuePairs[key]; - if (checkCollection.Count > Shared.Models.Stateless.ISorting.MaximumPerKey) + if (checkCollection.Count > _Configuration.SortingMaximumPerKey) continue; _ = hashSet.Add(sortingContainer.Sorting.NormalizedPixelPercentage); sortingContainer.Face.Mapping.UpdateMappingFromPerson(person.ApproximateYears, by, person.DisplayDirectoryName, personBirthday, mappingSegmentB); @@ -613,16 +621,16 @@ public class MapLogic return result; } - internal void ForceSingleImage(IEnumerable distinctFilteredFaces) + internal void ForceSingleImage(Property.Models.Configuration propertyConfiguration, IEnumerable distinctFilteredFaces) { long? personKey; const int zero = 0; string mappingSegmentB; + int by = _ForceSingleImage; int? approximateYears = null; PersonBirthday personBirthday; - int by = Shared.Models.Stateless.ISorting.ForceSingleImage; + string displayDirectoryName = propertyConfiguration.ResultAllInOne; Face[] orderedDistinctFilteredFaces = (from l in distinctFilteredFaces orderby l.Mapping is not null, l.Mapping?.MappingFromLocation.Confidence descending select l).ToArray(); - const string displayDirectoryName = Property.Models.Stateless.IResult.AllInOne; foreach (Face face in orderedDistinctFilteredFaces) { if (face.Mapping is null) @@ -639,6 +647,8 @@ public class MapLogic private List GetMappingSaveContainers(string dFacesContentDirectory, string d2ResultsFullGroupDirectory, List filteredFaces) { + if (_Configuration is null) + throw new NullReferenceException(nameof(_Configuration)); List results = new(); string by; string json; @@ -654,6 +664,7 @@ public class MapLogic SaveContainer saveContainer; FileHolder facePartsFileHolder; FileHolder hiddenFaceFileHolder; + Dictionary keyValuePairs = new(); foreach (Face face in filteredFaces) { if (face.Mapping is null) @@ -665,24 +676,27 @@ public class MapLogic continue; if (string.IsNullOrEmpty(face.Mapping.MappingFromPerson.SegmentB)) throw new NotSupportedException(); - personKeyFormatted = IPersonBirthday.GetFormatted(Shared.Models.Stateless.IPersonBirthday.Format, face.Mapping.MappingFromPerson.PersonBirthday); + personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, face.Mapping.MappingFromPerson.PersonBirthday); if (face.Mapping.MappingFromPerson.By is null) - by = $"{nameof(Mapping)}Null"; + by = $"{nameof(_Mapping)}Null"; else { - if (face.Mapping.MappingFromPerson.By == Shared.Models.Stateless.ISorting.Mapping && !Shared.Models.Stateless.IMapping.SaveMapped) + if (face.Mapping.MappingFromPerson.By == _Mapping && !_Configuration.MappingSaveMapped) continue; by = face.Mapping.MappingFromPerson.By.Value switch { - Shared.Models.Stateless.ISorting.Mapping => nameof(Mapping), - Shared.Models.Stateless.ISorting.Sorting => nameof(Sorting), - Shared.Models.Stateless.ISorting.ForceSingleImage => nameof(MapLogic.ForceSingleImage), + _Mapping => nameof(_Mapping), + _Sorting => nameof(_Sorting), + _ForceSingleImage => nameof(MapLogic.ForceSingleImage), _ => throw new NotImplementedException() }; } directory = Path.Combine(_ZPropertyHolderContentTicksDirectory, by, personKeyFormatted, face.Mapping.MappingFromPerson.SegmentB); + if (!keyValuePairs.ContainsKey(directory)) + keyValuePairs.Add(directory, 0); + keyValuePairs[directory]++; saveContainer = new(Path.Combine(directory, "!")); - if (face.Mapping.MappingFromPerson.By.HasValue && face.Mapping.MappingFromPerson.By == Shared.Models.Stateless.ISorting.Sorting) + if (face.Mapping.MappingFromPerson.By.HasValue && face.Mapping.MappingFromPerson.By == _Sorting && keyValuePairs[directory] > 3) results.Add(saveContainer); if (face.Mapping.MappingFromPerson.By is not null) personDirectory = Path.Combine(directory, face.Mapping.MappingFromPerson.DisplayDirectoryName, "lnk"); @@ -692,19 +706,19 @@ public class MapLogic results.Add(saveContainer); facesDirectory = string.Concat(dFacesContentDirectory, Path.Combine(directoryName, face.Mapping.MappingFromItem.ImageFileHolder.NameWithoutExtension)); facePartsDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, face.Mapping.MappingFromItem.ImageFileHolder.NameWithoutExtension)); - checkFile = Path.Combine(directory, $"{face.Mapping.MappingFromLocation.DeterministicHashCodeKeyDisplay}{face.Mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}"); - faceFileHolder = new(Path.Combine(facesDirectory, $"{face.Mapping.MappingFromLocation.DeterministicHashCodeKeyDisplay}{face.Mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_FacesFilenameExtension}")); - hiddenFaceFileHolder = new(Path.Combine(facesDirectory, $"{face.Mapping.MappingFromLocation.DeterministicHashCodeKeyDisplay}{face.Mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_FacesHiddenFilenameExtension}")); - facePartsFileHolder = new(Path.Combine(facePartsDirectory, $"{face.Mapping.MappingFromLocation.DeterministicHashCodeKeyDisplay}{face.Mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_FacePartsFilenameExtension}")); + checkFile = Path.Combine(directory, $"{face.Mapping.MappingFromLocation.DeterministicHashCodeKey}{face.Mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}"); + faceFileHolder = new(Path.Combine(facesDirectory, $"{face.Mapping.MappingFromLocation.DeterministicHashCodeKey}{face.Mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_FacesFilenameExtension}")); + hiddenFaceFileHolder = new(Path.Combine(facesDirectory, $"{face.Mapping.MappingFromLocation.DeterministicHashCodeKey}{face.Mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_FacesHiddenFilenameExtension}")); + facePartsFileHolder = new(Path.Combine(facePartsDirectory, $"{face.Mapping.MappingFromLocation.DeterministicHashCodeKey}{face.Mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{_FacePartsFilenameExtension}")); if (string.IsNullOrEmpty(personDirectory)) shortcutFile = string.Empty; else - shortcutFile = Path.Combine(personDirectory, $"{face.Mapping.MappingFromLocation.DeterministicHashCodeKeyDisplay}{face.Mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}.lnk"); + shortcutFile = Path.Combine(personDirectory, $"{face.Mapping.MappingFromLocation.DeterministicHashCodeKey}{face.Mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}.lnk"); saveContainer = new(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, string.Empty, facePartsFileHolder, face.Mapping.MappingFromItem.ResizedFileHolder, shortcutFile); results.Add(saveContainer); - if (!string.IsNullOrEmpty(checkFile) && Shared.Models.Stateless.IMapping.SaveFaceEncoding) + if (!string.IsNullOrEmpty(checkFile) && _Configuration.MappingSaveFaceEncoding) { - checkFile = Path.Combine(directory, $"{face.Mapping.MappingFromLocation.DeterministicHashCodeKeyDisplay}{face.Mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}.json"); + checkFile = Path.Combine(directory, $"{face.Mapping.MappingFromLocation.DeterministicHashCodeKey}{face.Mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}.json"); json = JsonSerializer.Serialize(face.FaceEncoding); saveContainer = new(checkFile, directory, json); results.Add(saveContainer); @@ -714,28 +728,22 @@ public class MapLogic return results; } - public void CommonWork(int maxDegreeOfParallelism, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, List distinctFilteredFaces, SortingContainer[] sortingContainers) + public void ForceSingleImageThenSaveMapping(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, List distinctFilteredFaces, SortingContainer[] sortingContainers, int totalNotMapped) { List saveContainers; - if (!_IdThenNormalizedPixelPercentageKeyValuePairs.Any()) - UseKeyValuePairsSaveFaceEncoding(maxDegreeOfParallelism, sortingContainers); - int totalNotMapped = AddToMapping(distinctFilteredFaces); - if (totalNotMapped == 0) - saveContainers = new(); - else if (!sortingContainers.Any()) + if (!sortingContainers.Any()) { - ForceSingleImage(distinctFilteredFaces); + ForceSingleImage(propertyConfiguration, distinctFilteredFaces); saveContainers = GetMappingSaveContainers(dFacesContentDirectory, d2ResultsFullGroupDirectory, distinctFilteredFaces); } else { int updated = UpdateFromSortingContainers(sortingContainers); if (totalNotMapped - updated > 0) - ForceSingleImage(distinctFilteredFaces); + ForceSingleImage(propertyConfiguration, distinctFilteredFaces); saveContainers = GetMappingSaveContainers(dFacesContentDirectory, d2ResultsFullGroupDirectory, distinctFilteredFaces); } SaveContainers(saveContainers); - SaveNotMappedTicks(); } private static double GetStandardDeviation(IEnumerable values, double average) @@ -782,16 +790,16 @@ public class MapLogic } } - public void SetPersonTicks(string outputResolution, Face[] filteredFaces) + public void SetPersonTicks(List distinctFilteredFaces) { PersonBirthday[] personBirthdays; Dictionary keyValuePairs; Dictionary> personTicks = new(); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - _Ticks).TotalSeconds); - string message = $") {filteredFaces.Length:000} Set Person Ticks - {totalSeconds} total second(s) - {outputResolution}"; + string message = $") {distinctFilteredFaces.Count:000} Set Person Ticks - {totalSeconds} total second(s)"; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - using ProgressBar progressBar = new(filteredFaces.Length, message, options); - foreach (Face face in filteredFaces) + using ProgressBar progressBar = new(distinctFilteredFaces.Count, message, options); + foreach (Face face in distinctFilteredFaces) { progressBar.Tick(); if (face.Mapping is null) diff --git a/Map/Models/Stateless/SetByDeterministicHashCode.cs b/Map/Models/Stateless/ByRef.cs similarity index 62% rename from Map/Models/Stateless/SetByDeterministicHashCode.cs rename to Map/Models/Stateless/ByRef.cs index 3289eef..264048f 100644 --- a/Map/Models/Stateless/SetByDeterministicHashCode.cs +++ b/Map/Models/Stateless/ByRef.cs @@ -5,10 +5,10 @@ using View_by_Distance.Shared.Models; namespace View_by_Distance.Map.Models.Stateless; -public class ByDeterministicHashCode +public class ByRef { - private static void SetOther(string resizeFilenameExtension, Person[] people, string deterministicHashCodePeopleDirectory, List skipCollection, Dictionary personKeyAliases, List<(string, int?, PersonBirthday[], long)> peopleCollection) + private static void SetOther(Property.Models.Configuration propertyConfiguration, Configuration configuration, string resizeFilenameExtension, Person[] people, string deterministicHashCodePeopleDirectory, List skipCollection, Dictionary personKeyAliases, List<(string, int?, PersonBirthday[], long)> peopleCollection) { long pK; string json; @@ -32,7 +32,7 @@ public class ByDeterministicHashCode Dictionary personKeyValuePairs = new(); foreach (Person person in people) { - personKeyFormatted = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(Shared.Models.Stateless.IPersonBirthday.Format, person.Birthday); + personKeyFormatted = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, person.Birthday); if (personKeyValuePairs.ContainsKey(personKeyFormatted)) break; personKeyValuePairs.Add(personKeyFormatted, person); @@ -71,11 +71,11 @@ public class ByDeterministicHashCode { personKeyFormatted = Path.GetFileName(personKeyDirectory); if (!DateTime.TryParseExact(personKeyFormatted, "MM.dd.yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime birthday)) - personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(Shared.Models.Stateless.IPersonBirthday.Format, personKeyFormatted); + personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, personKeyFormatted); else { personBirthday = new PersonBirthday(birthday); - personKeyFormatted = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(Shared.Models.Stateless.IPersonBirthday.Format, personBirthday); + personKeyFormatted = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personBirthday); convertedPersonKeyDirectory = Path.Combine(personDisplayDirectory, personKeyFormatted); if (!Directory.Exists(convertedPersonKeyDirectory)) Directory.Move(personKeyDirectory, convertedPersonKeyDirectory); @@ -89,7 +89,7 @@ public class ByDeterministicHashCode foreach (string personKeyDirectory in personKeyDirectories) { personKeyFormatted = Path.GetFileName(personKeyDirectory); - personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(Shared.Models.Stateless.IPersonBirthday.Format, personKeyFormatted); + personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, personKeyFormatted); if (personBirthday is null) continue; if (personKeyValuePairs.ContainsKey(personKeyFormatted)) @@ -123,25 +123,27 @@ public class ByDeterministicHashCode } } approximateYears = null; - const string displayDirectoryName = Property.Models.Stateless.IResult.AllInOne; - DateTime incrementDate = new(Shared.Models.Stateless.IPersonBirthday.FirstYear, 1, 1); + string displayDirectoryName = propertyConfiguration.ResultAllInOne; + DateTime incrementDate = new(configuration.PersonBirthdayFirstYear, 1, 1); for (int i = 0; i < 500; i++) { personKey = incrementDate.Ticks; personBirthday = new(incrementDate); incrementDate = incrementDate.AddDays(1); - personKeyFormatted = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(Shared.Models.Stateless.IPersonBirthday.Format, personBirthday); + personKeyFormatted = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personBirthday); if (personKeys.Contains(personKey)) continue; personKeys.Add(personKey); peopleCollection.Add(new(displayDirectoryName, approximateYears, new PersonBirthday[] { personBirthday }, personKey)); } } - internal static void SetCollections(int maxDegreeOfParallelism, long ticks, string zPropertyHolderContentDirectory, Dictionary personKeyAliases, List<(PersonBirthday, int, int)> idThenNormalizedPixelPercentageCollection, List<(PersonBirthday, int, int)> incorrectIdThenNormalizedPixelPercentageCollection, Dictionary> keyValuePairs) + + internal static List<(string, char, string, int?, int?, List?)> DeleteEmptyDirectoriesAndGetCollection(Configuration configuration, long ticks, string zPropertyHolderContentDirectory, Dictionary> keyValuePairs) { + List<(string, char, string, int?, int?, List?)> results = new(); int? id; string[] files; - long personKey; + List? faces; const int zero = 0; string[] yearDirectories; string personKeyFormatted; @@ -150,14 +152,12 @@ public class ByDeterministicHashCode string[] personKeyDirectories; int? normalizedPixelPercentage; string[] personNameDirectories; - PersonBirthday? personBirthday; string[] personNameLinkDirectories; string? personFirstInitialDirectory; bool keyValuePairsAny = keyValuePairs.Any(); - ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); string[] ticksDirectories = Directory.GetDirectories(zPropertyHolderContentDirectory, "*", SearchOption.TopDirectoryOnly); - string message = $") {ticksDirectories.Length:000} ticks Director(ies) - {totalSeconds} total second(s)"; + string message = $") {ticksDirectories.Length:000} 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) @@ -170,20 +170,8 @@ public class ByDeterministicHashCode foreach (string personKeyDirectory in personKeyDirectories) { personKeyFormatted = Path.GetFileName(personKeyDirectory); - if (personKeyFormatted.Length != Shared.Models.Stateless.IPersonBirthday.Format.Length) - personBirthday = null; - else - { - personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(Shared.Models.Stateless.IPersonBirthday.Format, personKeyFormatted); - if (personBirthday is null) - continue; - personKey = personBirthday.Value.Ticks; - if (personKeyAliases.ContainsKey(personKey)) - { - personKey = personKeyAliases[personKey]; - personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey); - } - } + if (personKeyFormatted.Length != configuration.PersonBirthdayFormat.Length) + continue; yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly); foreach (string yearDirectory in yearDirectories) { @@ -196,27 +184,24 @@ public class ByDeterministicHashCode personFirstInitial = Path.GetFileName(personNameDirectory)[..1]; if (personFirstInitial is null) continue; - personFirstInitialDirectory = Path.Combine(yearDirectory, personFirstInitial); - files = Directory.GetFiles(personNameDirectory, "*", SearchOption.TopDirectoryOnly); + personFirstInitialDirectory = Path.Combine(yearDirectory, personFirstInitial.ToString()); + if (personNameDirectory != personFirstInitialDirectory) + Directory.Move(personNameDirectory, personFirstInitialDirectory); + files = Directory.GetFiles(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly); if (personKeyFormatted == nameof(Models.MapLogic.ForceSingleImage) && files.Any()) throw new Exception($"Move personKey directories up one from {nameof(Models.MapLogic.ForceSingleImage)} and delete {nameof(Models.MapLogic.ForceSingleImage)} directory!"); if (personKeyFormatted == nameof(Sorting) && files.Any()) throw new Exception($"Move personKey directories up one from {nameof(Sorting)} and delete {nameof(Sorting)} directory!"); - if (personBirthday is null) - continue; foreach (string file in files) { if (file.EndsWith(".lnk") || file.EndsWith(".json")) continue; - (id, normalizedPixelPercentage) = Shared.Models.Stateless.Methods.IMapping.GetReversedDeterministicHashCodeKey(Shared.Models.Stateless.ILocation.Digits, keyValuePairsAny, keyValuePairs, file); + (id, normalizedPixelPercentage, faces) = Shared.Models.Stateless.Methods.IMapping.GetReversedDeterministicHashCodeKey(configuration.LocationDigits, keyValuePairsAny, keyValuePairs, file); if (id is null || normalizedPixelPercentage is null) continue; - if (personFirstInitial != "!") - idThenNormalizedPixelPercentageCollection.Add(new(personBirthday, id.Value, normalizedPixelPercentage.Value)); - else - incorrectIdThenNormalizedPixelPercentageCollection.Add(new(personBirthday, id.Value, normalizedPixelPercentage.Value)); + results.Add(new(personKeyFormatted, personFirstInitial[0], file, id, normalizedPixelPercentage, faces)); } - personNameLinkDirectories = Directory.GetDirectories(personNameDirectory, "*", SearchOption.TopDirectoryOnly); + personNameLinkDirectories = Directory.GetDirectories(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly); foreach (string personNameLinkDirectory in personNameLinkDirectories) { files = Directory.GetFiles(personNameLinkDirectory, "*", SearchOption.TopDirectoryOnly); @@ -228,10 +213,7 @@ public class ByDeterministicHashCode } _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(personNameLinkDirectory); } - if (personNameDirectory == personFirstInitialDirectory) - continue; - Directory.Move(personNameDirectory, personFirstInitialDirectory); - _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(personNameDirectory); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(personFirstInitialDirectory); } _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(yearDirectory); } @@ -240,9 +222,10 @@ public class ByDeterministicHashCode _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(ticksDirectory); _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(ticksDirectory); } + return results; } - private static void SetKeyValuePairs(List<(PersonBirthday, int, int)> idThenNormalizedPixelPercentageCollection, List<(PersonBirthday, int, int)> incorrectIdThenNormalizedPixelPercentageCollection, Dictionary> idThenNormalizedPixelPercentageKeyValuePairs, Dictionary> incorrectIdThenNormalizedPixelPercentageKeyValuePairs) + private static void SetKeyValuePairs(Configuration configuration, List<(PersonBirthday, int, int)> idThenNormalizedPixelPercentageCollection, List<(PersonBirthday, int, int)> incorrectIdThenNormalizedPixelPercentageCollection, Dictionary> idThenNormalizedPixelPercentageKeyValuePairs, Dictionary> incorrectIdThenNormalizedPixelPercentageKeyValuePairs) { string check; int normalizedPixelPercentageInDecimalForm; @@ -252,7 +235,7 @@ public class ByDeterministicHashCode if (!idThenNormalizedPixelPercentageScope.ContainsKey(id)) idThenNormalizedPixelPercentageScope.Add(id, new()); check = normalizedPixelPercentage.ToString(); - if (check.Length == Shared.Models.Stateless.ILocation.Digits) + if (check.Length == configuration.LocationDigits) { if (!idThenNormalizedPixelPercentageScope[id].ContainsKey(normalizedPixelPercentage)) idThenNormalizedPixelPercentageScope[id].Add(normalizedPixelPercentage, new()); @@ -260,7 +243,7 @@ public class ByDeterministicHashCode } else { - normalizedPixelPercentageInDecimalForm = int.Parse(check.PadRight(Shared.Models.Stateless.ILocation.Digits, '0')); + normalizedPixelPercentageInDecimalForm = int.Parse(check.PadRight(configuration.LocationDigits, '0')); if (!idThenNormalizedPixelPercentageScope[id].ContainsKey(normalizedPixelPercentageInDecimalForm)) idThenNormalizedPixelPercentageScope[id].Add(normalizedPixelPercentageInDecimalForm, new()); idThenNormalizedPixelPercentageScope[id][normalizedPixelPercentageInDecimalForm].Add(personBirthday); @@ -278,7 +261,7 @@ public class ByDeterministicHashCode if (!incorrectIdThenNormalizedPixelPercentageScope.ContainsKey(id)) incorrectIdThenNormalizedPixelPercentageScope.Add(id, new()); check = normalizedPixelPercentage.ToString(); - if (check.Length == Shared.Models.Stateless.ILocation.Digits) + if (check.Length == configuration.LocationDigits) { if (!incorrectIdThenNormalizedPixelPercentageScope[id].ContainsKey(normalizedPixelPercentage)) incorrectIdThenNormalizedPixelPercentageScope[id].Add(normalizedPixelPercentage, new()); @@ -286,7 +269,7 @@ public class ByDeterministicHashCode } else { - normalizedPixelPercentageInDecimalForm = int.Parse(check.PadRight(Shared.Models.Stateless.ILocation.Digits, '0')); + normalizedPixelPercentageInDecimalForm = int.Parse(check.PadRight(configuration.LocationDigits, '0')); if (!incorrectIdThenNormalizedPixelPercentageScope[id].ContainsKey(normalizedPixelPercentageInDecimalForm)) incorrectIdThenNormalizedPixelPercentageScope[id].Add(normalizedPixelPercentageInDecimalForm, new()); incorrectIdThenNormalizedPixelPercentageScope[id][normalizedPixelPercentageInDecimalForm].Add(personBirthday); @@ -300,19 +283,151 @@ public class ByDeterministicHashCode } } - internal static void SetByRef(int maxDegreeOfParallelism, long ticks, string resizeFilenameExtension, Person[] people, List skipCollection, Dictionary peopleKeyValuePairs, List notMappedPersonKeys, Dictionary> idThenNormalizedPixelPercentageKeyValuePairs, Dictionary> incorrectIdThenNormalizedPixelPercentageKeyValuePairs, string zPropertyHolderContentDirectory, string zPropertyHolderPeopleContentDirectory) + private static string? GetCheckFile(string file, int id, int normalizedPixelPercentage) { + string? result; + string? fileName = Path.GetFileName(file); + if (fileName is null) + result = null; + else + { + string[] segments = fileName.Split('.'); + if (segments.Length != 3) + result = null; + else + { + string extensionLowered = $".{segments[2]}"; + string? directoryName = Path.GetDirectoryName(file); + if (string.IsNullOrEmpty(directoryName)) + result = null; + else + result = Path.Combine(directoryName, $"{Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(id, normalizedPixelPercentage)}{extensionLowered}.json"); + } + } + return result; + } + + private static bool Valid(string checkFile, List faces) + { + bool result = false; + string json; + foreach (Face face in faces) + { + if (face.FaceEncoding is null) + throw new NotSupportedException(); + if (faces.Count != 1) + break; + result = true; + if (File.Exists(checkFile)) + continue; + json = JsonSerializer.Serialize(face.FaceEncoding); + _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); + } + return result; + } + + private static int SetCollectionsAndGet(Configuration configuration, long ticks, Shared.Models.Methods.IFaceDistance? distance, Dictionary personKeyAliases, List<(PersonBirthday, int, int)> idThenNormalizedPixelPercentageCollection, List<(PersonBirthday, int, int)> incorrectIdThenNormalizedPixelPercentageCollection, List<(string, char, string, int?, int?, List?)> collection) + { + int result = 0; + long personKey; + string? checkFile; + List checkFaces = new(); + PersonBirthday? personBirthday; + int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + string message = $") {collection.Count:000} ticks Director(ies) - B - {totalSeconds} total second(s)"; + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + using ProgressBar progressBar = new(collection.Count, message, options); + foreach ((string personKeyFormatted, char personFirstInitial, string file, int? id, int? normalizedPixelPercentage, List? faces) in collection) + { + progressBar.Tick(); + if (id is null || normalizedPixelPercentage is null) + continue; + personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, personKeyFormatted); + if (personBirthday is null) + continue; + personKey = personBirthday.Value.Ticks; + if (personKeyAliases.ContainsKey(personKey)) + { + personKey = personKeyAliases[personKey]; + personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey); + } + if (faces is not null) + { + checkFaces.Clear(); + foreach (Face face in faces) + { + if (face.Mapping is null) + throw new NotSupportedException(); + if (normalizedPixelPercentage.Value != face.Mapping.MappingFromLocation.NormalizedPixelPercentage) + continue; + checkFaces.Add(face); + } + checkFile = GetCheckFile(file, id.Value, normalizedPixelPercentage.Value); + if (string.IsNullOrEmpty(checkFile)) + { + result++; + continue; + } + if (checkFaces.Count != 1 && distance is not null && File.Exists(checkFile)) + { + checkFaces.Clear(); + checkFaces.AddRange(distance.GetMatchingFaces(configuration.FaceDistanceTolerance, checkFile, faces)); + } + if (!checkFaces.Any()) + { + result++; + continue; + } + if (checkFaces.Count != 1) + { + result++; + continue; + } + if (!Valid(checkFile, checkFaces)) + { + result++; + continue; + } + } + if (personFirstInitial != '!') + idThenNormalizedPixelPercentageCollection.Add(new(personBirthday, id.Value, normalizedPixelPercentage.Value)); + else + incorrectIdThenNormalizedPixelPercentageCollection.Add(new(personBirthday, id.Value, normalizedPixelPercentage.Value)); + } + return result; + } + + internal static void Set(Property.Models.Configuration propertyConfiguration, Configuration? configuration, long ticks, string resizeFilenameExtension, Person[] people, string zPropertyHolderContentDirectory, string zPropertyHolderPeopleContentDirectory, List distinctFilteredFaces, Shared.Models.Methods.IFaceDistance? distance, List skipCollection, Dictionary peopleKeyValuePairs, List notMappedPersonKeys, Dictionary> idThenNormalizedPixelPercentageKeyValuePairs, Dictionary> incorrectIdThenNormalizedPixelPercentageKeyValuePairs) + { + if (configuration is null) + throw new NullReferenceException(nameof(configuration)); Dictionary personKeyAliases = new(); Dictionary> keyValuePairs = new(); List idThenNormalizedPixelPercentagePersonKeys = new(); List<(string, int?, PersonBirthday[], long)> peopleCollection = new(); List<(PersonBirthday, int, int)> idThenNormalizedPixelPercentageCollection = new(); List<(PersonBirthday, int, int)> incorrectIdThenNormalizedPixelPercentageCollection = new(); - SetOther(resizeFilenameExtension, people, zPropertyHolderPeopleContentDirectory, skipCollection, personKeyAliases, peopleCollection); - SetCollections(maxDegreeOfParallelism, ticks, zPropertyHolderContentDirectory, personKeyAliases, idThenNormalizedPixelPercentageCollection, incorrectIdThenNormalizedPixelPercentageCollection, keyValuePairs); - SetKeyValuePairs(idThenNormalizedPixelPercentageCollection, incorrectIdThenNormalizedPixelPercentageCollection, idThenNormalizedPixelPercentageKeyValuePairs, incorrectIdThenNormalizedPixelPercentageKeyValuePairs); + SetOther(propertyConfiguration, configuration, resizeFilenameExtension, people, zPropertyHolderPeopleContentDirectory, skipCollection, personKeyAliases, peopleCollection); + foreach (Face face in distinctFilteredFaces) + { + if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) + throw new NotSupportedException(); + if (face.Mapping is null) + throw new NotSupportedException(); + if (!keyValuePairs.ContainsKey(face.Mapping.MappingFromItem.Id)) + keyValuePairs.Add(face.Mapping.MappingFromItem.Id, new()); + keyValuePairs[face.Mapping.MappingFromItem.Id].Add(face); + } + List<(string, char, string, int?, int?, List?)> collection = DeleteEmptyDirectoriesAndGetCollection(configuration, ticks, zPropertyHolderContentDirectory, keyValuePairs); + int unableToMatchCount = SetCollectionsAndGet(configuration, ticks, distance, personKeyAliases, idThenNormalizedPixelPercentageCollection, incorrectIdThenNormalizedPixelPercentageCollection, collection); + SetKeyValuePairs(configuration, idThenNormalizedPixelPercentageCollection, incorrectIdThenNormalizedPixelPercentageCollection, idThenNormalizedPixelPercentageKeyValuePairs, incorrectIdThenNormalizedPixelPercentageKeyValuePairs); + int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + string message = $") {collection.Count:000} ticks Director(ies) - C - {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); foreach (KeyValuePair> keyValuePair in idThenNormalizedPixelPercentageKeyValuePairs) { + progressBar.Tick(); foreach (KeyValuePair keyValue in keyValuePair.Value) idThenNormalizedPixelPercentagePersonKeys.AddRange(from l in keyValue.Value select l.Value.Ticks); } @@ -337,7 +452,7 @@ public class ByDeterministicHashCode { int? approximateYears = null; PersonBirthday? personBirthday; - const string displayDirectoryName = Property.Models.Stateless.IResult.AllInOne; + string displayDirectoryName = propertyConfiguration.ResultAllInOne; foreach (long personKey in idThenNormalizedPixelPercentagePersonKeys) { if (!peopleKeyValuePairs.ContainsKey(personKey)) diff --git a/Metadata/Models/B_Metadata.cs b/Metadata/Models/B_Metadata.cs index 1e58783..b0d60d3 100644 --- a/Metadata/Models/B_Metadata.cs +++ b/Metadata/Models/B_Metadata.cs @@ -78,7 +78,7 @@ public class B_Metadata return results; } - public (int, List>) GetMetadataCollection(string bResultsFullGroupDirectory, List> subFileTuples, List parseExceptions, Shared.Models.Item item) + public (int, List>) GetMetadataCollection(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, List> subFileTuples, List parseExceptions, Shared.Models.Item item) { List> results = new(); if (item.Property?.Id is null) @@ -90,7 +90,7 @@ public class B_Metadata Dictionary>>? dictionary; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); string usingRelativePath = Path.Combine(AngleBracketCollection[0].Replace("<>", "{}"), string.Concat(item.ImageFileHolder.NameWithoutExtension, ".json")); - string bMetadataSingletonFile = Path.Combine(bResultsFullGroupDirectory, "{}", Property.Models.Stateless.IResult.AllInOne, $"{item.Property.Id.Value}{item.ImageFileHolder.ExtensionLowered}.json"); + string bMetadataSingletonFile = Path.Combine(bResultsFullGroupDirectory, "{}", propertyConfiguration.ResultAllInOne, $"{item.Property.Id.Value}{item.ImageFileHolder.ExtensionLowered}.json"); FileInfo fileInfo = new(bMetadataSingletonFile); if (!fileInfo.Exists) { diff --git a/Property/Models/A_Property.cs b/Property/Models/A_Property.cs index 85b7325..a422bcd 100644 --- a/Property/Models/A_Property.cs +++ b/Property/Models/A_Property.cs @@ -144,8 +144,8 @@ public class A_Property } else if (!isIgnoreExtension && isValidImageFormatExtension) { - // if (populateId && (id is null || !indices.Any()) && !_IndicesFromNew.Any() && !_KeyValuePairs.Any()) - // throw new Exception("In order to keep six character indices at least one need to have an item!"); + if (populateId && (id is null || !indices.Any()) && !_IndicesFromNew.Any() && !_KeyValuePairs.Any()) + throw new Exception("May need to move mapLogic constructor! In order to keep six character indices at least one need to have an item!"); try { using Image image = Image.FromFile(filteredSourceDirectoryFileHolder.FullName); @@ -641,7 +641,7 @@ public class A_Property continue; SetAngleBracketCollection(container.SourceDirectory); totalSeconds = (int)Math.Truncate(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); - message = $"{i:000}.{container.G} / {containersCount:000}) {filteredItems.Length:000} file(s) - {totalSeconds} total second(s) - {container.SourceDirectory}"; + message = $"{i + 1:000}.{container.G} / {containersCount:000}) {filteredItems.Length:000} file(s) - {totalSeconds} total second(s) - {container.SourceDirectory}"; ParallelWork(firstPass, exceptions, sourceDirectoryChanges, container, filteredItems, message); foreach (Exception exception in exceptions) _Log.Error(string.Concat(container.SourceDirectory, Environment.NewLine, exception.Message, Environment.NewLine, exception.StackTrace), exception); diff --git a/Property/Models/Binder/Configuration.cs b/Property/Models/Binder/Configuration.cs index c03bf92..bf9a356 100644 --- a/Property/Models/Binder/Configuration.cs +++ b/Property/Models/Binder/Configuration.cs @@ -19,6 +19,10 @@ public class Configuration [Display(Name = "Populate Properties Id"), Required] public bool? PopulatePropertyId { get; set; } [Display(Name = "Properties Changed For Property"), Required] public bool? PropertiesChangedForProperty { get; set; } [Display(Name = "Property Content Collection Files"), Required] public string[] PropertyContentCollectionFiles { get; set; } + [Display(Name = "Result All In One"), Required] public string ResultAllInOne { get; set; } + [Display(Name = "Result Collection"), Required] public string ResultCollection { get; set; } + [Display(Name = "Result Content"), Required] public string ResultContent { get; set; } + [Display(Name = "Result Singleton"), Required] public string ResultSingleton { get; set; } [Display(Name = "Root Directory"), Required] public string RootDirectory { get; set; } [Display(Name = "Valid Image Format Extensions"), Required] public string[] ValidImageFormatExtensions { get; set; } [Display(Name = "Valid Metadata Extensions"), Required] public string[] ValidMetadataExtensions { get; set; } @@ -44,6 +48,14 @@ public class Configuration throw new NullReferenceException(nameof(configuration.PopulatePropertyId)); if (configuration.PropertiesChangedForProperty is null) throw new NullReferenceException(nameof(configuration.PropertiesChangedForProperty)); + if (configuration.ResultAllInOne is null) + throw new NullReferenceException(nameof(configuration.ResultAllInOne)); + if (configuration.ResultCollection is null) + throw new NullReferenceException(nameof(configuration.ResultCollection)); + if (configuration.ResultContent is null) + throw new NullReferenceException(nameof(configuration.ResultContent)); + if (configuration.ResultSingleton is null) + throw new NullReferenceException(nameof(configuration.ResultSingleton)); if (configuration.WriteBitmapDataBytes is null) throw new NullReferenceException(nameof(configuration.WriteBitmapDataBytes)); if (configuration.IgnoreExtensions is null) @@ -65,6 +77,10 @@ public class Configuration configuration.PopulatePropertyId.Value, configuration.PropertiesChangedForProperty.Value, configuration.PropertyContentCollectionFiles, + configuration.ResultAllInOne, + configuration.ResultCollection, + configuration.ResultContent, + configuration.ResultSingleton, configuration.RootDirectory, configuration.ValidImageFormatExtensions, configuration.ValidMetadataExtensions, diff --git a/Property/Models/Configuration.cs b/Property/Models/Configuration.cs index 94f8f08..58ae958 100644 --- a/Property/Models/Configuration.cs +++ b/Property/Models/Configuration.cs @@ -18,13 +18,34 @@ public class Configuration public bool PopulatePropertyId { init; get; } public bool PropertiesChangedForProperty { init; get; } public string[] PropertyContentCollectionFiles { init; get; } + public string ResultAllInOne { init; get; } + public string ResultCollection { init; get; } + public string ResultContent { init; get; } + public string ResultSingleton { init; get; } public string[] ValidImageFormatExtensions { init; get; } public string[] ValidMetadataExtensions { init; get; } public string[] VerifyToSeason { init; get; } public bool WriteBitmapDataBytes { init; get; } [JsonConstructor] - public Configuration(string dateGroup, string fileNameDirectorySeparator, bool forcePropertyLastWriteTimeToCreationTime, string[] ignoreExtensions, int maxImagesInDirectoryForTopLevelFirstPass, string pattern, bool populatePropertyId, bool propertiesChangedForProperty, string[] propertyContentCollectionFiles, string rootDirectory, string[] validImageFormatExtensions, string[] validMetadataExtensions, string[] verifyToSeason, bool writeBitmapDataBytes) + public Configuration(string dateGroup, + string fileNameDirectorySeparator, + bool forcePropertyLastWriteTimeToCreationTime, + string[] ignoreExtensions, + int maxImagesInDirectoryForTopLevelFirstPass, + string pattern, + bool populatePropertyId, + bool propertiesChangedForProperty, + string[] propertyContentCollectionFiles, + string resultAllInOne, + string resultCollection, + string resultContent, + string resultSingleton, + string rootDirectory, + string[] validImageFormatExtensions, + string[] validMetadataExtensions, + string[] verifyToSeason, + bool writeBitmapDataBytes) { DateGroup = dateGroup; FileNameDirectorySeparator = fileNameDirectorySeparator; @@ -35,6 +56,10 @@ public class Configuration PopulatePropertyId = populatePropertyId; PropertiesChangedForProperty = propertiesChangedForProperty; PropertyContentCollectionFiles = propertyContentCollectionFiles; + ResultAllInOne = resultAllInOne; + ResultCollection = resultCollection; + ResultContent = resultContent; + ResultSingleton = resultSingleton; _RootDirectory = rootDirectory; ValidImageFormatExtensions = validImageFormatExtensions; ValidMetadataExtensions = validMetadataExtensions; diff --git a/Property/Models/Stateless/Container.cs b/Property/Models/Stateless/Container.cs index b993fca..8c1716a 100644 --- a/Property/Models/Stateless/Container.cs +++ b/Property/Models/Stateless/Container.cs @@ -15,7 +15,7 @@ public class Container string[] sourceDirectoryFiles; List fileCollections = new(); if (!topDirectories.Any()) - topDirectories.AddRange(from l in Directory.GetDirectories(rootDirectory, "*", SearchOption.TopDirectoryOnly) orderby Path.GetFileName(l)[..1], l select Path.GetFullPath(l)); + topDirectories.AddRange(from l in Directory.GetDirectories(rootDirectory, "*", SearchOption.TopDirectoryOnly) select Path.GetFullPath(l)); for (int g = 1; g < 5; g++) { if (g == 4) @@ -31,7 +31,6 @@ public class Container } else if (g == 2) { - fileCollections = (from l in fileCollections orderby l.Length descending select l).ToList(); for (int i = fileCollections.Count - 1; i > -1; i--) { if (fileCollections[i].Length > maxImagesInDirectoryForTopLevelFirstPass * g) diff --git a/Property/Models/Stateless/IResult.cs b/Property/Models/Stateless/IResult.cs index ba13791..1353f6a 100644 --- a/Property/Models/Stateless/IResult.cs +++ b/Property/Models/Stateless/IResult.cs @@ -5,11 +5,6 @@ namespace View_by_Distance.Property.Models.Stateless; public interface IResult { - const string Content = "()"; - const string Singleton = "{}"; - const string Collection = "[]"; - const string AllInOne = "_ _ _"; - string TestStatic_GetRelativePath(Configuration configuration, string path); static string GetRelativePath(Configuration configuration, string path) => Result.GetRelativePath(configuration, path); diff --git a/Property/Models/Stateless/Result.cs b/Property/Models/Stateless/Result.cs index b4c617d..b12cee1 100644 --- a/Property/Models/Stateless/Result.cs +++ b/Property/Models/Stateless/Result.cs @@ -64,13 +64,13 @@ internal class Result return result; } - private static void CheckContent(string dateGroupDirectory, string contentDescription, string result) + private static void CheckContent(Configuration configuration, string dateGroupDirectory, string contentDescription, string result) { string checkDirectory; - checkDirectory = Path.Combine(dateGroupDirectory, IResult.Content, IResult.AllInOne); + checkDirectory = Path.Combine(dateGroupDirectory, configuration.ResultContent, configuration.ResultAllInOne); if (!Directory.Exists(checkDirectory)) _ = Directory.CreateDirectory(checkDirectory); - string contentDirectory = new(result.Replace("<>", IResult.Content)); + string contentDirectory = new(result.Replace("<>", configuration.ResultContent)); if (!Directory.Exists(contentDirectory)) _ = Directory.CreateDirectory(contentDirectory); checkDirectory = Path.Combine(dateGroupDirectory, string.Concat("() - ", contentDescription)); @@ -78,15 +78,15 @@ internal class Result _ = Directory.CreateDirectory(checkDirectory); } - private static void CheckSingleton(string dateGroupDirectory, string singletonDescription, bool converted, string result) + private static void CheckSingleton(Configuration configuration, string dateGroupDirectory, string singletonDescription, bool converted, string result) { string checkDirectory; - checkDirectory = Path.Combine(dateGroupDirectory, IResult.Singleton, IResult.AllInOne); + checkDirectory = Path.Combine(dateGroupDirectory, configuration.ResultSingleton, configuration.ResultAllInOne); if (!Directory.Exists(checkDirectory)) _ = Directory.CreateDirectory(checkDirectory); if (!converted) { - string singletonDirectory = new(result.Replace("<>", IResult.Singleton)); + string singletonDirectory = new(result.Replace("<>", configuration.ResultSingleton)); if (!Directory.Exists(singletonDirectory)) _ = Directory.CreateDirectory(singletonDirectory); } @@ -95,14 +95,14 @@ internal class Result _ = Directory.CreateDirectory(checkDirectory); } - private static void CheckCollection(string dateGroupDirectory, string collectionDescription, bool converted, string result) + private static void CheckCollection(Configuration configuration, string dateGroupDirectory, string collectionDescription, bool converted, string result) { - string checkDirectory = Path.Combine(dateGroupDirectory, IResult.Collection, IResult.AllInOne); + string checkDirectory = Path.Combine(dateGroupDirectory, configuration.ResultCollection, configuration.ResultAllInOne); if (!Directory.Exists(checkDirectory)) _ = Directory.CreateDirectory(checkDirectory); if (!converted) { - string collectionDirectory = new(result.Replace("<>", IResult.Collection)); + string collectionDirectory = new(result.Replace("<>", configuration.ResultCollection)); if (!Directory.Exists(collectionDirectory)) _ = Directory.CreateDirectory(collectionDirectory); } @@ -117,11 +117,11 @@ internal class Result string sourceDirectorySegment = GetRelativePath(configuration, sourceDirectory); string result = string.Concat(Path.Combine(dateGroupDirectory, "<>"), sourceDirectorySegment); if (!string.IsNullOrEmpty(contentDescription)) - CheckContent(dateGroupDirectory, contentDescription, result); + CheckContent(configuration, dateGroupDirectory, contentDescription, result); if (!string.IsNullOrEmpty(singletonDescription)) - CheckSingleton(dateGroupDirectory, singletonDescription, converted, result); + CheckSingleton(configuration, dateGroupDirectory, singletonDescription, converted, result); if (!string.IsNullOrEmpty(collectionDescription)) - CheckCollection(dateGroupDirectory, collectionDescription, converted, result); + CheckCollection(configuration, dateGroupDirectory, collectionDescription, converted, result); results.Add(result); return results; } diff --git a/Resize/Models/_C_Resize.cs b/Resize/Models/_C_Resize.cs index 84842a8..435b79f 100644 --- a/Resize/Models/_C_Resize.cs +++ b/Resize/Models/_C_Resize.cs @@ -451,7 +451,7 @@ public class C_Resize return results; } - public Dictionary GetResizeKeyValuePairs(string cResultsFullGroupDirectory, List> subFileTuples, List parseExceptions, string original, List> metadataCollection, Shared.Models.Item item) + public Dictionary GetResizeKeyValuePairs(Property.Models.Configuration configuration, string cResultsFullGroupDirectory, List> subFileTuples, List parseExceptions, string original, List> metadataCollection, Shared.Models.Item item) { Dictionary results; if (item.Property?.Id is null) @@ -462,7 +462,7 @@ public class C_Resize string[] changesFrom = new string[] { nameof(Property.Models.A_Property), nameof(B_Metadata) }; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); string usingRelativePath = Path.Combine(AngleBracketCollection[0].Replace("<>", "{}"), string.Concat(item.ImageFileHolder.NameWithoutExtension, ".json")); - string cResizeSingletonFile = Path.Combine(cResultsFullGroupDirectory, "{}", Property.Models.Stateless.IResult.AllInOne, $"{item.Property.Id.Value}{item.ImageFileHolder.ExtensionLowered}.json"); + string cResizeSingletonFile = Path.Combine(cResultsFullGroupDirectory, "{}", configuration.ResultAllInOne, $"{item.Property.Id.Value}{item.ImageFileHolder.ExtensionLowered}.json"); FileInfo fileInfo = new(cResizeSingletonFile); if (!fileInfo.Exists) { diff --git a/Shared/Models/Mapping.cs b/Shared/Models/Mapping.cs index 77cbf26..ca07bb5 100644 --- a/Shared/Models/Mapping.cs +++ b/Shared/Models/Mapping.cs @@ -34,14 +34,14 @@ public class MappingFromLocation : Properties.IMappingFromLocation { public double Confidence { init; get; } - public string DeterministicHashCodeKeyDisplay { init; get; } + public string DeterministicHashCodeKey { init; get; } public int NormalizedPixelPercentage { init; get; } [JsonConstructor] public MappingFromLocation(double confidence, string deterministicHashCodeKeyDisplay, int normalizedPixelPercentage) { Confidence = confidence; - DeterministicHashCodeKeyDisplay = deterministicHashCodeKeyDisplay; + DeterministicHashCodeKey = deterministicHashCodeKeyDisplay; NormalizedPixelPercentage = normalizedPixelPercentage; } diff --git a/Shared/Models/Methods/IFaceDistance.cs b/Shared/Models/Methods/IFaceDistance.cs new file mode 100644 index 0000000..f9fea77 --- /dev/null +++ b/Shared/Models/Methods/IFaceDistance.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IFaceDistance +{ + + List GetMatchingFaces(double faceDistanceTolerance, string checkFile, List faces); + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IMapping.cs b/Shared/Models/Properties/IMapping.cs index 85a0a31..f426569 100644 --- a/Shared/Models/Properties/IMapping.cs +++ b/Shared/Models/Properties/IMapping.cs @@ -15,7 +15,7 @@ public interface IMappingFromLocation { public double Confidence { init; get; } - public string DeterministicHashCodeKeyDisplay { init; get; } + public string DeterministicHashCodeKey { init; get; } public int NormalizedPixelPercentage { init; get; } } diff --git a/Shared/Models/Stateless/IFaceDistance.cs b/Shared/Models/Stateless/IFaceDistance.cs deleted file mode 100644 index bb75419..0000000 --- a/Shared/Models/Stateless/IFaceDistance.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace View_by_Distance.Shared.Models.Stateless; - -public interface IFaceDistance -{ - - const int HiddenImageFactor = 2; - const int Permyriad = 10000; - const double MinimumConfidence = 1.25d; - const double Tolerance = 0.23d; - - // (637987888254767613) Tolerance = 0.31d; MinimumConfidence = 0.80d; => 1003 in 20 minutes with 9 failures - // (637987913910140924) Tolerance = 0.21d; MinimumConfidence = 0.95d; => 0254 in 04 minutes with 1 failures - // (??????????????????) Tolerance = 0.23d; MinimumConfidence = 1.25d; => ____ in __ minutes with _ failures - -} \ No newline at end of file diff --git a/Shared/Models/Stateless/IMapping.cs b/Shared/Models/Stateless/IMapping.cs deleted file mode 100644 index 4f84cef..0000000 --- a/Shared/Models/Stateless/IMapping.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace View_by_Distance.Shared.Models.Stateless; - -public interface IMapping -{ - - const bool SaveFaceEncoding = false; - const bool SaveMapped = false; - -} \ No newline at end of file diff --git a/Shared/Models/Stateless/IPerson.cs b/Shared/Models/Stateless/IPerson.cs deleted file mode 100644 index 629759c..0000000 --- a/Shared/Models/Stateless/IPerson.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace View_by_Distance.Shared.Models.Stateless; - -public interface IPerson -{ - const string KeyFormat = "yyyy-MM-dd_HH"; - -} \ No newline at end of file diff --git a/Shared/Models/Stateless/IPersonBirthday.cs b/Shared/Models/Stateless/IPersonBirthday.cs deleted file mode 100644 index 4a6da5a..0000000 --- a/Shared/Models/Stateless/IPersonBirthday.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace View_by_Distance.Shared.Models.Stateless; - -public interface IPersonBirthday -{ - - const int FirstYear = 1500; - const string Format = "yyyy-MM-dd_HH"; - -} \ No newline at end of file diff --git a/Shared/Models/Stateless/ISorting.cs b/Shared/Models/Stateless/ISorting.cs deleted file mode 100644 index ad7ba8f..0000000 --- a/Shared/Models/Stateless/ISorting.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace View_by_Distance.Shared.Models.Stateless; - -public interface ISorting -{ - - const int DaysDeltaTolerance = 700; - const int FacesToSkipAfterSortBeforeLoad = 0; - const int FacesToTakeAfterSortBeforeLoad = 123000; - const int ForceSingleImage = 3; - const int Mapping = 1; - const int MaximumPerFaceShouldBeHigh = 1000; - const int MaximumPerKey = 27; - const int Sigma = 3; - const int Sorting = 2; - -} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/ILocation.cs b/Shared/Models/Stateless/Methods/ILocation.cs index b6ffc54..0c562e6 100644 --- a/Shared/Models/Stateless/Methods/ILocation.cs +++ b/Shared/Models/Stateless/Methods/ILocation.cs @@ -23,4 +23,18 @@ public interface ILocation static int GetNormalizedPixelPercentage(int bottom, int height, int left, int locationDigits, int locationFactor, int right, int top, int width, int zCount) => Location.GetNormalizedPixelPercentage(bottom, height, left, locationDigits, locationFactor, right, top, width, zCount); + Models.Location TestStatic_GetTrimBound(double detectionConfidence, System.Drawing.Rectangle rectangle, int width, int height, int facesCount) => + TrimBound(detectionConfidence, rectangle, width, height, facesCount); + static Models.Location TrimBound(double detectionConfidence, System.Drawing.Rectangle rectangle, int width, int height, int facesCount) => + new(Math.Min(rectangle.Bottom, height), + detectionConfidence, + height, + Math.Max(rectangle.Left, 0), + Stateless.ILocation.Digits, + Stateless.ILocation.Factor, + Math.Min(rectangle.Right, width), + Math.Max(rectangle.Top, 0), + width, + facesCount); + } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IMapping.cs b/Shared/Models/Stateless/Methods/IMapping.cs index 820e119..1be1317 100644 --- a/Shared/Models/Stateless/Methods/IMapping.cs +++ b/Shared/Models/Stateless/Methods/IMapping.cs @@ -3,15 +3,12 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods; public interface IMapping { // ... - static string GetDeterministicHashCodeKeyDisplay(int id, int normalizedPixelPercentage) + static string GetDeterministicHashCodeKey(int id, int normalizedPixelPercentage) => $"{id}.{normalizedPixelPercentage}"; - static double GetDeterministicHashCodeKeyValue(int locationDigits, int id, int normalizedPixelPercentage) - => Math.Round(double.Parse($"{id}.{normalizedPixelPercentage}"), locationDigits); - - (int?, int?) TestStatic_GetReversedDeterministicHashCodeKey(int locationDigits, bool keyValuePairsAny, Dictionary> keyValuePairs, string file) => + (int?, int?, List?) TestStatic_GetReversedDeterministicHashCodeKey(int locationDigits, bool keyValuePairsAny, Dictionary> keyValuePairs, string file) => GetReversedDeterministicHashCodeKey(locationDigits, keyValuePairsAny, keyValuePairs, file); - static (int?, int?) GetReversedDeterministicHashCodeKey(int locationDigits, bool keyValuePairsAny, Dictionary> keyValuePairs, string file) => + static (int?, int?, List?) GetReversedDeterministicHashCodeKey(int locationDigits, bool keyValuePairsAny, Dictionary> keyValuePairs, string file) => Mapping.GetReversedDeterministicHashCodeKey(locationDigits, keyValuePairsAny, keyValuePairs, file); } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/Mapping.cs b/Shared/Models/Stateless/Methods/Mapping.cs index 3404ab2..32a7e0e 100644 --- a/Shared/Models/Stateless/Methods/Mapping.cs +++ b/Shared/Models/Stateless/Methods/Mapping.cs @@ -1,80 +1,68 @@ -using System.Text.Json; - namespace View_by_Distance.Shared.Models.Stateless.Methods; internal abstract class Mapping { - private static void UseKeyValuePairsSaveFaceEncoding(int locationDigits, Dictionary> keyValuePairs, string file, int id, int normalizedPixelPercentageValue, double deterministicHashCodeKey, string extensionLowered) + private static void IfNotAlreadyFileMove(string file, int idValue, int normalizedPixelPercentageValue, string extensionLowered) { - string json; - string checkFile; - string? directoryName; - List collection = new(); - List faces = keyValuePairs[id]; - foreach (Models.Face face in faces) - { - if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) - continue; - if (normalizedPixelPercentageValue != face.Location.NormalizedPixelPercentage.Value && deterministicHashCodeKey != IMapping.GetDeterministicHashCodeKeyValue(locationDigits, id, face.Location.NormalizedPixelPercentage.Value)) - continue; - collection.Add(face); - } - if (collection.Count != 1) + string? directoryName = Path.GetDirectoryName(file); + if (string.IsNullOrEmpty(directoryName)) throw new Exception(); - foreach (Models.Face face in collection) - { - directoryName = Path.GetDirectoryName(file); - if (string.IsNullOrEmpty(directoryName)) - continue; - checkFile = Path.Combine(directoryName, $"{deterministicHashCodeKey}{extensionLowered}.json"); - if (File.Exists(checkFile)) - continue; - json = JsonSerializer.Serialize(face.FaceEncoding); - _ = IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); - } + string checkFile = Path.Combine(directoryName, $"{IMapping.GetDeterministicHashCodeKey(idValue, normalizedPixelPercentageValue)}{extensionLowered}"); + if (!File.Exists(checkFile)) + File.Move(file, checkFile); } - private static (int?, int?, double?) GetReversedDeterministicHashCodeKeysFromSegments(int locationDigits, bool keyValuePairsAny, Dictionary> keyValuePairs, string file, string[] segments) - { - double? result; - if (segments.Length != 3) - throw new Exception(); - string id = segments[0]; - int normalizedPixelPercentageValue; - string normalizedPixelPercentage = segments[1]; - if (!int.TryParse(id, out int idValue) | !int.TryParse(normalizedPixelPercentage, out normalizedPixelPercentageValue)) - result = null; - else - { - result = IMapping.GetDeterministicHashCodeKeyValue(locationDigits, idValue, normalizedPixelPercentageValue); - if (keyValuePairsAny && keyValuePairs.ContainsKey(idValue)) - UseKeyValuePairsSaveFaceEncoding(locationDigits, keyValuePairs, file, idValue, normalizedPixelPercentageValue, result.Value, $".{segments[2]}"); - } - return new(idValue, normalizedPixelPercentageValue, result); - } - - internal static (int?, int?) GetReversedDeterministicHashCodeKey(int locationDigits, bool keyValuePairsAny, Dictionary> keyValuePairs, string file) + private static (int?, int?, List?) GetReversedDeterministicHashCodeKeysFromSegments(int locationDigits, bool keyValuePairsAny, Dictionary> keyValuePairs, string file, string[] segments) { int? id; + List? faces; + int? normalizedPixelPercentage; + if (segments.Length != 3) + { + id = null; + faces = null; + normalizedPixelPercentage = null; + } + else if (!int.TryParse(segments[0], out int idValue) || !int.TryParse(segments[1].PadRight(locationDigits, '0'), out int normalizedPixelPercentageValue)) + { + id = null; + faces = null; + normalizedPixelPercentage = null; + } + else + { + id = idValue; + string extensionLowered = $".{segments[2]}"; + normalizedPixelPercentage = normalizedPixelPercentageValue; + if (segments[1].Length != locationDigits) + IfNotAlreadyFileMove(file, idValue, normalizedPixelPercentageValue, extensionLowered); + if (!keyValuePairsAny || !keyValuePairs.ContainsKey(idValue)) + faces = null; + else + faces = keyValuePairs[idValue]; + } + return new(id, normalizedPixelPercentage, faces); + } + + internal static (int?, int?, List?) GetReversedDeterministicHashCodeKey(int locationDigits, bool keyValuePairsAny, Dictionary> keyValuePairs, string file) + { + int? id; + List? faces; int? normalizedPixelPercentage; string fileName = Path.GetFileName(file); if (fileName.Length < 2 || fileName[1..].Contains('-')) { id = null; + faces = null; normalizedPixelPercentage = null; } else { string[] segments = fileName.Split('.'); - (id, normalizedPixelPercentage, double? result) = GetReversedDeterministicHashCodeKeysFromSegments(locationDigits, keyValuePairsAny, keyValuePairs, file, segments); - if (result is null) - { - id = null; - normalizedPixelPercentage = null; - } + (id, normalizedPixelPercentage, faces) = GetReversedDeterministicHashCodeKeysFromSegments(locationDigits, keyValuePairsAny, keyValuePairs, file, segments); } - return new(id, normalizedPixelPercentage); + return new(id, normalizedPixelPercentage, faces); } } \ No newline at end of file diff --git a/Tests/UnitTestCalculations.cs b/Tests/UnitTestCalculations.cs index c6b119e..9f2ed03 100644 --- a/Tests/UnitTestCalculations.cs +++ b/Tests/UnitTestCalculations.cs @@ -94,25 +94,4 @@ public class UnitTestCalculations Assert.IsTrue(checkB > checkA); } - [TestMethod] - public void TestMethodRoundB() - { - const int DistanceDigits = 3; - const int DistanceFactor = 1000; - const int ToleranceAfterFactor = 600; - Assert.IsTrue(DistanceDigits == 3); - Assert.IsTrue(DistanceFactor == 1000); - Assert.IsTrue(Shared.Models.Stateless.IFaceDistance.Tolerance == 0.6d); - Assert.IsTrue(ToleranceAfterFactor == 600); - double valueA = 0.00001d; - int checkA = (int)(Math.Round(valueA, Shared.Models.Stateless.ILocation.Digits) * Shared.Models.Stateless.ILocation.Factor); - Assert.IsTrue(checkA == 10); - double valueB = 0.01d; - int checkB = (int)(Math.Round(valueB, Shared.Models.Stateless.ILocation.Digits) * Shared.Models.Stateless.ILocation.Factor); - Assert.IsTrue(checkB == 10000); - Assert.IsTrue(checkB > checkA); - int checkC = (int)(Shared.Models.Stateless.IFaceDistance.Tolerance * DistanceFactor); - Assert.IsTrue(checkC == ToleranceAfterFactor); - } - } \ No newline at end of file diff --git a/Tests/UnitTestResize.cs b/Tests/UnitTestResize.cs index e807aa9..8a7d9b9 100644 --- a/Tests/UnitTestResize.cs +++ b/Tests/UnitTestResize.cs @@ -242,8 +242,8 @@ public class UnitTestResize property = propertyLogic.GetProperty(item, subFileTuples, parseExceptions); item.Update(property); } - (int _, metadataCollection) = metadata.GetMetadataCollection(bResultsFullGroupDirectory, subFileTuples, parseExceptions, item); - imageResizeKeyValuePairs = resize.GetResizeKeyValuePairs(cResultsFullGroupDirectory, subFileTuples, parseExceptions, original, metadataCollection, item); + (int _, metadataCollection) = metadata.GetMetadataCollection(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, subFileTuples, parseExceptions, item); + imageResizeKeyValuePairs = resize.GetResizeKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, subFileTuples, parseExceptions, original, metadataCollection, item); Assert.IsNotNull(item.ResizedFileHolder); resize.SaveResizedSubfile(outputResolution, cResultsFullGroupDirectory, subFileTuples, item, original, imageResizeKeyValuePairs); } diff --git a/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs b/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs index f3bffeb..3ddaab9 100644 --- a/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs +++ b/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs @@ -13,6 +13,10 @@ 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 = "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; } + [Display(Name = "Face Distance Tolerance"), Required] public double? FaceDistanceTolerance { get; set; } [Display(Name = "Force Face Last Write Time to Creation Time"), Required] public bool? ForceFaceLastWriteTimeToCreationTime { get; set; } [Display(Name = "Force Metadata Last Write Time to Creation Time"), Required] public bool? ForceMetadataLastWriteTimeToCreationTime { get; set; } [Display(Name = "Force Resize Last Write Time to Creation Time"), Required] public bool? ForceResizeLastWriteTimeToCreationTime { get; set; } @@ -23,7 +27,14 @@ public class Configuration [Display(Name = "Load Or Create Then Save Image Faces Results"), Required] public string[] LoadOrCreateThenSaveImageFacesResultsForOutputResolutions { get; set; } [Display(Name = "Load Or Create Then Save Index"), Required] public bool? LoadOrCreateThenSaveIndex { get; set; } [Display(Name = "Location Confidence Factor"), Required] public int? LocationConfidenceFactor { get; set; } + [Display(Name = "Location Digits"), Required] public int? LocationDigits { get; set; } + [Display(Name = "Location Factor"), Required] public int? LocationFactor { get; set; } + [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 Save Face Encoding"), Required] public bool? MappingSaveFaceEncoding { get; set; } + [Display(Name = "MappingSaveMapped"), Required] public bool? MappingSaveMapped { get; set; } + [Display(Name = "Mapping Use Deterministic Hash Code Unknown Face Key Value Pairs for Add to Mapping"), Required] public bool? MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping { get; set; } + [Display(Name = "Mapping Use Deterministic Hash Code Unknown Face Key Value Pairs for Save Mapping"), Required] public bool? MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping { get; set; } [Display(Name = "Max Items In Distance Collection"), Required] public int? MaxItemsInDistanceCollection { get; set; } [Display(Name = "Mixed Year Relative Paths"), Required] public string[] MixedYearRelativePaths { get; set; } [Display(Name = "Model Directory"), Required] public string ModelDirectory { get; set; } @@ -37,6 +48,9 @@ public class Configuration [Display(Name = "Override For Face Landmark Images"), Required] public bool? OverrideForFaceLandmarkImages { get; set; } [Display(Name = "Override For Resize Images"), Required] public bool? OverrideForResizeImages { get; set; } [Display(Name = "Padding Loops"), Required] public int? PaddingLoops { get; set; } + [Display(Name = "Person Birthday First Year"), Required] public int? PersonBirthdayFirstYear { get; set; } + [Display(Name = "Person Birthday Format"), Required] public string PersonBirthdayFormat { get; set; } + [Display(Name = "PersonKey Format"), Required] public string PersonKeyFormat { get; set; } [Display(Name = "Predictor Model Name"), Required] public string PredictorModelName { get; set; } [Display(Name = "Properties Changed For Distance"), Required] public bool? PropertiesChangedForDistance { get; set; } [Display(Name = "Properties Changed For Faces"), Required] public bool? PropertiesChangedForFaces { get; set; } @@ -50,6 +64,12 @@ 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 = "Skip Search"), Required] public bool? SkipSearch { get; set; } + [Display(Name = "Sorting Days Delta Tolerance"), Required] public int? SortingDaysDeltaTolerance { get; set; } + [Display(Name = "Sorting Faces To Skip After Sort Before Load"), Required] public int? SortingFacesToSkipAfterSortBeforeLoad { get; set; } + [Display(Name = "Sorting Faces To Take After Sort Before Load"), Required] public int? SortingFacesToTakeAfterSortBeforeLoad { 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 Sigma"), Required] public int? SortingSigma { get; set; } [Display(Name = "Test Distance Results"), Required] public bool? TestDistanceResults { get; set; } [Display(Name = "Valid Resolutions"), Required] public string[] ValidResolutions { get; set; } @@ -70,6 +90,14 @@ public class Configuration throw new NullReferenceException(nameof(configuration.CrossDirectoryMaxItemsInDistanceCollection)); if (configuration.DistanceFactor is null) throw new NullReferenceException(nameof(configuration.DistanceFactor)); + if (configuration.FaceDistanceHiddenImageFactor is null) + throw new NullReferenceException(nameof(configuration.FaceDistanceHiddenImageFactor)); + if (configuration.FaceDistanceMinimumConfidence is null) + throw new NullReferenceException(nameof(configuration.FaceDistanceMinimumConfidence)); + if (configuration.FaceDistancePermyriad is null) + throw new NullReferenceException(nameof(configuration.FaceDistancePermyriad)); + if (configuration.FaceDistanceTolerance is null) + throw new NullReferenceException(nameof(configuration.FaceDistanceTolerance)); if (configuration.ForceFaceLastWriteTimeToCreationTime is null) throw new NullReferenceException(nameof(configuration.ForceFaceLastWriteTimeToCreationTime)); if (configuration.ForceMetadataLastWriteTimeToCreationTime is null) @@ -80,10 +108,28 @@ public class Configuration throw new NullReferenceException(nameof(configuration.IgnoreExtensions)); if (configuration.IgnoreRelativePaths is null) throw new NullReferenceException(nameof(configuration.IgnoreRelativePaths)); + if (configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions is null) + configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions = Array.Empty(); + if (configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions is null) + configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = Array.Empty(); if (configuration.LoadOrCreateThenSaveIndex is null) throw new NullReferenceException(nameof(configuration.LoadOrCreateThenSaveIndex)); if (configuration.LocationConfidenceFactor is null) throw new NullReferenceException(nameof(configuration.LocationConfidenceFactor)); + if (configuration.LocationDigits is null) + throw new NullReferenceException(nameof(configuration.LocationDigits)); + if (configuration.LocationFactor is null) + throw new NullReferenceException(nameof(configuration.LocationFactor)); + if (configuration.MapLogicSigma is null) + throw new NullReferenceException(nameof(configuration.MapLogicSigma)); + if (configuration.MappingSaveFaceEncoding is null) + throw new NullReferenceException(nameof(configuration.MappingSaveFaceEncoding)); + if (configuration.MappingSaveMapped is null) + throw new NullReferenceException(nameof(configuration.MappingSaveMapped)); + if (configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping is null) + throw new NullReferenceException(nameof(configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping)); + if (configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping is null) + throw new NullReferenceException(nameof(configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping)); if (configuration.MaxItemsInDistanceCollection is null) throw new NullReferenceException(nameof(configuration.MaxItemsInDistanceCollection)); if (configuration.MixedYearRelativePaths is null) @@ -104,6 +150,12 @@ public class Configuration throw new NullReferenceException(nameof(configuration.OverrideForResizeImages)); if (configuration.PaddingLoops is null) throw new NullReferenceException(nameof(configuration.PaddingLoops)); + if (configuration.PersonBirthdayFirstYear is null) + throw new NullReferenceException(nameof(configuration.PersonBirthdayFirstYear)); + if (configuration.PersonBirthdayFormat is null) + throw new NullReferenceException(nameof(configuration.PersonBirthdayFormat)); + if (configuration.PersonKeyFormat is null) + throw new NullReferenceException(nameof(configuration.PersonKeyFormat)); if (configuration.PropertiesChangedForDistance is null) throw new NullReferenceException(nameof(configuration.PropertiesChangedForDistance)); if (configuration.PropertiesChangedForFaces is null) @@ -116,14 +168,30 @@ public class Configuration throw new NullReferenceException(nameof(configuration.PropertiesChangedForResize)); if (configuration.Reverse is null) throw new NullReferenceException(nameof(configuration.Reverse)); + if (configuration.SaveFaceLandmarkForOutputResolutions is null) + configuration.SaveFaceLandmarkForOutputResolutions = Array.Empty(); if (configuration.SaveFaceLandmarkForOutputResolutions is null) throw new NullReferenceException(nameof(configuration.SaveFaceLandmarkForOutputResolutions)); if (configuration.SaveFullYearOfRandomFiles is null) throw new NullReferenceException(nameof(configuration.SaveFullYearOfRandomFiles)); if (configuration.SaveResizedSubfiles is null) throw new NullReferenceException(nameof(configuration.SaveResizedSubfiles)); + if (configuration.SaveShortcutsForOutputResolutions is null) + configuration.SaveShortcutsForOutputResolutions = Array.Empty(); if (configuration.SkipSearch is null) throw new NullReferenceException(nameof(configuration.SkipSearch)); + if (configuration.SortingDaysDeltaTolerance is null) + throw new NullReferenceException(nameof(configuration.SortingDaysDeltaTolerance)); + if (configuration.SortingFacesToSkipAfterSortBeforeLoad is null) + throw new NullReferenceException(nameof(configuration.SortingFacesToSkipAfterSortBeforeLoad)); + if (configuration.SortingFacesToTakeAfterSortBeforeLoad is null) + throw new NullReferenceException(nameof(configuration.SortingFacesToTakeAfterSortBeforeLoad)); + if (configuration.SortingMaximumPerFaceShouldBeHigh is null) + throw new NullReferenceException(nameof(configuration.SortingMaximumPerFaceShouldBeHigh)); + if (configuration.SortingMaximumPerKey is null) + throw new NullReferenceException(nameof(configuration.SortingMaximumPerKey)); + if (configuration.SortingSigma is null) + throw new NullReferenceException(nameof(configuration.SortingSigma)); if (configuration.TestDistanceResults is null) throw new NullReferenceException(nameof(configuration.TestDistanceResults)); if (configuration.ValidResolutions is null) @@ -140,6 +208,10 @@ public class Configuration configuration.CheckJsonForDistanceResults.Value, configuration.CrossDirectoryMaxItemsInDistanceCollection.Value, configuration.DistanceFactor.Value, + configuration.FaceDistanceHiddenImageFactor.Value, + configuration.FaceDistanceMinimumConfidence.Value, + configuration.FaceDistancePermyriad.Value, + configuration.FaceDistanceTolerance.Value, configuration.ForceFaceLastWriteTimeToCreationTime.Value, configuration.ForceMetadataLastWriteTimeToCreationTime.Value, configuration.ForceResizeLastWriteTimeToCreationTime.Value, @@ -150,7 +222,14 @@ public class Configuration configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions, configuration.LoadOrCreateThenSaveIndex.Value, configuration.LocationConfidenceFactor.Value, + configuration.LocationDigits.Value, + configuration.LocationFactor.Value, + configuration.MapLogicSigma.Value, configuration.MappedMaxIndex, + configuration.MappingSaveFaceEncoding.Value, + configuration.MappingSaveMapped.Value, + configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping.Value, + configuration.MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping.Value, configuration.MaxItemsInDistanceCollection.Value, configuration.MixedYearRelativePaths, configuration.ModelDirectory, @@ -164,6 +243,9 @@ public class Configuration configuration.OverrideForFaceLandmarkImages.Value, configuration.OverrideForResizeImages.Value, configuration.PaddingLoops.Value, + configuration.PersonBirthdayFirstYear.Value, + configuration.PersonBirthdayFormat, + configuration.PersonKeyFormat, configuration.PredictorModelName, configuration.PropertiesChangedForDistance.Value, configuration.PropertiesChangedForFaces.Value, @@ -176,6 +258,12 @@ public class Configuration configuration.SaveResizedSubfiles.Value, configuration.SaveShortcutsForOutputResolutions, configuration.SkipSearch.Value, + configuration.SortingDaysDeltaTolerance.Value, + configuration.SortingFacesToSkipAfterSortBeforeLoad.Value, + configuration.SortingFacesToTakeAfterSortBeforeLoad.Value, + configuration.SortingMaximumPerFaceShouldBeHigh.Value, + configuration.SortingMaximumPerKey.Value, + configuration.SortingSigma.Value, configuration.TestDistanceResults.Value, configuration.ValidResolutions); return result; diff --git a/TestsWithFaceRecognitionDotNet/Models/Configuration.cs b/TestsWithFaceRecognitionDotNet/Models/Configuration.cs index 617469e..1279a92 100644 --- a/TestsWithFaceRecognitionDotNet/Models/Configuration.cs +++ b/TestsWithFaceRecognitionDotNet/Models/Configuration.cs @@ -12,6 +12,10 @@ public class Configuration public bool CheckJsonForDistanceResults { init; get; } public int CrossDirectoryMaxItemsInDistanceCollection { init; get; } public int DistanceFactor { init; get; } + public int FaceDistanceHiddenImageFactor { init; get; } + public double FaceDistanceMinimumConfidence { init; get; } + public int FaceDistancePermyriad { init; get; } + public double FaceDistanceTolerance { init; get; } public bool ForceFaceLastWriteTimeToCreationTime { init; get; } public bool ForceMetadataLastWriteTimeToCreationTime { init; get; } public bool ForceResizeLastWriteTimeToCreationTime { init; get; } @@ -22,7 +26,14 @@ public class Configuration public string[] LoadOrCreateThenSaveImageFacesResultsForOutputResolutions { init; get; } public bool LoadOrCreateThenSaveIndex { init; get; } public int LocationConfidenceFactor { init; get; } + public int LocationDigits { init; get; } + public int LocationFactor { init; get; } + public int MapLogicSigma { init; get; } public int? MappedMaxIndex { init; get; } + public bool MappingSaveFaceEncoding { init; get; } + public bool MappingSaveMapped { init; get; } + public bool MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping { init; get; } + public bool MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping { init; get; } public int MaxItemsInDistanceCollection { init; get; } public string[] MixedYearRelativePaths { init; get; } public string ModelDirectory { init; get; } @@ -36,6 +47,9 @@ public class Configuration public bool OverrideForFaceLandmarkImages { init; get; } public bool OverrideForResizeImages { init; get; } public int PaddingLoops { init; get; } + public int PersonBirthdayFirstYear { init; get; } + public string PersonBirthdayFormat { init; get; } + public string PersonKeyFormat { init; get; } public string PredictorModelName { init; get; } public bool PropertiesChangedForDistance { init; get; } public bool PropertiesChangedForFaces { init; get; } @@ -48,16 +62,87 @@ public class Configuration public bool SaveResizedSubfiles { init; get; } public string[] SaveShortcutsForOutputResolutions { init; get; } public bool SkipSearch { init; get; } + public int SortingDaysDeltaTolerance { init; get; } + public int SortingFacesToSkipAfterSortBeforeLoad { init; get; } + public int SortingFacesToTakeAfterSortBeforeLoad { init; get; } + public int SortingMaximumPerFaceShouldBeHigh { init; get; } + public int SortingMaximumPerKey { init; get; } + public int SortingSigma { init; get; } public bool TestDistanceResults { init; get; } public string[] ValidResolutions { init; get; } [JsonConstructor] - public Configuration(Property.Models.Configuration propertyConfiguration, bool checkJsonForDistanceResults, int crossDirectoryMaxItemsInDistanceCollection, int distanceFactor, bool forceFaceLastWriteTimeToCreationTime, bool forceMetadataLastWriteTimeToCreationTime, bool forceResizeLastWriteTimeToCreationTime, string[] ignoreExtensions, string[] ignoreRelativePaths, string[] juliePhares, string[] loadOrCreateThenSaveDistanceResultsForOutputResolutions, string[] loadOrCreateThenSaveImageFacesResultsForOutputResolutions, bool loadOrCreateThenSaveIndex, int locationConfidenceFactor, int? mappedMaxIndex, int maxItemsInDistanceCollection, string[] mixedYearRelativePaths, string modelDirectory, string modelName, int numberOfJitters, int numberOfTimesToUpsample, string outputExtension, int outputQuality, string[] outputResolutions, bool overrideForFaceImages, bool overrideForFaceLandmarkImages, bool overrideForResizeImages, int paddingLoops, string predictorModelName, bool propertiesChangedForDistance, bool propertiesChangedForFaces, bool propertiesChangedForIndex, bool propertiesChangedForMetadata, bool propertiesChangedForResize, bool reverse, string[] saveFaceLandmarkForOutputResolutions, bool saveFullYearOfRandomFiles, bool saveResizedSubfiles, string[] saveShortcutsForOutputResolutions, bool skipSearch, bool testDistanceResults, string[] validResolutions) + public Configuration(Property.Models.Configuration propertyConfiguration, + bool checkJsonForDistanceResults, + int crossDirectoryMaxItemsInDistanceCollection, + int distanceFactor, + int faceDistanceHiddenImageFactor, + double faceDistanceMinimumConfidence, + int faceDistancePermyriad, + double faceDistanceTolerance, + bool forceFaceLastWriteTimeToCreationTime, + bool forceMetadataLastWriteTimeToCreationTime, + bool forceResizeLastWriteTimeToCreationTime, + string[] ignoreExtensions, + string[] ignoreRelativePaths, + string[] juliePhares, + string[] loadOrCreateThenSaveDistanceResultsForOutputResolutions, + string[] loadOrCreateThenSaveImageFacesResultsForOutputResolutions, + bool loadOrCreateThenSaveIndex, + int locationConfidenceFactor, + int locationDigits, + int locationFactor, + int mapLogicSigma, + int? mappedMaxIndex, + bool mappingSaveFaceEncoding, + bool mappingSaveMapped, + bool mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping, + bool mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping, + int maxItemsInDistanceCollection, + string[] mixedYearRelativePaths, + string modelDirectory, + string modelName, + int numberOfJitters, + int numberOfTimesToUpsample, + string outputExtension, + int outputQuality, + string[] outputResolutions, + bool overrideForFaceImages, + bool overrideForFaceLandmarkImages, + bool overrideForResizeImages, + int paddingLoops, + int personBirthdayFirstYear, + string personBirthdayFormat, + string personKeyFormat, + string predictorModelName, + bool propertiesChangedForDistance, + bool propertiesChangedForFaces, + bool propertiesChangedForIndex, + bool propertiesChangedForMetadata, + bool propertiesChangedForResize, + bool reverse, + string[] saveFaceLandmarkForOutputResolutions, + bool saveFullYearOfRandomFiles, + bool saveResizedSubfiles, + string[] saveShortcutsForOutputResolutions, + bool skipSearch, + int sortingDaysDeltaTolerance, + int sortingFacesToSkipAfterSortBeforeLoad, + int sortingFacesToTakeAfterSortBeforeLoad, + int sortingMaximumPerFaceShouldBeHigh, + int sortingMaximumPerKey, + int sortingSigma, + bool testDistanceResults, + string[] validResolutions) { _PropertyConfiguration = propertyConfiguration; CheckJsonForDistanceResults = checkJsonForDistanceResults; CrossDirectoryMaxItemsInDistanceCollection = crossDirectoryMaxItemsInDistanceCollection; DistanceFactor = distanceFactor; + FaceDistanceHiddenImageFactor = faceDistanceHiddenImageFactor; + FaceDistanceMinimumConfidence = faceDistanceMinimumConfidence; + FaceDistancePermyriad = faceDistancePermyriad; + FaceDistanceTolerance = faceDistanceTolerance; ForceFaceLastWriteTimeToCreationTime = forceFaceLastWriteTimeToCreationTime; ForceMetadataLastWriteTimeToCreationTime = forceMetadataLastWriteTimeToCreationTime; ForceResizeLastWriteTimeToCreationTime = forceResizeLastWriteTimeToCreationTime; @@ -68,7 +153,14 @@ public class Configuration LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = loadOrCreateThenSaveImageFacesResultsForOutputResolutions; LoadOrCreateThenSaveIndex = loadOrCreateThenSaveIndex; LocationConfidenceFactor = locationConfidenceFactor; + LocationDigits = locationDigits; + LocationFactor = locationFactor; + MapLogicSigma = mapLogicSigma; MappedMaxIndex = mappedMaxIndex; + MappingSaveFaceEncoding = mappingSaveFaceEncoding; + MappingSaveMapped = mappingSaveMapped; + MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping = mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForAddToMapping; + MappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping = mappingUseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping; MaxItemsInDistanceCollection = maxItemsInDistanceCollection; MixedYearRelativePaths = mixedYearRelativePaths; ModelDirectory = modelDirectory; @@ -82,6 +174,9 @@ public class Configuration OverrideForFaceLandmarkImages = overrideForFaceLandmarkImages; OverrideForResizeImages = overrideForResizeImages; PaddingLoops = paddingLoops; + PersonBirthdayFirstYear = personBirthdayFirstYear; + PersonBirthdayFormat = personBirthdayFormat; + PersonKeyFormat = personKeyFormat; PredictorModelName = predictorModelName; PropertiesChangedForDistance = propertiesChangedForDistance; PropertiesChangedForFaces = propertiesChangedForFaces; @@ -94,6 +189,12 @@ public class Configuration SaveResizedSubfiles = saveResizedSubfiles; SaveShortcutsForOutputResolutions = saveShortcutsForOutputResolutions; SkipSearch = skipSearch; + SortingDaysDeltaTolerance = sortingDaysDeltaTolerance; + SortingFacesToSkipAfterSortBeforeLoad = sortingFacesToSkipAfterSortBeforeLoad; + SortingFacesToTakeAfterSortBeforeLoad = sortingFacesToTakeAfterSortBeforeLoad; + SortingMaximumPerFaceShouldBeHigh = sortingMaximumPerFaceShouldBeHigh; + SortingMaximumPerKey = sortingMaximumPerKey; + SortingSigma = sortingSigma; TestDistanceResults = testDistanceResults; ValidResolutions = validResolutions; } diff --git a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs index 795fd77..eee20b0 100644 --- a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs +++ b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs @@ -62,6 +62,15 @@ public class UnitTestFace _PropertyConfiguration = propertyConfiguration; } + [TestMethod] + public void TestConfiguration() + { + if (_Configuration.LocationDigits != Shared.Models.Stateless.ILocation.Digits) + throw new Exception("Configuration has to match interface!"); + if (_Configuration.LocationFactor != Shared.Models.Stateless.ILocation.Factor) + throw new Exception("Configuration has to match interface!"); + } + [TestMethod] public void TestMethodNull() { @@ -124,6 +133,27 @@ public class UnitTestFace return result; } + [TestMethod] + public void TestMethodRoundB() + { + const int DistanceDigits = 3; + const int DistanceFactor = 1000; + const int ToleranceAfterFactor = 600; + Assert.IsTrue(DistanceDigits == 3); + Assert.IsTrue(DistanceFactor == 1000); + Assert.IsTrue(_Configuration.FaceDistanceTolerance == 0.6d); + Assert.IsTrue(ToleranceAfterFactor == 600); + double valueA = 0.00001d; + int checkA = (int)(Math.Round(valueA, _Configuration.LocationDigits) * _Configuration.LocationFactor); + Assert.IsTrue(checkA == 10); + double valueB = 0.01d; + int checkB = (int)(Math.Round(valueB, _Configuration.LocationDigits) * _Configuration.LocationFactor); + Assert.IsTrue(checkB == 10000); + Assert.IsTrue(checkB > checkA); + int checkC = (int)(_Configuration.FaceDistanceTolerance * DistanceFactor); + Assert.IsTrue(checkC == ToleranceAfterFactor); + } + [TestMethod] public void TestMethodFace() { @@ -204,8 +234,8 @@ public class UnitTestFace property = propertyLogic.GetProperty(item, subFileTuples, parseExceptions); item.Update(property); } - (int _, metadataCollection) = metadata.GetMetadataCollection(bResultsFullGroupDirectory, subFileTuples, parseExceptions, item); - imageResizeKeyValuePairs = resize.GetResizeKeyValuePairs(cResultsFullGroupDirectory, subFileTuples, parseExceptions, original, metadataCollection, item); + (int _, metadataCollection) = metadata.GetMetadataCollection(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, subFileTuples, parseExceptions, item); + imageResizeKeyValuePairs = resize.GetResizeKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, subFileTuples, parseExceptions, original, metadataCollection, item); Assert.IsNotNull(item.ResizedFileHolder); resize.SaveResizedSubfile(outputResolution, cResultsFullGroupDirectory, subFileTuples, item, original, imageResizeKeyValuePairs); Image image = FaceRecognition.LoadImageFile(item.ResizedFileHolder.FullName);