diff --git a/.vscode/settings.json b/.vscode/settings.json index 763fbd0..8b1e351 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,23 +1,32 @@ { "cSpell.words": [ "appsettings", + "Argb", "ASPNETCORE", "Barrick", "bcdfghjklmnpqrstvwxyz", "Beichler", "Bohdi", + "cref", "CUDA", "Dlib", "Exif", "Getα", + "Greyscale", "mmod", "nosj", + "paramref", "Phares", "resnet", "Serilog", "Subfile", "Subfiles", + "Unmanaged", + "Upsample", "Vericruz" ], - "cSpell.enabled": true + "cSpell.enabled": true, + "files.exclude": { + "**/.git": false + }, } \ No newline at end of file diff --git a/Compare/Compare.cs b/Compare/Compare.cs index 34061f7..118b733 100644 --- a/Compare/Compare.cs +++ b/Compare/Compare.cs @@ -35,7 +35,7 @@ public class Compare string[] segments; _AppSettings = appSettings; if (appSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(appSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(appSettings.MaxDegreeOfParallelism)); _RenameFindReplace = new(); _RenameBFindReplace = new(); _RenameCFindReplace = new(); @@ -56,7 +56,7 @@ public class Compare Model? model = null; PredictorModel? predictorModel = null; if (propertyConfiguration.PopulatePropertyId is null) - throw new Exception($"{nameof(propertyConfiguration.PopulatePropertyId)} is null!"); + throw new ArgumentNullException(nameof(propertyConfiguration.PopulatePropertyId)); foreach (string spelling in configuration.Spelling) { segments = spelling.Split('|'); @@ -372,14 +372,14 @@ public class Compare private static void Verify(Models.Configuration configuration) { if (configuration.Spelling is null || !configuration.Spelling.Any()) - throw new Exception($"{nameof(configuration.Spelling)} should have at least one!"); + throw new ArgumentNullException(nameof(configuration.Spelling)); } private long LogDelta(long ticks, string methodName) { long result; if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); double delta = new TimeSpan(DateTime.Now.Ticks - ticks).TotalMilliseconds; _Log.Debug($"{methodName} took {Math.Floor(delta)} millisecond(s)"); result = DateTime.Now.Ticks; @@ -390,9 +390,9 @@ public class Compare { PropertyLogic result; if (_AppSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(_AppSettings.MaxDegreeOfParallelism)); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); result = new(_AppSettings.MaxDegreeOfParallelism.Value, _Configuration.PropertyConfiguration); string fromPrepareForOld = "34720-637858334555170379.tsv"; string fromPrepareForOldFile = Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, fromPrepareForOld); @@ -432,11 +432,11 @@ public class Compare private void SaveDiffFilesOrSaveLogAndMoveFiles(Property.Models.Configuration configuration) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); if (_AppSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(_AppSettings.MaxDegreeOfParallelism)); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); _Log.Information(aPropertySingletonDirectory); _Log.Information("to"); @@ -510,7 +510,7 @@ public class Compare private void ChangeExtensionFromDeleteToJson(string aPropertySingletonDirectory) { if (_AppSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(_AppSettings.MaxDegreeOfParallelism)); string searchPattern = "*.delete"; long ticks = DateTime.Now.Ticks; List topDirectories = new(); @@ -647,7 +647,7 @@ public class Compare private bool PossiblyCorrect(List topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection) { if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); bool result = false; string corrected; string correctedMoveTo; @@ -695,7 +695,7 @@ public class Compare private List GetMissingVerifyToSeasonCollection(List _, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection) { if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); List results = new(); string check; foreach ((int _, string sourceDirectory, string[] _, int _) in groupCollection) @@ -715,7 +715,7 @@ public class Compare private void CreateWindowsShortcuts((long Ticks, string FilteredSourceDirectoryFile, string PropertyDirectory, int PropertyId)[] collection, bool keepAll) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); int z = 0; string fileName; WindowsShortcut windowsShortcut; @@ -753,9 +753,9 @@ public class Compare private void ThirdPassToMove(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, PropertyLogic propertyLogic, List propertyHolderCollections, string aPropertyContentCollectionDirectory) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); int stay = 0; string fileName; string id = " - Id"; @@ -831,7 +831,7 @@ public class Compare private void FourthPassCreateWindowsShortcuts(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, PropertyLogic propertyLogic, List propertyHolderCollections, bool saveToCollection, bool keepAll) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); int stay = 0; A_Property? property; ConsoleKey? consoleKey = null; diff --git a/Date-Group/DateGroup.cs b/Date-Group/DateGroup.cs index d86526b..11d1687 100644 --- a/Date-Group/DateGroup.cs +++ b/Date-Group/DateGroup.cs @@ -31,7 +31,7 @@ public class DateGroup { } _AppSettings = appSettings; if (appSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(appSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(appSettings.MaxDegreeOfParallelism)); _IsEnvironment = isEnvironment; _Exceptions = new List(); _Log = Serilog.Log.ForContext(); @@ -46,11 +46,11 @@ public class DateGroup PredictorModel? predictorModel = null; _Configuration = configuration; if (configuration.ByHash is null) - throw new Exception($"{nameof(configuration.ByHash)} is null!"); + throw new ArgumentNullException(nameof(configuration.ByHash)); if (configuration.ByCreateDateShortcut is null) - throw new Exception($"{nameof(configuration.ByCreateDateShortcut)} is null!"); + throw new ArgumentNullException(nameof(configuration.ByCreateDateShortcut)); if (propertyConfiguration.PopulatePropertyId is null) - throw new Exception($"{nameof(propertyConfiguration.PopulatePropertyId)} is null!"); + throw new ArgumentNullException(nameof(propertyConfiguration.PopulatePropertyId)); if (!_IsEnvironment.Development) throw new Exception("This program only allows development environments!"); long ticks = DateTime.Now.Ticks; @@ -94,21 +94,21 @@ public class DateGroup private static void Verify(Models.Configuration configuration) { if (configuration.ByCreateDateShortcut is null) - throw new Exception($"{nameof(configuration.ByCreateDateShortcut)} is null!"); + throw new ArgumentNullException(nameof(configuration.ByCreateDateShortcut)); if (configuration.ByDay is null) - throw new Exception($"{nameof(configuration.ByDay)} is null!"); + throw new ArgumentNullException(nameof(configuration.ByDay)); if (configuration.ByHash is null) - throw new Exception($"{nameof(configuration.ByHash)} is null!"); + throw new ArgumentNullException(nameof(configuration.ByHash)); if (configuration.BySeason is null) - throw new Exception($"{nameof(configuration.BySeason)} is null!"); + throw new ArgumentNullException(nameof(configuration.BySeason)); if (configuration.ByWeek is null) - throw new Exception($"{nameof(configuration.ByWeek)} is null!"); + throw new ArgumentNullException(nameof(configuration.ByWeek)); if (!configuration.ByCreateDateShortcut.Value && !configuration.ByDay.Value && !configuration.ByWeek.Value && !configuration.BySeason.Value && !configuration.ByHash.Value) throw new Exception("Change configuration!"); if (configuration.KeepFullPath is null) - throw new Exception($"{nameof(configuration.KeepFullPath)} is null!"); + throw new ArgumentNullException(nameof(configuration.KeepFullPath)); if (configuration?.PropertyConfiguration?.PopulatePropertyId is null) - throw new Exception($"{nameof(configuration.PropertyConfiguration.PopulatePropertyId)} must be set!"); + throw new ArgumentNullException(nameof(configuration.PropertyConfiguration.PopulatePropertyId)); if (configuration.PropertyConfiguration.PopulatePropertyId.Value && !configuration.ByCreateDateShortcut.Value && !configuration.ByHash.Value) throw new Exception("Change configuration!"); if (!configuration.PropertyConfiguration.PopulatePropertyId.Value && configuration.ByHash.Value) @@ -153,7 +153,7 @@ public class DateGroup { long result; if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); double delta = new TimeSpan(DateTime.Now.Ticks - ticks).TotalMilliseconds; _Log.Debug($"{methodName} took {Math.Floor(delta)} millisecond(s)"); result = DateTime.Now.Ticks; @@ -164,17 +164,17 @@ public class DateGroup { List<(string Source, string[] Destination)> results = new(); if (_Configuration.ByCreateDateShortcut is null) - throw new Exception($"{nameof(_Configuration.ByCreateDateShortcut)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.ByCreateDateShortcut)); if (_Configuration.ByDay is null) - throw new Exception($"{nameof(_Configuration.ByDay)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.ByDay)); if (_Configuration.ByHash is null) - throw new Exception($"{nameof(_Configuration.ByHash)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.ByHash)); if (_Configuration.BySeason is null) - throw new Exception($"{nameof(_Configuration.BySeason)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.BySeason)); if (_Configuration.ByWeek is null) - throw new Exception($"{nameof(_Configuration.ByWeek)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.ByWeek)); if (_Configuration.KeepFullPath is null) - throw new Exception($"{nameof(_Configuration.KeepFullPath)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.KeepFullPath)); char flag; string day; int season; @@ -332,9 +332,9 @@ public class DateGroup { PropertyLogic result; if (_AppSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(_AppSettings.MaxDegreeOfParallelism)); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); result = new(_AppSettings.MaxDegreeOfParallelism.Value, _Configuration.PropertyConfiguration); return result; } @@ -343,9 +343,9 @@ public class DateGroup { List<(string Source, string[] Destination)> results = new(); if (_Configuration.KeepFullPath is null) - throw new Exception($"{nameof(_Configuration.KeepFullPath)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.KeepFullPath)); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); string? topDirectory; string? checkDirectory; string sourceDirectory; @@ -380,9 +380,9 @@ public class DateGroup private void MoveFiles(List topDirectories, List groupCollection) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); string directoryName; List distinct = new(); List<(string Source, string[] Destination)> fileMoveCollectionAll = GetFileMoveCollectionAll(topDirectories, groupCollection); diff --git a/FaceRecognitionDotNet/Dlib/Python/FaceRecognitionModelV1.cs b/FaceRecognitionDotNet/Dlib/Python/FaceRecognitionModelV1.cs index f9140d2..ce35715 100644 --- a/FaceRecognitionDotNet/Dlib/Python/FaceRecognitionModelV1.cs +++ b/FaceRecognitionDotNet/Dlib/Python/FaceRecognitionModelV1.cs @@ -8,23 +8,23 @@ internal sealed class FaceRecognitionModelV1 #region Methods - public static Matrix ComputeFaceDescriptor(LossMetric net, Image img, FullObjectDetection face, int numJitters) + public static Matrix ComputeFaceDescriptor(LossMetric net, Image img, FullObjectDetection face, int numberOfJitters) { FullObjectDetection[]? faces = new[] { face }; - return ComputeFaceDescriptors(net, img, faces, numJitters).First(); + return ComputeFaceDescriptors(net, img, faces, numberOfJitters).First(); } - public static IEnumerable> ComputeFaceDescriptors(LossMetric net, Image img, IEnumerable faces, int numJitters) + public static IEnumerable> ComputeFaceDescriptors(LossMetric net, Image img, IEnumerable faces, int numberOfJitters) { Image[]? batchImage = new[] { img }; IEnumerable[]? batchFaces = new[] { faces }; - return BatchComputeFaceDescriptors(net, batchImage, batchFaces, numJitters).First(); + return BatchComputeFaceDescriptors(net, batchImage, batchFaces, numberOfJitters).First(); } public static IEnumerable>> BatchComputeFaceDescriptors(LossMetric net, IList batchImages, IList> batchFaces, - int numJitters) + int numberOfJitters) { if (batchImages.Count != batchFaces.Count) throw new ArgumentException("The array of images and the array of array of locations must be of the same size"); @@ -60,7 +60,7 @@ internal sealed class FaceRecognitionModelV1 for (int i = 0, count = batchImages.Count; i < count; i++) faceDescriptors.Add(new List>()); - if (numJitters <= 1) + if (numberOfJitters <= 1) { // extract descriptors and convert from float vectors to double vectors OutputLabels>? descriptors = net.Operator(faceChips, 16); @@ -80,7 +80,7 @@ internal sealed class FaceRecognitionModelV1 for (int i = 0; i < batchFaces.Count; ++i) for (int j = 0; j < batchFaces[i].Count(); ++j) { - Matrix[]? tmp = JitterImage(faceChips[index++], numJitters).ToArray(); + Matrix[]? tmp = JitterImage(faceChips[index++], numberOfJitters).ToArray(); using (OutputLabels>? tmp2 = net.Operator(tmp, 16)) using (MatrixOp? mat = DlibDotNet.Dlib.Mat(tmp2)) { @@ -113,10 +113,10 @@ internal sealed class FaceRecognitionModelV1 private static readonly Rand _Rand = new(); - private static IEnumerable> JitterImage(Matrix img, int numJitters) + private static IEnumerable> JitterImage(Matrix img, int numberOfJitters) { List>? crops = new(); - for (int i = 0; i < numJitters; ++i) + for (int i = 0; i < numberOfJitters; ++i) crops.Add(DlibDotNet.Dlib.JitterImage(img, _Rand)); return crops; diff --git a/FaceRecognitionDotNet/FaceEncoding.cs b/FaceRecognitionDotNet/FaceEncoding.cs index cfaf1ab..031076e 100644 --- a/FaceRecognitionDotNet/FaceEncoding.cs +++ b/FaceRecognitionDotNet/FaceEncoding.cs @@ -30,9 +30,9 @@ public sealed class FaceEncoding : DisposableObject, ISerializable int? row = (int?)info.GetValue(nameof(_Encoding.Rows), typeof(int)); int? column = (int?)info.GetValue(nameof(_Encoding.Columns), typeof(int)); if (row is null) - throw new Exception($"{nameof(row)} is null"); + throw new ArgumentNullException(nameof(row)); if (column is null) - throw new Exception($"{nameof(column)} is null"); + throw new ArgumentNullException(nameof(column)); _Encoding = new Matrix(array, row.Value, column.Value); } diff --git a/FaceRecognitionDotNet/FaceRecognition.cs b/FaceRecognitionDotNet/FaceRecognition.cs index 1b6d06d..a0d3574 100644 --- a/FaceRecognitionDotNet/FaceRecognition.cs +++ b/FaceRecognitionDotNet/FaceRecognition.cs @@ -150,7 +150,7 @@ public sealed class FaceRecognition : DisposableObject /// The number of images to include in each GPU processing batch. /// An enumerable collection of array of found face locations. /// is null. - public IEnumerable BatchFaceLocations(IEnumerable images, int numberOfTimesToUpsample = 1, int batchSize = 128) + public IEnumerable BatchFaceLocations(IEnumerable images, int numberOfTimesToUpsample, int batchSize = 128) { if (images == null) throw new ArgumentNullException(nameof(images)); @@ -167,7 +167,7 @@ public sealed class FaceRecognition : DisposableObject for (int index = 0; index < rawDetectionsBatched.Length; index++) { MModRect[]? faces = rawDetectionsBatched[index].ToArray(); - Location[]? locations = faces.Select(rect => new Location(TrimBound(rect.Rect, image.Width, image.Height), rect.DetectionConfidence)).ToArray(); + Location[]? locations = faces.Select(rect => new Location(rect.DetectionConfidence, TrimBound(rect.Rect, image.Width, image.Height), image.Width, image.Height)).ToArray(); foreach (MModRect? face in faces) face.Dispose(); results.Add(locations); @@ -358,7 +358,7 @@ public sealed class FaceRecognition : DisposableObject /// /// The image contains faces. The image can contain multiple faces. /// The enumerable collection of location rectangle for faces. If specified null, method will find face locations. - /// The number of times to re-sample the face when calculating encoding. + /// The number of times to re-sample the face when calculating encoding. /// The dimension of vector which be returned from detector. /// The model of face detector to detect in image. If is not null, this value is ignored. /// An enumerable collection of face feature data corresponds to all faces in specified image. @@ -366,11 +366,7 @@ public sealed class FaceRecognition : DisposableObject /// contains no elements. /// or this object or custom face landmark detector is disposed. /// is not supported. - public List FaceEncodings(Image image, - IEnumerable? knownFaceLocation = null, - int numJitters = 1, - PredictorModel predictorModel = PredictorModel.Small, - Model model = Model.Hog) + public List FaceEncodings(Image image, int numberOfTimesToUpsample, IEnumerable? knownFaceLocation, int numberOfJitters, PredictorModel predictorModel, Model model) { if (image == null) throw new ArgumentNullException(nameof(image)); @@ -383,12 +379,12 @@ public sealed class FaceRecognition : DisposableObject image.ThrowIfDisposed(); ThrowIfDisposed(); - IEnumerable? rawLandmarks = RawFaceLandmarks(image, knownFaceLocation, predictorModel, model); + List rawLandmarks = RawFaceLandmarks(image, numberOfTimesToUpsample, knownFaceLocation, predictorModel, model); List results = new(); - foreach (FullObjectDetection? landmark in rawLandmarks) + foreach (FullObjectDetection landmark in rawLandmarks) { - FaceEncoding? ret = new(FaceRecognitionModelV1.ComputeFaceDescriptor(_FaceEncoder, image, landmark, numJitters)); + FaceEncoding? ret = new(FaceRecognitionModelV1.ComputeFaceDescriptor(_FaceEncoder, image, landmark, numberOfJitters)); landmark.Dispose(); results.Add(ret); } @@ -396,6 +392,14 @@ public sealed class FaceRecognition : DisposableObject return results; } + private static FacePoint[] Join(IEnumerable facePoints1, IEnumerable facePoints2) + { + List results = new(); + results.AddRange(facePoints1); + results.AddRange(facePoints2); + return results.ToArray(); + } + /// /// Returns an enumerable collection of dictionary of face parts locations (eyes, nose, etc) for each face in the image. /// @@ -408,89 +412,53 @@ public sealed class FaceRecognition : DisposableObject /// contains no elements. /// or this object or custom face landmark detector is disposed. /// The custom face landmark detector is not ready. - public List>> FaceLandmark(Image faceImage, - IEnumerable? faceLocations = null, - PredictorModel predictorModel = PredictorModel.Large, - Model model = Model.Hog) + public List<(FacePart, FacePoint[])[]> GetFaceLandmarkCollection(Image faceImage, int numberOfTimesToUpsample, IEnumerable? faceLocations, PredictorModel predictorModel, Model model) { + List<(FacePart, FacePoint[])[]> results = new(); if (faceImage == null) throw new ArgumentNullException(nameof(faceImage)); - if (faceLocations != null && !faceLocations.Any()) throw new InvalidOperationException($"{nameof(faceLocations)} contains no elements."); - faceImage.ThrowIfDisposed(); ThrowIfDisposed(); - if (predictorModel == PredictorModel.Custom) + throw new NotImplementedException(); + List fullObjectDetections = RawFaceLandmarks(faceImage, numberOfTimesToUpsample, faceLocations, predictorModel, model); + List landmarksCollection = fullObjectDetections.Select(landmark => Enumerable.Range(0, (int)landmark.Parts) + .Select(index => new FacePoint(index, landmark.GetPart((uint)index).X, landmark.GetPart((uint)index).Y)).ToArray()).ToList(); + foreach (FullObjectDetection? landmark in fullObjectDetections) + landmark.Dispose(); + List<(FacePart, FacePoint[])> collection; + foreach (FacePoint[] facePoints in landmarksCollection) { - if (CustomFaceLandmarkDetector == null) - throw new NotSupportedException("The custom face landmark detector is not ready."); - - if (CustomFaceLandmarkDetector.IsDisposed) - throw new ObjectDisposedException($"{nameof(CustomFaceLandmarkDetector)}", "The custom face landmark detector is disposed."); - } - - FullObjectDetection[]? landmarks = RawFaceLandmarks(faceImage, faceLocations, predictorModel, model).ToArray(); - IEnumerable? landmarkTuples = landmarks.Select(landmark => Enumerable.Range(0, (int)landmark.Parts) - .Select(index => new FacePoint(index, landmark.GetPart((uint)index).X, landmark.GetPart((uint)index).Y)).ToArray()); - - List>> results = new(); - - try - { - - // For a definition of each point index, see https://cdn-images-1.medium.com/max/1600/1*AbEg31EgkbXSQehuNJBlWg.png + collection = new(); switch (predictorModel) { + case PredictorModel.Custom: + throw new NotImplementedException(); case PredictorModel.Large: - results.AddRange(landmarkTuples.Select(landmarkTuple => new Dictionary> - { - { FacePart.Chin, Enumerable.Range(0,17).Select(i => landmarkTuple[i]).ToArray() }, - { FacePart.LeftEyebrow, Enumerable.Range(17,5).Select(i => landmarkTuple[i]).ToArray() }, - { FacePart.RightEyebrow, Enumerable.Range(22,5).Select(i => landmarkTuple[i]).ToArray() }, - { FacePart.NoseBridge, Enumerable.Range(27,5).Select(i => landmarkTuple[i]).ToArray() }, - { FacePart.NoseTip, Enumerable.Range(31,5).Select(i => landmarkTuple[i]).ToArray() }, - { FacePart.LeftEye, Enumerable.Range(36,6).Select(i => landmarkTuple[i]).ToArray() }, - { FacePart.RightEye, Enumerable.Range(42,6).Select(i => landmarkTuple[i]).ToArray() }, - { FacePart.TopLip, Enumerable.Range(48,7).Select(i => landmarkTuple[i]) - .Concat( new [] { landmarkTuple[64] }) - .Concat( new [] { landmarkTuple[63] }) - .Concat( new [] { landmarkTuple[62] }) - .Concat( new [] { landmarkTuple[61] }) - .Concat( new [] { landmarkTuple[60] }) }, - { FacePart.BottomLip, Enumerable.Range(54,6).Select(i => landmarkTuple[i]) - .Concat( new [] { landmarkTuple[48] }) - .Concat( new [] { landmarkTuple[60] }) - .Concat( new [] { landmarkTuple[67] }) - .Concat( new [] { landmarkTuple[66] }) - .Concat( new [] { landmarkTuple[65] }) - .Concat( new [] { landmarkTuple[64] }) } - })); + if (facePoints.Length != 68) + continue; + collection.Add(new(FacePart.Chin, facePoints.Skip(0).Take(17).ToArray())); + collection.Add(new(FacePart.LeftEyebrow, facePoints.Skip(17).Take(5).ToArray())); + collection.Add(new(FacePart.RightEyebrow, facePoints.Skip(22).Take(5).ToArray())); + collection.Add(new(FacePart.NoseBridge, facePoints.Skip(27).Take(5).ToArray())); + collection.Add(new(FacePart.NoseTip, facePoints.Skip(31).Take(5).ToArray())); + collection.Add(new(FacePart.LeftEye, facePoints.Skip(36).Take(6).ToArray())); + collection.Add(new(FacePart.RightEye, facePoints.Skip(42).Take(6).ToArray())); + collection.Add(new(FacePart.TopLip, Join(facePoints.Skip(48).Take(7), facePoints.Skip(60).Take(5)))); + collection.Add(new(FacePart.BottomLip, Join(facePoints.Skip(55).Take(5), facePoints.Skip(65).Take(3)))); break; case PredictorModel.Small: - results.AddRange(landmarkTuples.Select(landmarkTuple => new Dictionary> - { - { FacePart.NoseTip, Enumerable.Range(4,1).Select(i => landmarkTuple[i]).ToArray() }, - { FacePart.LeftEye, Enumerable.Range(2,2).Select(i => landmarkTuple[i]).ToArray() }, - { FacePart.RightEye, Enumerable.Range(0,2).Select(i => landmarkTuple[i]).ToArray() } - })); + if (facePoints.Length != 5) + continue; + collection.Add(new(FacePart.RightEye, facePoints.Skip(0).Take(2).ToArray())); + collection.Add(new(FacePart.LeftEye, facePoints.Skip(2).Take(2).ToArray())); + collection.Add(new(FacePart.NoseTip, facePoints.Skip(4).Take(1).ToArray())); break; - case PredictorModel.Custom: - if (CustomFaceLandmarkDetector is null) - throw new Exception($"{nameof(CustomFaceLandmarkDetector)} is null"); - results.AddRange(CustomFaceLandmarkDetector.GetLandmarks(landmarkTuples)); - break; - default: - throw new ArgumentOutOfRangeException(nameof(predictorModel), predictorModel, null); } + results.Add(collection.ToArray()); } - finally - { - foreach (FullObjectDetection? landmark in landmarks) - landmark.Dispose(); - } - return results; } @@ -503,7 +471,7 @@ public sealed class FaceRecognition : DisposableObject /// An enumerable collection of face location correspond to all faces in specified image. /// is null. /// or this object is disposed. - public List FaceLocations(Image image, int numberOfTimesToUpsample = 1, Model model = Model.Hog) + public List FaceLocations(Model model, Image image, int numberOfTimesToUpsample, bool sortByPixelPercentage) { if (image == null) throw new ArgumentNullException(nameof(image)); @@ -517,9 +485,10 @@ public sealed class FaceRecognition : DisposableObject Location? ret = TrimBound(face.Rect, image.Width, image.Height); double confidence = face.DetectionConfidence; face.Dispose(); - results.Add(new Location(ret, confidence)); + results.Add(new Location(confidence, ret, image.Width, image.Height)); } - + if (sortByPixelPercentage) + results = (from l in results orderby l.PixelPercentage select l).ToList(); return results; } @@ -763,36 +732,33 @@ public sealed class FaceRecognition : DisposableObject #region Helpers - private IEnumerable RawFaceLandmarks(Image faceImage, - IEnumerable? faceLocations = null, - PredictorModel predictorModel = PredictorModel.Large, - Model model = Model.Hog) + private List RawFaceLandmarks(Image faceImage, int numberOfTimesToUpsample, IEnumerable? faceLocations, PredictorModel predictorModel, Model model) { - IEnumerable rects; + IEnumerable locations; if (faceLocations == null) { List? list = new(); - IEnumerable? tmp = RawFaceLocations(faceImage, 1, model); + IEnumerable? tmp = RawFaceLocations(faceImage, numberOfTimesToUpsample, model); foreach (MModRect? mModRect in tmp) { - list.Add(new Location(mModRect.DetectionConfidence, mModRect.Rect.Bottom, mModRect.Rect.Left, mModRect.Rect.Right, mModRect.Rect.Top)); + list.Add(new Location(mModRect.DetectionConfidence, mModRect.Rect.Bottom, mModRect.Rect.Left, mModRect.Rect.Right, mModRect.Rect.Top, faceImage.Width, faceImage.Height)); mModRect.Dispose(); } - rects = list; + locations = list; } else { - rects = faceLocations; + locations = faceLocations; } - List? results = new(); + List results = new(); if (predictorModel == PredictorModel.Custom) { if (CustomFaceLandmarkDetector is null) - throw new Exception($"{nameof(CustomFaceLandmarkDetector)} is null"); - foreach (Location? rect in rects) + throw new ArgumentNullException(nameof(CustomFaceLandmarkDetector)); + foreach (Location? rect in locations) { FullObjectDetection? ret = CustomFaceLandmarkDetector.Detect(faceImage, rect); results.Add(ret); @@ -808,7 +774,7 @@ public sealed class FaceRecognition : DisposableObject break; } - foreach (Location? rect in rects) + foreach (Location? rect in locations) { FullObjectDetection? ret = posePredictor.Detect(faceImage.Matrix, new DlibDotNet.Rectangle(rect.Left, rect.Top, rect.Right, rect.Bottom)); results.Add(ret); @@ -818,7 +784,7 @@ public sealed class FaceRecognition : DisposableObject return results; } - private IEnumerable RawFaceLocations(Image faceImage, int numberOfTimesToUpsample = 1, Model model = Model.Hog) + private IEnumerable RawFaceLocations(Image faceImage, int numberOfTimesToUpsample, Model model) { switch (model) { @@ -838,9 +804,9 @@ public sealed class FaceRecognition : DisposableObject } } - private IEnumerable> RawFaceLocationsBatched(IEnumerable faceImages, int numberOfTimesToUpsample = 1, int batchSize = 128) => CnnFaceDetectionModelV1.DetectMulti(_CnnFaceDetector, faceImages, numberOfTimesToUpsample, batchSize); + private IEnumerable> RawFaceLocationsBatched(IEnumerable faceImages, int numberOfTimesToUpsample, int batchSize = 128) => CnnFaceDetectionModelV1.DetectMulti(_CnnFaceDetector, faceImages, numberOfTimesToUpsample, batchSize); - private static Location TrimBound(DlibDotNet.Rectangle location, int width, int height) => new(Math.Max(location.Left, 0), Math.Max(location.Top, 0), Math.Min(location.Right, width), Math.Min(location.Bottom, height)); + private static Location TrimBound(DlibDotNet.Rectangle location, int width, int height) => new(Math.Max(location.Left, 0), Math.Max(location.Top, 0), Math.Min(location.Right, width), Math.Min(location.Bottom, height), width, height); #endregion diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index b9471f1..6b8d58d 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -41,7 +41,7 @@ public class DlibDotNet Person[] people; _AppSettings = appSettings; if (appSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(appSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(appSettings.MaxDegreeOfParallelism)); _IsEnvironment = isEnvironment; _Exceptions = new List(); _Log = Serilog.Log.ForContext(); @@ -61,21 +61,21 @@ public class DlibDotNet _Distance = new E_Distance(configuration); _FaceLandmarks = new D2_FaceLandmarks(configuration); if (configuration.ForceMetadataLastWriteTimeToCreationTime is null) - throw new Exception($"{nameof(configuration.ForceMetadataLastWriteTimeToCreationTime)} is null!"); + throw new ArgumentNullException(nameof(configuration.ForceMetadataLastWriteTimeToCreationTime)); if (configuration.ForceResizeLastWriteTimeToCreationTime is null) - throw new Exception($"{nameof(configuration.ForceResizeLastWriteTimeToCreationTime)} is null!"); + throw new ArgumentNullException(nameof(configuration.ForceResizeLastWriteTimeToCreationTime)); if (configuration.IgnoreExtensions is null) - throw new Exception($"{nameof(configuration.IgnoreExtensions)} is null!"); + throw new ArgumentNullException(nameof(configuration.IgnoreExtensions)); if (configuration.OutputQuality is null) - throw new Exception($"{nameof(configuration.OutputQuality)} is null!"); + throw new ArgumentNullException(nameof(configuration.OutputQuality)); if (configuration.OverrideForResizeImages is null) - throw new Exception($"{nameof(configuration.OverrideForResizeImages)} is null!"); + throw new ArgumentNullException(nameof(configuration.OverrideForResizeImages)); if (configuration.PropertiesChangedForMetadata is null) - throw new Exception($"{nameof(configuration.PropertiesChangedForMetadata)} is null!"); + throw new ArgumentNullException(nameof(configuration.PropertiesChangedForMetadata)); if (configuration.PropertiesChangedForResize is null) - throw new Exception($"{nameof(configuration.PropertiesChangedForResize)} is null!"); + throw new ArgumentNullException(nameof(configuration.PropertiesChangedForResize)); if (configuration.Reverse is null) - throw new Exception($"{nameof(configuration.Reverse)} is null!"); + throw new ArgumentNullException(nameof(configuration.Reverse)); _Metadata = new(configuration.ForceMetadataLastWriteTimeToCreationTime.Value, configuration.PropertiesChangedForMetadata.Value); if (args.Count > 0) argZero = Path.GetFullPath(args[0]); @@ -88,7 +88,7 @@ public class DlibDotNet (Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(configuration); _Faces = new D_Face(configuration, argZero, model, modelParameter, predictorModel); if (configuration.SkipSearch is null) - throw new Exception($"{nameof(configuration.SkipSearch)} is null!"); + throw new ArgumentNullException(nameof(configuration.SkipSearch)); if (!_ArgZeroIsConfigurationRootDirectory) people = Array.Empty(); else @@ -134,7 +134,7 @@ public class DlibDotNet { long result; if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); double delta = new TimeSpan(DateTime.Now.Ticks - ticks).TotalMilliseconds; _Log.Debug($"{methodName} took {Math.Floor(delta)} millisecond(s)"); result = DateTime.Now.Ticks; @@ -188,7 +188,7 @@ public class DlibDotNet private void Verify(Models.Configuration configuration) { if (!configuration.OutputResolutions.Any() || string.IsNullOrEmpty(configuration.OutputResolutions[0]) || !configuration.ValidResolutions.Contains(configuration.OutputResolutions[0])) - throw new Exception($"{nameof(configuration.OutputResolutions)} must be a valid outputResolution!"); + throw new ArgumentNullException(nameof(configuration.OutputResolutions), "must be a valid outputResolution!"); if ((from l in configuration.OutputResolutions where !configuration.ValidResolutions.Contains(l) select false).Any()) throw new Exception($"One or more {nameof(configuration.OutputResolutions)} are not in the ValidResolutions list!"); if ((from l in configuration.LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions where !configuration.ValidResolutions.Contains(l) select false).Any()) @@ -202,79 +202,81 @@ public class DlibDotNet if ((from l in configuration.SaveFaceLandmarkForOutputResolutions where !configuration.ValidResolutions.Contains(l) select false).Any()) throw new Exception($"One or more {nameof(configuration.SaveFaceLandmarkForOutputResolutions)} are not in the ValidResolutions list!"); if (configuration.CheckJsonForDistanceResults is null) - throw new Exception($"{nameof(configuration.CheckJsonForDistanceResults)} must be set!"); + throw new ArgumentNullException(nameof(configuration.CheckJsonForDistanceResults)); if (configuration.CrossDirectoryMaxItemsInDistanceCollection is null) - throw new Exception($"{nameof(configuration.CrossDirectoryMaxItemsInDistanceCollection)} must be set!"); + throw new ArgumentNullException(nameof(configuration.CrossDirectoryMaxItemsInDistanceCollection)); if (configuration.DistanceFactor is null) - throw new Exception($"{nameof(configuration.DistanceFactor)} must be set!"); + throw new ArgumentNullException(nameof(configuration.DistanceFactor)); if (configuration.ForceMetadataLastWriteTimeToCreationTime is null) - throw new Exception($"{nameof(configuration.ForceMetadataLastWriteTimeToCreationTime)} must be set!"); + throw new ArgumentNullException(nameof(configuration.ForceMetadataLastWriteTimeToCreationTime)); if (configuration.ForceResizeLastWriteTimeToCreationTime is null) - throw new Exception($"{nameof(configuration.ForceResizeLastWriteTimeToCreationTime)} must be set!"); + throw new ArgumentNullException(nameof(configuration.ForceResizeLastWriteTimeToCreationTime)); if (configuration.IgnoreExtensions is null) - throw new Exception($"{nameof(configuration.IgnoreExtensions)} must be set!"); + throw new ArgumentNullException(nameof(configuration.IgnoreExtensions)); if (configuration.IgnoreRelativePaths is null) - throw new Exception($"{nameof(configuration.IgnoreRelativePaths)} must be set!"); + throw new ArgumentNullException(nameof(configuration.IgnoreRelativePaths)); if (configuration.LoadOrCreateThenSaveIndex is null) - throw new Exception($"{nameof(configuration.LoadOrCreateThenSaveIndex)} must be set!"); + throw new ArgumentNullException(nameof(configuration.LoadOrCreateThenSaveIndex)); if (configuration.LocationConfidenceFactor is null) - throw new Exception($"{nameof(configuration.LocationConfidenceFactor)} must be set!"); + throw new ArgumentNullException(nameof(configuration.LocationConfidenceFactor)); if (configuration.MappedMaxIndex is null) - throw new Exception($"{nameof(configuration.MappedMaxIndex)} must be set!"); + throw new ArgumentNullException(nameof(configuration.MappedMaxIndex)); if (configuration.MappedMaxIndex.HasValue && configuration.LoadOrCreateThenSaveIndex.Value && !_IsEnvironment.DebuggerWasAttachedDuringConstructor) - throw new Exception($"{nameof(configuration.MappedMaxIndex)} only allowed when debugger is attached!"); + throw new ArgumentNullException(nameof(configuration.MappedMaxIndex)); if (configuration.MaxItemsInDistanceCollection is null) - throw new Exception($"{nameof(configuration.MaxItemsInDistanceCollection)} must be set!"); + throw new ArgumentNullException(nameof(configuration.MaxItemsInDistanceCollection)); if (configuration.MixedYearRelativePaths is null) - throw new Exception($"{nameof(configuration.MixedYearRelativePaths)} must be set!"); - if (configuration.NumJitters is null) - throw new Exception($"{nameof(configuration.NumJitters)} must be set!"); + throw new ArgumentNullException(nameof(configuration.MixedYearRelativePaths)); + if (configuration.NumberOfJitters is null) + throw new ArgumentNullException(nameof(configuration.NumberOfJitters)); + if (configuration.NumberOfTimesToUpsample is null) + throw new ArgumentNullException(nameof(configuration.NumberOfTimesToUpsample)); if (configuration.OutputQuality is null) - throw new Exception($"{nameof(configuration.OutputQuality)} must be set!"); + throw new ArgumentNullException(nameof(configuration.OutputQuality)); if (configuration.OutputResolutions is null) - throw new Exception($"{nameof(configuration.OutputResolutions)} must be set!"); + throw new ArgumentNullException(nameof(configuration.OutputResolutions)); if (configuration.OverrideForFaceImages is null) - throw new Exception($"{nameof(configuration.OverrideForFaceImages)} must be set!"); + throw new ArgumentNullException(nameof(configuration.OverrideForFaceImages)); if (configuration.OverrideForFaceLandmarkImages is null) - throw new Exception($"{nameof(configuration.OverrideForFaceLandmarkImages)} must be set!"); + throw new ArgumentNullException(nameof(configuration.OverrideForFaceLandmarkImages)); if (configuration.OverrideForResizeImages is null) - throw new Exception($"{nameof(configuration.OverrideForResizeImages)} must be set!"); + throw new ArgumentNullException(nameof(configuration.OverrideForResizeImages)); if (configuration.PaddingLoops is null) - throw new Exception($"{nameof(configuration.PaddingLoops)} must be set!"); + throw new ArgumentNullException(nameof(configuration.PaddingLoops)); if (configuration.PropertiesChangedForDistance is null) - throw new Exception($"{nameof(configuration.PropertiesChangedForDistance)} must be set!"); + throw new ArgumentNullException(nameof(configuration.PropertiesChangedForDistance)); if (configuration.PropertiesChangedForFaces is null) - throw new Exception($"{nameof(configuration.PropertiesChangedForFaces)} must be set!"); + throw new ArgumentNullException(nameof(configuration.PropertiesChangedForFaces)); if (configuration.PropertiesChangedForIndex is null) - throw new Exception($"{nameof(configuration.PropertiesChangedForIndex)} must be set!"); + throw new ArgumentNullException(nameof(configuration.PropertiesChangedForIndex)); if (configuration.PropertiesChangedForMetadata is null) - throw new Exception($"{nameof(configuration.PropertiesChangedForMetadata)} must be set!"); + throw new ArgumentNullException(nameof(configuration.PropertiesChangedForMetadata)); if (configuration.PropertiesChangedForResize is null) - throw new Exception($"{nameof(configuration.PropertiesChangedForResize)} must be set!"); + throw new ArgumentNullException(nameof(configuration.PropertiesChangedForResize)); if (configuration.Reverse is null) - throw new Exception($"{nameof(configuration.Reverse)} must be set!"); + throw new ArgumentNullException(nameof(configuration.Reverse)); if (configuration.SaveFaceLandmarkForOutputResolutions is null) - throw new Exception($"{nameof(configuration.SaveFaceLandmarkForOutputResolutions)} must be set!"); + throw new ArgumentNullException(nameof(configuration.SaveFaceLandmarkForOutputResolutions)); if (configuration.SaveFullYearOfRandomFiles is null) - throw new Exception($"{nameof(configuration.SaveFullYearOfRandomFiles)} must be set!"); + throw new ArgumentNullException(nameof(configuration.SaveFullYearOfRandomFiles)); if (configuration.SaveResizedSubfiles is null) - throw new Exception($"{nameof(configuration.SaveResizedSubfiles)} must be set!"); + throw new ArgumentNullException(nameof(configuration.SaveResizedSubfiles)); if (configuration.SkipSearch is null) - throw new Exception($"{nameof(configuration.SkipSearch)} must be set!"); + throw new ArgumentNullException(nameof(configuration.SkipSearch)); if (configuration.TestDistanceResults is null) - throw new Exception($"{nameof(configuration.TestDistanceResults)} must be set!"); + throw new ArgumentNullException(nameof(configuration.TestDistanceResults)); if (configuration.ValidResolutions is null) - throw new Exception($"{nameof(configuration.ValidResolutions)} must be set!"); + throw new ArgumentNullException(nameof(configuration.ValidResolutions)); if (string.IsNullOrEmpty(configuration.ModelDirectory) || !Directory.Exists(configuration.ModelDirectory)) - throw new Exception($"{nameof(configuration.ModelDirectory)} must have a value and exits!"); + throw new ArgumentNullException(nameof(configuration.ModelDirectory)); if (string.IsNullOrEmpty(configuration.ModelName)) - throw new Exception($"{nameof(configuration.ModelName)} must have a value!"); + throw new ArgumentNullException(nameof(configuration.ModelName)); if (string.IsNullOrEmpty(configuration.OutputExtension)) - throw new Exception($"{nameof(configuration.OutputExtension)} must have a value!"); + throw new ArgumentNullException(nameof(configuration.OutputExtension)); if (string.IsNullOrEmpty(configuration.PredictorModelName)) - throw new Exception($"{nameof(configuration.PredictorModelName)} must have a value!"); + throw new ArgumentNullException(nameof(configuration.PredictorModelName)); if (configuration.DistanceFactor.Value + configuration.LocationConfidenceFactor.Value != 10) - throw new Exception($"{nameof(configuration.DistanceFactor)} and {nameof(configuration.LocationConfidenceFactor)} must add up to 10!"); + throw new ArgumentNullException(nameof(configuration.DistanceFactor)); } private void VerifyExtra(List args, Property.Models.Configuration propertyConfiguration, Models.Configuration configuration) @@ -306,15 +308,15 @@ public class DlibDotNet private void FullParallelForWork(PropertyLogic propertyLogic, object @lock, string outputResolution, List> sourceDirectoryChanges, List propertyFileInfoCollection, List propertyCollection, List>> metadataCollections, List> resizeKeyValuePairs, List> imageFaceCollections, string sourceDirectory, int index, PropertyHolder propertyHolder) { if (propertyHolder.ImageFileInfo is null) - throw new Exception($"{nameof(propertyHolder.ImageFileInfo)} is null!"); + throw new ArgumentNullException(nameof(propertyHolder.ImageFileInfo)); if (_AppSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(_AppSettings.MaxDegreeOfParallelism)); if (_Configuration.SaveResizedSubfiles is null) - throw new Exception($"{nameof(_Configuration.SaveResizedSubfiles)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.SaveResizedSubfiles)); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); if (_Configuration.PropertyConfiguration.WriteBitmapDataBytes is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration.WriteBitmapDataBytes)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration.WriteBitmapDataBytes)); A_Property property; List faceCollection; string original = "Original"; @@ -395,9 +397,9 @@ public class DlibDotNet { int result = 0; if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); if (_AppSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(AppSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(AppSettings.MaxDegreeOfParallelism)); ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism.Value }; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; if (faceCollections.Count != filteredPropertyHolderCollection.Length || metadataCollection.Count != filteredPropertyHolderCollection.Length || resizeKeyValuePairs.Count != filteredPropertyHolderCollection.Length || propertyCollection.Count != filteredPropertyHolderCollection.Length) @@ -460,7 +462,7 @@ public class DlibDotNet if (metadataIdLines.Any()) { text = string.Join(Environment.NewLine, from l in metadataIdLines orderby l.Id select l.Line); - _ = Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, text, compareBeforeWrite: true); + _ = Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, text, updateDateWhenMatches: true, compareBeforeWrite: true); } else { @@ -472,19 +474,18 @@ public class DlibDotNet private void WriteGroup(Property.Models.Configuration configuration, PropertyLogic propertyLogic, List propertyCollection, List>> metadataCollection, List> faceCollections, List> resizeKeyValuePairs, string sourceDirectory, string outputResolution, PropertyHolder[] filteredPropertyHolderCollection) { if (_Configuration.PropertiesChangedForMetadata is null) - throw new Exception($"{nameof(_Configuration.PropertiesChangedForMetadata)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.PropertiesChangedForMetadata)); if (configuration.PropertiesChangedForProperty is null) - throw new Exception($"{nameof(configuration.PropertiesChangedForProperty)} is null!"); + throw new ArgumentNullException(nameof(configuration.PropertiesChangedForProperty)); if (_Configuration.PropertiesChangedForResize is null) - throw new Exception($"{nameof(_Configuration.PropertiesChangedForResize)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.PropertiesChangedForResize)); if (_Configuration.PropertiesChangedForFaces is null) - throw new Exception($"{nameof(_Configuration.PropertiesChangedForFaces)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.PropertiesChangedForFaces)); string key; string json; string checkFile; PropertyHolder propertyHolder; int sourceDirectoryLength = sourceDirectory.Length; - int rootDirectoryLength = configuration.RootDirectory.Length; _FilePropertiesKeyValuePairs.Add(sourceDirectory, new List>()); JsonSerializerOptions writeIndentedJsonSerializerOptions = new() { WriteIndented = false }; if (!(from l in propertyCollection where l?.Width is null select true).Any()) @@ -511,16 +512,6 @@ public class DlibDotNet resizeKeyValuePairsCollections.Add(new KeyValuePair>(key, resizeKeyValuePairs[i])); metadataCollectionKeyValuePairs.Add(new KeyValuePair>>(key, metadataCollection[i])); } - if (_Metadata.AngleBracketCollection.Any()) - { - checkDirectory = Property.Models.Stateless.IPath.GetDirectory(_Metadata.AngleBracketCollection[0], level, "[{}]"); - checkFile = Path.Combine(checkDirectory, fileName); - if (File.Exists(checkFile)) - File.Move(checkFile, Path.Combine(checkDirectory, fileName)); - checkFile = Path.Combine(checkDirectory, fileName); - json = JsonSerializer.Serialize(metadataCollectionKeyValuePairs, writeIndentedJsonSerializerOptions); - _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, compareBeforeWrite: true); - } if (propertyLogic.AngleBracketCollection.Any()) { checkDirectory = Property.Models.Stateless.IPath.GetDirectory(propertyLogic.AngleBracketCollection[0], level, "[{}]"); @@ -529,7 +520,17 @@ public class DlibDotNet File.Move(checkFile, Path.Combine(checkDirectory, fileName)); checkFile = Path.Combine(checkDirectory, fileName); json = JsonSerializer.Serialize(propertyCollectionKeyValuePairs, writeIndentedJsonSerializerOptions); - _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, compareBeforeWrite: true); + _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true); + } + if (_Metadata.AngleBracketCollection.Any()) + { + checkDirectory = Property.Models.Stateless.IPath.GetDirectory(_Metadata.AngleBracketCollection[0], level, "[{}]"); + checkFile = Path.Combine(checkDirectory, fileName); + if (File.Exists(checkFile)) + File.Move(checkFile, Path.Combine(checkDirectory, fileName)); + checkFile = Path.Combine(checkDirectory, fileName); + json = JsonSerializer.Serialize(metadataCollectionKeyValuePairs, writeIndentedJsonSerializerOptions); + _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true); } if (_Resize.AngleBracketCollection.Any()) { @@ -539,7 +540,7 @@ public class DlibDotNet File.Move(checkFile, Path.Combine(checkDirectory, fileName)); checkFile = Path.Combine(checkDirectory, fileName); json = JsonSerializer.Serialize(resizeKeyValuePairsCollections, writeIndentedJsonSerializerOptions); - _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, compareBeforeWrite: true); + _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true); } if (_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution) && _Faces.AngleBracketCollection.Any()) { @@ -549,7 +550,7 @@ public class DlibDotNet File.Move(checkFile, Path.Combine(checkDirectory, fileName)); checkFile = Path.Combine(checkDirectory, fileName); json = JsonSerializer.Serialize(faceCollectionsKeyValuePairs, writeIndentedJsonSerializerOptions); - _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, compareBeforeWrite: true); + _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true); } } } @@ -557,9 +558,9 @@ public class DlibDotNet private void FullDoWork(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string argZero, Dictionary> peopleCollection, PropertyLogic propertyLogic, List propertyHolderCollections) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); if (_AppSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(_AppSettings.MaxDegreeOfParallelism)); int g; int r; int exceptionCount; @@ -677,11 +678,11 @@ public class DlibDotNet { if (outputResolution == _Configuration.OutputResolutions[0] || _Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) { - PropertyHolder.AddToNamed(propertyLogic, filteredPropertyHolderCollection); for (int i = 0; i < faceCollections.Count; i++) - PropertyHolder.AddToFaces(filteredPropertyHolderCollection, (from l in faceCollections[i] select (object)l).ToArray()); + filteredPropertyHolderCollection[i].Faces.AddRange(from l in faceCollections[i] select l); + PropertyHolder.AddToNamed(propertyLogic, filteredPropertyHolderCollection); if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) - D_Face.SaveShortcuts(configuration, model, predictorModel, _Configuration.JuliePhares, peopleCollection, propertyLogic, outputResolution, filteredPropertyHolderCollection, faceCollections); + D_Face.SaveShortcuts(configuration, model, predictorModel, _Configuration.JuliePhares, ticks, peopleCollection, propertyLogic, outputResolution, filteredPropertyHolderCollection); } } if (exceptionCount == 0 && _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution)) @@ -707,7 +708,7 @@ public class DlibDotNet { propertyLogic.SaveAllCollection(); if (propertyLogic.NamedFaceInfoDeterministicHashCodeIndices.Any()) - E_Distance.SaveGroupedFaceEncodings(configuration, model, predictorModel, argZero, peopleCollection, outputResolution, propertyHolderCollections); + E_Distance.SaveGroupedFaceEncodings(configuration, model, predictorModel, argZero, ticks, peopleCollection, outputResolution, propertyHolderCollections); if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Any()) break; if (_Exceptions.Count == 0) @@ -731,9 +732,9 @@ public class DlibDotNet { PropertyLogic result; if (_AppSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(_AppSettings.MaxDegreeOfParallelism)); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); result = new(_AppSettings.MaxDegreeOfParallelism.Value, _Configuration.PropertyConfiguration); return result; } diff --git a/Instance/Models/Binder/Configuration.cs b/Instance/Models/Binder/Configuration.cs index d9f3daa..cfa51f6 100644 --- a/Instance/Models/Binder/Configuration.cs +++ b/Instance/Models/Binder/Configuration.cs @@ -24,7 +24,8 @@ public class Configuration [Display(Name = "Mixed Year Relative Paths"), Required] public string[] MixedYearRelativePaths { get; set; } [Display(Name = "Model Directory"), Required] public string ModelDirectory { get; set; } [Display(Name = "Model Name"), Required] public string ModelName { get; set; } - [Display(Name = "Num Jitters"), Required] public int? NumJitters { get; set; } + [Display(Name = "Number Jitters"), Required] public int? NumberOfJitters { get; set; } + [Display(Name = "Number of Times To Up Sample"), Required] public int? NumberOfTimesToUpsample { get; set; } [Display(Name = "Output Extension"), Required] public string OutputExtension { get; set; } [Display(Name = "Output Quality"), Required] public int? OutputQuality { get; set; } [Display(Name = "Output Resolutions"), Required] public string[] OutputResolutions { get; set; } @@ -68,7 +69,8 @@ public class Configuration MixedYearRelativePaths = Array.Empty(); ModelDirectory = string.Empty; ModelName = string.Empty; - NumJitters = null; + NumberOfJitters = null; + NumberOfTimesToUpsample = null; OutputExtension = string.Empty; OutputQuality = null; OutputResolutions = Array.Empty(); diff --git a/Instance/Models/Configuration.cs b/Instance/Models/Configuration.cs index bd7d4d0..91b0c8c 100644 --- a/Instance/Models/Configuration.cs +++ b/Instance/Models/Configuration.cs @@ -24,7 +24,8 @@ public class Configuration protected readonly string[] _MixedYearRelativePaths; protected readonly string _ModelDirectory; protected readonly string _ModelName; - protected readonly int? _NumJitters; + protected readonly int? _NumberOfJitters; + protected readonly int? _NumberOfTimesToUpsample; protected readonly string _OutputExtension; protected readonly int? _OutputQuality; protected readonly string[] _OutputResolutions; @@ -65,7 +66,8 @@ public class Configuration public string[] MixedYearRelativePaths => _MixedYearRelativePaths; public string ModelDirectory => _ModelDirectory; public string ModelName => _ModelName; - public int? NumJitters => _NumJitters; + public int? NumberOfJitters => _NumberOfJitters; + public int? NumberOfTimesToUpsample => _NumberOfTimesToUpsample; public string OutputExtension => _OutputExtension; public int? OutputQuality => _OutputQuality; public string[] OutputResolutions => _OutputResolutions; @@ -90,7 +92,7 @@ public class Configuration public string[] ValidResolutions => _ValidResolutions; [JsonConstructor] - public Configuration(bool? checkJsonForDistanceResults, int? crossDirectoryMaxItemsInDistanceCollection, int? distanceFactor, bool? forceMetadataLastWriteTimeToCreationTime, bool? forceResizeLastWriteTimeToCreationTime, string[] ignoreExtensions, string[] ignoreRelativePaths, string[] juliePhares, string[] loadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions, string[] loadOrCreateThenSaveDistanceResultsForOutputResolutions, string[] loadOrCreateThenSaveImageFacesResultsForOutputResolutions, bool? loadOrCreateThenSaveIndex, int? locationConfidenceFactor, int? mappedMaxIndex, int? maxItemsInDistanceCollection, string[] mixedYearRelativePaths, string modelDirectory, string modelName, int? numJitters, 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, Property.Models.Configuration? propertyConfiguration, bool? reverse, string[] saveFaceLandmarkForOutputResolutions, bool? saveFullYearOfRandomFiles, bool? saveResizedSubfiles, string[] saveShortcutsForOutputResolutions, bool? skipSearch, bool? testDistanceResults, string[] validResolutions) + public Configuration(bool? checkJsonForDistanceResults, int? crossDirectoryMaxItemsInDistanceCollection, int? distanceFactor, bool? forceMetadataLastWriteTimeToCreationTime, bool? forceResizeLastWriteTimeToCreationTime, string[] ignoreExtensions, string[] ignoreRelativePaths, string[] juliePhares, string[] loadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions, 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, Property.Models.Configuration? propertyConfiguration, bool? reverse, string[] saveFaceLandmarkForOutputResolutions, bool? saveFullYearOfRandomFiles, bool? saveResizedSubfiles, string[] saveShortcutsForOutputResolutions, bool? skipSearch, bool? testDistanceResults, string[] validResolutions) { _CheckJsonForDistanceResults = checkJsonForDistanceResults; _CrossDirectoryMaxItemsInDistanceCollection = crossDirectoryMaxItemsInDistanceCollection; @@ -110,7 +112,8 @@ public class Configuration _MixedYearRelativePaths = mixedYearRelativePaths; _ModelDirectory = modelDirectory; _ModelName = modelName; - _NumJitters = numJitters; + _NumberOfJitters = numberOfJitters; + _NumberOfTimesToUpsample = numberOfTimesToUpsample; _OutputExtension = outputExtension; _OutputQuality = outputQuality; _OutputResolutions = outputResolutions; diff --git a/Instance/Models/_A2_People.cs b/Instance/Models/_A2_People.cs index c1083bc..0eaca2c 100644 --- a/Instance/Models/_A2_People.cs +++ b/Instance/Models/_A2_People.cs @@ -56,7 +56,7 @@ internal class A2_People _ = Directory.CreateDirectory(directoryFullName); jsonFile = Path.Combine(directoryFullName, $"{segments[1]}.json"); json = JsonSerializer.Serialize(keyValuePair.Value, _WriteIndentedJsonSerializerOptions); - if (!Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, compareBeforeWrite: true)) + if (!Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: true, compareBeforeWrite: true)) continue; } } @@ -65,7 +65,7 @@ internal class A2_People { Person[] results; if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); string rootDirectory = _Configuration.PropertyConfiguration.RootDirectory; string peopleRootDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A2_People)); string? rootResultsDirectory = Path.GetDirectoryName(Path.GetDirectoryName(peopleRootDirectory)); diff --git a/Instance/Models/_D2_FaceLandmark.cs b/Instance/Models/_D2_FaceLandmark.cs index 5908e66..82b7312 100644 --- a/Instance/Models/_D2_FaceLandmark.cs +++ b/Instance/Models/_D2_FaceLandmark.cs @@ -116,8 +116,10 @@ internal class D2_FaceLandmarks string parentCheck; const int pointSize = 2; FileInfo rotatedFileInfo; + DateTime? dateTime = null; long ticks = DateTime.Now.Ticks; List imageFiles = new(); + bool updateDateWhenMatches = false; string facesDirectory = Path.Combine(AngleBracketCollection[0].Replace("<>", "()"), propertyHolder.ImageFileNameWithoutExtension); string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize), nameof(D_Face) }; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); @@ -155,6 +157,11 @@ internal class D2_FaceLandmarks check = true; else if (dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) check = true; + if (check && !updateDateWhenMatches) + { + updateDateWhenMatches = dateTimes.Any() && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime; + dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); + } } if (check) SaveFaceLandmarkImages(faceCollections, imageFiles, pointSize, propertyHolder.ResizedFileInfo); diff --git a/Instance/Models/_D_Face.cs b/Instance/Models/_D_Face.cs index d82116b..53a717e 100644 --- a/Instance/Models/_D_Face.cs +++ b/Instance/Models/_D_Face.cs @@ -233,10 +233,12 @@ public class D_Face : Shared.Models.Properties.IFace, IFace if (!faceCollection[i].Populated || faceCollection[i]?.Location is null) continue; location = new Location(faceCollection[i].Location.Confidence, - faceCollection[i].Location.Bottom, - faceCollection[i].Location.Left, - faceCollection[i].Location.Right, - faceCollection[i].Location.Top); + faceCollection[i].Location.Bottom, + faceCollection[i].Location.Left, + faceCollection[i].Location.Right, + faceCollection[i].Location.Top, + source.Width, + source.Height); width = location.Right - location.Left; height = location.Bottom - location.Top; rectangle = new Rectangle(location.Left, location.Top, width, height); @@ -254,10 +256,11 @@ public class D_Face : Shared.Models.Properties.IFace, IFace List results = new(); if (_Configuration.PaddingLoops is null) throw new Exception(); - if (_Configuration.NumJitters is null) - throw new Exception(); + if (_Configuration.NumberOfJitters is null) + throw new ArgumentNullException(nameof(_Configuration.NumberOfJitters)); + if (_Configuration.NumberOfTimesToUpsample is null) + throw new ArgumentNullException(nameof(_Configuration.NumberOfTimesToUpsample)); List locations; - const int numberOfTimesToUpSample = 1; FaceRecognitionDotNet.Image? unknownImage = null; if (resizedFileInfo.Exists) { @@ -270,7 +273,7 @@ public class D_Face : Shared.Models.Properties.IFace, IFace else { FaceRecognition faceRecognition = FaceRecognition.Create(_ModelParameter); - locations = faceRecognition.FaceLocations(unknownImage, numberOfTimesToUpSample, _Model); + locations = faceRecognition.FaceLocations(_Model, unknownImage, _Configuration.NumberOfTimesToUpsample.Value, sortByPixelPercentage: true); if (!locations.Any()) results.Add(new D_Face(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, propertyHolder.RelativePath, i: null, location: null)); else @@ -279,10 +282,10 @@ public class D_Face : Shared.Models.Properties.IFace, IFace int width; int height; int padding; - int leftEyeX; - int leftEyeY; - int rightEyeX; - int rightEyeY; + int? leftEyeX; + int? leftEyeY; + int? rightEyeX; + int? rightEyeY; Bitmap rotated; string faceFile; Location location; @@ -291,12 +294,11 @@ public class D_Face : Shared.Models.Properties.IFace, IFace D_Face? face = null; Rectangle rectangle; double[] rawEncoding; - IEnumerable facePoints; Shared.Models.FaceEncoding faceEncoding; FaceRecognitionDotNet.Image? knownImage; FaceRecognitionDotNet.Image? rotatedImage; + List<(FacePart, FacePoint[])[]> facesLandmarks; List faceEncodings; - List>> faceLandmarks; using Bitmap source = unknownImage.ToBitmap(); padding = (int)((source.Width + source.Height) / 2 * .01); for (int i = 0; i < locations.Count; i++) @@ -304,16 +306,22 @@ public class D_Face : Shared.Models.Properties.IFace, IFace for (int p = 0; p <= _Configuration.PaddingLoops.Value; p++) { location = new(locations[i].Confidence, - locations[i].Bottom + (padding * p), - locations[i].Left - (padding * p), - locations[i].Right + (padding * p), - locations[i].Top - (padding * p)); - face = new D_Face(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, propertyHolder.RelativePath, i, location); + locations[i].Bottom + (padding * p), + locations[i].Left - (padding * p), + locations[i].Right + (padding * p), + locations[i].Top - (padding * p), + source.Width, + source.Height); + face = new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, propertyHolder.RelativePath, i, location); width = location.Right - location.Left; height = location.Bottom - location.Top; rectangle = new Rectangle(location.Left, location.Top, width, height); using (preRotated = new Bitmap(width, height)) { + leftEyeX = null; + leftEyeY = null; + rightEyeX = null; + rightEyeY = null; using (graphics = Graphics.FromImage(preRotated)) graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel); // source.Save(Path.Combine(_Configuration.RootDirectory, "source.jpg")); @@ -321,32 +329,40 @@ public class D_Face : Shared.Models.Properties.IFace, IFace using (knownImage = FaceRecognition.LoadImage(preRotated)) { if (knownImage is null || knownImage.IsDisposed) - throw new Exception($"{nameof(knownImage)} is null"); - faceLandmarks = faceRecognition.FaceLandmark(knownImage, faceLocations: null, _PredictorModel, _Model); + throw new ArgumentNullException(nameof(knownImage)); + facesLandmarks = faceRecognition.GetFaceLandmarkCollection(knownImage, _Configuration.NumberOfTimesToUpsample.Value, faceLocations: null, _PredictorModel, _Model); } - if (faceLandmarks.Count == 0 && p < _Configuration.PaddingLoops.Value) + if (facesLandmarks.Count == 0 && p < _Configuration.PaddingLoops.Value) continue; - else if (faceLandmarks.Count != 1) + else if (facesLandmarks.Count != 1) continue; - foreach (KeyValuePair> keyValuePair in faceLandmarks[0]) - face.FaceLandmarks.Add(keyValuePair.Key.ToString(), keyValuePair.Value.ToArray()); - if (!faceLandmarks[0].ContainsKey(FacePart.LeftEye) || !faceLandmarks[0].ContainsKey(FacePart.RightEye)) + foreach ((FacePart facePart, FacePoint[] facePoints) in facesLandmarks[0]) + { + face.FaceLandmarks.Add(facePart.ToString(), facePoints); + if (facePart is not FacePart.LeftEye and not FacePart.RightEye) + continue; + if (facePart is FacePart.LeftEye) + { + leftEyeX = (int)(from l in facePoints select l.X).Average(); + leftEyeY = (int)(from l in facePoints select l.Y).Average(); + } + if (facePart is FacePart.RightEye) + { + rightEyeX = (int)(from l in facePoints select l.X).Average(); + rightEyeY = (int)(from l in facePoints select l.Y).Average(); + } + } + if (rightEyeX is null || leftEyeX is null || rightEyeY is null || leftEyeY is null) continue; - facePoints = faceLandmarks[0][FacePart.LeftEye]; - leftEyeX = (int)(from l in facePoints select l.X).Average(); - leftEyeY = (int)(from l in facePoints select l.Y).Average(); - facePoints = faceLandmarks[0][FacePart.RightEye]; - rightEyeX = (int)(from l in facePoints select l.X).Average(); - rightEyeY = (int)(from l in facePoints select l.Y).Average(); - α = Shared.Models.Stateless.Methods.IFace.Getα(rightEyeX, leftEyeX, rightEyeY, leftEyeY); + α = Shared.Models.Stateless.Methods.IFace.Getα(rightEyeX.Value, leftEyeX.Value, rightEyeY.Value, leftEyeY.Value); using (rotated = RotateBitmap(preRotated, (float)α.Value)) { // rotated.Save(Path.Combine(_Configuration.RootDirectory, $"{p} - rotated.jpg")); using (rotatedImage = FaceRecognition.LoadImage(rotated)) { if (rotatedImage is null || rotatedImage.IsDisposed) - throw new Exception($"{nameof(rotatedImage)} is null"); - faceEncodings = faceRecognition.FaceEncodings(rotatedImage, knownFaceLocation: null, _Configuration.NumJitters.Value, _PredictorModel, _Model); + throw new ArgumentNullException(nameof(rotatedImage)); + faceEncodings = faceRecognition.FaceEncodings(rotatedImage, _Configuration.NumberOfTimesToUpsample.Value, knownFaceLocation: null, _Configuration.NumberOfJitters.Value, _PredictorModel, _Model); } if (faceEncodings.Count == 0 && p < _Configuration.PaddingLoops.Value) continue; @@ -366,10 +382,12 @@ public class D_Face : Shared.Models.Properties.IFace, IFace if (face is null || !face.Populated) { location = new(locations[i].Confidence, - locations[i].Bottom, - locations[i].Left, - locations[i].Right, - locations[i].Top); + locations[i].Bottom, + locations[i].Left, + locations[i].Right, + locations[i].Top, + source.Width, + source.Height); face = new D_Face(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, propertyHolder.RelativePath, i, location); results.Add(face); } @@ -427,7 +445,7 @@ public class D_Face : Shared.Models.Properties.IFace, IFace { results = JsonSerializer.Deserialize>(json); if (results is null) - throw new Exception($"{nameof(results)} is null"); + throw new ArgumentNullException(nameof(results)); for (int i = 0; i < results.Count; i++) { face = results[i]; @@ -448,14 +466,18 @@ public class D_Face : Shared.Models.Properties.IFace, IFace if (results is not null && checkForOutputResolutionChange) { json = JsonSerializer.Serialize(results, _WriteIndentedJsonSerializerOptions); - if (Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, compareBeforeWrite: true)) + bool updateDateWhenMatches = dateTimes.Any() && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime; + DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); + if (Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); } else if (results is null) { results = GetFaces(resizedFileInfo, propertyHolder, property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, facesDirectory); json = JsonSerializer.Serialize(results, _WriteIndentedJsonSerializerOptions); - if (Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, compareBeforeWrite: true)) + bool updateDateWhenMatches = dateTimes.Any() && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime; + DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); + if (Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) subFileTuples.Add(new Tuple(nameof(D_Face), DateTime.Now)); } return results; @@ -505,109 +527,20 @@ public class D_Face : Shared.Models.Properties.IFace, IFace SaveFaces(faceCollection, propertyHolder.ResizedFileInfo, imageFiles); } - private static List<(PropertyHolder, (string, D_Face?, (string, string, string, string))[])> GetCollection(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, PropertyLogic propertyLogic, string outputResolution, PropertyHolder[] filteredPropertyHolderCollection, List> faceCollections) - { - List<(PropertyHolder, (string, D_Face?, (string, string, string, string))[])> results = new(); - string[] keys; - string directory; - string personKey; - bool? isWrongYear; - TimeSpan timeSpan; - DateTime? birthDate; - string copyFileName; - string copyDirectory; - string? relativePath; - string isWrongYearFlag; - string shortcutFileName; - string subDirectoryName; - List indices = new(); - List faceCollection; - PropertyHolder propertyHolder; - List<(string, D_Face?, (string, string, string, string))> collection; - string dFacesContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "(_)"); - for (int i = 0; i < filteredPropertyHolderCollection.Length; i++) - { - indices.Clear(); - personKey = string.Empty; - copyFileName = string.Empty; - copyDirectory = string.Empty; - propertyHolder = filteredPropertyHolderCollection[i]; - if (propertyHolder.ImageFileInfo is null) - continue; - relativePath = Path.GetDirectoryName($"C:{propertyHolder.RelativePath}"); - if (string.IsNullOrEmpty(relativePath) || relativePath.Length < 3) - continue; - if (propertyHolder.Property?.Id is null || propertyHolder.MinimumDateTime is null || propertyHolder.ResizedFileInfo is null) - continue; - collection = new(); - if (!propertyLogic.NamedFaceInfoDeterministicHashCodeIndices.ContainsKey(propertyHolder.Property.Id.Value)) - { - faceCollection = new(); - directory = Path.Combine(dFacesContentDirectory, $"Unnamed{relativePath[2..]}"); - } - else - { - faceCollection = faceCollections[i]; - keys = propertyLogic.NamedFaceInfoDeterministicHashCodeIndices[propertyHolder.Property.Id.Value]; - (isWrongYear, _) = propertyHolder.Property.IsWrongYear(propertyHolder.ImageFileInfo.FullName, propertyHolder.MinimumDateTime.Value); - isWrongYearFlag = PropertyHolder.GetWrongYearFlag(isWrongYear); - subDirectoryName = $"{isWrongYearFlag}{propertyHolder.MinimumDateTime.Value:yyyy}"; - if (!faceCollection.Any()) - directory = Path.Combine(dFacesContentDirectory, $"None{relativePath[2..]}", subDirectoryName); - else if (keys.Length != 1) - directory = Path.Combine(dFacesContentDirectory, $"Not Supported{relativePath[2..]}", subDirectoryName); - else if (faceCollection.Count != 1) - directory = Path.Combine(dFacesContentDirectory, $"Many{relativePath[2..]}", subDirectoryName); - else - { - indices.Add(0); - personKey = keys[0]; - if (isWrongYear is not null && !isWrongYear.Value && personKey[..2] is "19" or "20") - { - birthDate = Shared.Models.Stateless.Methods.IPersonBirthday.Get(personKey); - if (birthDate.HasValue) - { - timeSpan = new(propertyHolder.MinimumDateTime.Value.Ticks - birthDate.Value.Ticks); - if (timeSpan.Ticks < 0) - subDirectoryName = "!---"; - else - subDirectoryName = $"^{Math.Floor(timeSpan.TotalDays / 365):000}"; - } - } - directory = Path.Combine(dFacesContentDirectory, "Shortcuts", personKey, subDirectoryName); - if (faceCollection[0].FaceEncoding is not null) - copyDirectory = Path.Combine(dFacesContentDirectory, "Images", personKey, subDirectoryName); - else - copyDirectory = Path.Combine(dFacesContentDirectory, "ImagesBut", personKey, subDirectoryName); - copyFileName = Path.Combine(copyDirectory, $"{propertyHolder.Property.Id.Value}{propertyHolder.ResizedFileInfo.Extension}"); - } - } - shortcutFileName = Path.Combine(directory, $"{propertyHolder.Property.Id.Value}.lnk"); - if (string.IsNullOrEmpty(personKey) || !indices.Any()) - collection.Add(new(personKey, null, (directory, copyDirectory, copyFileName, shortcutFileName))); - else - { - foreach (int index in indices) - collection.Add(new(personKey, faceCollection[index], (directory, copyDirectory, copyFileName, shortcutFileName))); - } - results.Add(new(propertyHolder, collection.ToArray())); - } - return results; - } - - internal static void SaveShortcuts(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string[] juliePhares, Dictionary> peopleCollection, PropertyLogic propertyLogic, string outputResolution, PropertyHolder[] filteredPropertyHolderCollection, List> faceCollections) + internal static void SaveShortcuts(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string[] juliePhares, long ticks, Dictionary> peopleCollection, PropertyLogic propertyLogic, string outputResolution, PropertyHolder[] filteredPropertyHolderCollection) { Person person; string fileName; string fullName; WindowsShortcut windowsShortcut; const string pattern = @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]"; - List<(PropertyHolder, (string, D_Face?, (string, string, string, string))[])> collections = GetCollection(configuration, model, predictorModel, propertyLogic, outputResolution, filteredPropertyHolderCollection, faceCollections); - foreach ((PropertyHolder propertyHolder, (string personKey, D_Face? face, (string, string, string, string))[] collection) in collections) + string dFacesContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), $"({ticks})"); + List<(PropertyHolder, (string, Shared.Models.Properties.IFace?, (string, string, string, string))[])> collections = PropertyHolder.GetCollection(propertyLogic, filteredPropertyHolderCollection, dFacesContentDirectory); + foreach ((PropertyHolder propertyHolder, (string personKey, Shared.Models.Properties.IFace? _, (string, string, string, string))[] collection) in collections) { if (collection.Length != 1) continue; - foreach ((string personKey, D_Face? face, (string directory, string copyDirectory, string copyFileName, string shortcutFileName)) in collection) + foreach ((string personKey, Shared.Models.Properties.IFace? _, (string directory, string copyDirectory, string copyFileName, string shortcutFileName)) in collection) { if (string.IsNullOrEmpty(personKey)) continue; @@ -619,7 +552,7 @@ public class D_Face : Shared.Models.Properties.IFace, IFace if (!string.IsNullOrEmpty(personKey) && peopleCollection.ContainsKey(personKey)) { person = peopleCollection[personKey][0]; - fullName = Regex.Replace($"{Shared.Models.Stateless.Methods.IPersonName.GetFullName(person.Name)}.txt", pattern, string.Empty); + fullName = string.Concat(Regex.Replace(Shared.Models.Stateless.Methods.IPersonName.GetFullName(person.Name), pattern, string.Empty), ".txt"); File.WriteAllText(Path.Combine(directory, fullName), string.Empty); } } diff --git a/Instance/Models/_E2_Navigate.cs b/Instance/Models/_E2_Navigate.cs index 4724136..dfc7460 100644 --- a/Instance/Models/_E2_Navigate.cs +++ b/Instance/Models/_E2_Navigate.cs @@ -38,7 +38,7 @@ internal class E2_Navigate private void DisplayTags(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string outputResolution, string[] directories, Dictionary directoryKeyValuePairs, string[] files, Dictionary fileKeyValuePairs) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); bool all = false; FileSystem fileSystem; string requestPath = "/RootResultsDirectory"; @@ -71,7 +71,7 @@ internal class E2_Navigate private void DisplayFaces(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string outputResolution, string selectedFileFullName) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); string requestPath = "/RootResultsDirectory"; string? rootResultsDirectory = Path.GetDirectoryName(Property.Models.Stateless.IResult.GetResultsGroupDirectory(configuration, nameof(B_Metadata))); if (string.IsNullOrEmpty(rootResultsDirectory)) @@ -95,9 +95,9 @@ internal class E2_Navigate { string result; if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); _Log.Warn(string.Concat("What is the new name for [", Path.GetFileName(subSourceDirectory), "]<", subSourceDirectory, ">?")); string? newDirectoryName = _Console.ReadLine(); _Log.Warn("Are you sure y[es] || n[o]?"); @@ -135,7 +135,7 @@ internal class E2_Navigate internal void Navigate(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string outputResolution) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); string[] subFiles; ConsoleKey consoleKey; string[] subDirectories; diff --git a/Instance/Models/_E3_Rename.cs b/Instance/Models/_E3_Rename.cs index 632d786..ccb171b 100644 --- a/Instance/Models/_E3_Rename.cs +++ b/Instance/Models/_E3_Rename.cs @@ -115,7 +115,7 @@ internal class E3_Rename { List results = new(); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); bool add; string to; bool exists; @@ -230,7 +230,7 @@ internal class E3_Rename internal void DirectoryRename(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string relativePath, string newDirectoryName) { if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); string json; FileInfo current; FileInfo fileInfo; @@ -299,7 +299,7 @@ internal class E3_Rename if (json.Contains(oldValue)) { json = json.Replace(oldValue, newValue); - if (!Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, compareBeforeWrite: true)) + if (!Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true)) continue; File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime); } diff --git a/Instance/Models/_E_Distance.cs b/Instance/Models/_E_Distance.cs index 320faa1..4b120b5 100644 --- a/Instance/Models/_E_Distance.cs +++ b/Instance/Models/_E_Distance.cs @@ -128,7 +128,7 @@ internal class E_Distance return result; } - private void LoadOrCreateThenSaveDistanceResultsForOutputResolutionsLoop(Property.Models.Configuration configuration, List> faceCollections, int subFilesCount, int i, List faceCollection, List locationIndicesCollection, List> subFileTuples, List faceEncodingCollection, List faceEncodingCollections, string fileNameWithoutExtension, string jsonDirectory, string tvsDirectory) + private void LoadOrCreateThenSaveDistanceResultsForOutputResolutionsLoop(Property.Models.Configuration configuration, List> faceCollections, int subFilesCount, int i, List faceCollection, List locationIndicesCollection, List> subFileTuples, List faceEncodingCollection, List faceEncodingCollections, string fileNameWithoutExtension, string jsonDirectory, string tvsDirectory, bool updateDateWhenMatches, DateTime? updateToWhenMatches) { string text; string json; @@ -144,7 +144,7 @@ internal class E_Distance orderedFaceCollection = GetOrderedNoFaceCollection(faceCollections, i, faceCollection[j]); json = JsonSerializer.Serialize(orderedFaceCollection, _WriteIndentedJsonSerializerOptions); jsonFile = Path.Combine(jsonDirectory, $"{j} - {fileNameWithoutExtension}.json"); - if (Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, compareBeforeWrite: true)) + if (Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: updateToWhenMatches)) subFileTuples.Add(new Tuple(nameof(E_Distance), DateTime.Now)); } else @@ -162,16 +162,16 @@ internal class E_Distance indicesAndValues = GetValues(faceCollections, locationIndicesCollection, faceDistances); orderedFaceCollection = GetOrderedFaceCollection(faceCollections, locationIndicesCollection, indicesAndValues); text = GetText(fileNameWithoutExtension, faceCollections, locationIndicesCollection, indicesAndValues); - if (Property.Models.Stateless.IPath.WriteAllText(tvsFile, text, compareBeforeWrite: true)) + if (Property.Models.Stateless.IPath.WriteAllText(tvsFile, text, updateDateWhenMatches, compareBeforeWrite: true)) subFileTuples.Add(new Tuple(nameof(E_Distance), DateTime.Now)); json = JsonSerializer.Serialize(orderedFaceCollection, _WriteIndentedJsonSerializerOptions); - if (Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, compareBeforeWrite: true)) + if (Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches, compareBeforeWrite: true)) subFileTuples.Add(new Tuple(nameof(E_Distance), DateTime.Now)); } } } - private void LoadOrCreateThenSaveDistanceResultsForOutputResolutions(Property.Models.Configuration configuration, PropertyHolder[] filteredPropertyHolderCollection, List> faceCollections, List directories) + private void LoadOrCreateThenSaveDistanceResultsForOutputResolutions(Property.Models.Configuration configuration, PropertyHolder[] filteredPropertyHolderCollection, List> faceCollections, List directories, bool updateDateWhenMatches, DateTime? updateToWhenMatches) { FileInfo? fileInfo; string fileNameWithoutExtension; @@ -190,7 +190,7 @@ internal class E_Distance if (fileInfo is null) continue; fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.FullName); - LoadOrCreateThenSaveDistanceResultsForOutputResolutionsLoop(configuration, faceCollections, filteredPropertyHolderCollection.Length, i, faceCollections[i], locationIndicesCollection, subFileTuples, faceEncodingCollection, faceEncodingCollections[i], fileNameWithoutExtension, directories[i][0], directories[i][1]); + LoadOrCreateThenSaveDistanceResultsForOutputResolutionsLoop(configuration, faceCollections, filteredPropertyHolderCollection.Length, i, faceCollections[i], locationIndicesCollection, subFileTuples, faceEncodingCollection, faceEncodingCollections[i], fileNameWithoutExtension, directories[i][0], directories[i][1], updateDateWhenMatches, updateToWhenMatches); } } @@ -204,8 +204,10 @@ internal class E_Distance FileInfo? fileInfo; bool check = false; string parentCheck; + DateTime? dateTime = null; FileInfo[] fileInfoCollection; string fileNameWithoutExtension; + bool updateDateWhenMatches = false; List directories = new(); System.IO.DirectoryInfo directoryInfo; System.IO.DirectoryInfo tvsDirectoryInfo; @@ -264,9 +266,14 @@ internal class E_Distance check = true; else if (dateTimes.Any() && dateTimes.Max() > directoryInfo.LastWriteTime) check = true; + if (check && !updateDateWhenMatches) + { + updateDateWhenMatches = dateTimes.Any() && directoryInfo.Exists && dateTimes.Max() > directoryInfo.LastWriteTime; + dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); + } } if (check) - LoadOrCreateThenSaveDistanceResultsForOutputResolutions(configuration, filteredPropertyHolderCollection, faceCollections, directories); + LoadOrCreateThenSaveDistanceResultsForOutputResolutions(configuration, filteredPropertyHolderCollection, faceCollections, directories, updateDateWhenMatches, updateToWhenMatches: dateTime); _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(directoryInfoCollection[0].Replace("<>", "()")); } @@ -335,7 +342,7 @@ internal class E_Distance _ = Directory.CreateDirectory(jsonDirectory); string json = JsonSerializer.Serialize(faceAndFaceDistanceCollection, _WriteIndentedJsonSerializerOptions); string jsonFile = Path.Combine(jsonDirectory, $"{k} - {fileNameWithoutExtension}.nosj"); - _ = Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, compareBeforeWrite: true); + _ = Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: true, compareBeforeWrite: true); } private static Tuple Get(FaceEncoding faceEncoding, (string, List, List) match) @@ -350,7 +357,7 @@ internal class E_Distance internal void LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string outputResolution) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); string? relativePath; Shared.Models.Face face; ParallelOptions parallelOptions = new(); @@ -401,87 +408,89 @@ internal class E_Distance } } - private static Dictionary> Convert(string argZero, List propertyHolderCollections) + public static double GetStandardDeviation(IEnumerable values, double average) { - Dictionary> results = new(); - string key; - string personKey; - bool? isWrongYear; - TimeSpan? timeSpan; - string isWrongYearFlag; - foreach (PropertyHolder[] propertyHolderCollection in propertyHolderCollections) - { - if (!propertyHolderCollection.Any()) - continue; - if (!propertyHolderCollection[0].SourceDirectory.StartsWith(argZero)) - continue; - foreach (PropertyHolder propertyHolder in propertyHolderCollection) - { - if (propertyHolder.ImageFileInfo is null || propertyHolder.Property is null || !propertyHolder.Named.Any()) - continue; - if (propertyHolder.Named.Count != 1 || propertyHolder.Faces.Count != 1) - continue; - for (int i = 0; i < propertyHolder.Named.Count; i++) - { - if (propertyHolder.MinimumDateTime is null) - continue; - if (propertyHolder.Faces[i] is not D_Face face) - continue; - timeSpan = propertyHolder.Named[i].TimeSpan; - personKey = propertyHolder.Named[i].PersonKey; - isWrongYear = propertyHolder.Named[i].IsWrongYear; - isWrongYearFlag = PropertyHolder.GetWrongYearFlag(isWrongYear); - if (timeSpan is null) - key = $"{personKey}\t{isWrongYearFlag}{propertyHolder.MinimumDateTime.Value:yyyy}"; - else if (timeSpan.Value.Ticks < 0) - key = $"{personKey}\t{isWrongYearFlag}!---"; - else - key = $"{personKey}\t^{Math.Floor(timeSpan.Value.TotalDays / 365):000}"; - if (!results.ContainsKey(key)) - results.Add(key, new()); - results[key].Add(new(personKey, face)); - } - } - } - return results; + double result = 0; + if (!values.Any()) + throw new Exception("Collection must have at least one value!"); + double sum = values.Sum(l => (l - average) * (l - average)); + result = Math.Sqrt(sum / values.Count()); + return result; } - internal static void SaveGroupedFaceEncodings(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string argZero, Dictionary> peopleCollection, string outputResolution, List propertyHolderCollections) + internal static void SaveGroupedFaceEncodings(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string argZero, long ticks, Dictionary> peopleCollection, string outputResolution, List propertyHolderCollections) { + double lcl; + double ucl; string json; + double average; + int lowestIndex; string checkFile; - string directory; + string personKey; + double lowestAverage; + double standardDeviation; + FaceEncoding faceEncoding; + List faceDistances; + List rawEncodings; Shared.Models.Person person; + List faceEncodings; List checkDirectories = new(); - List collection; const string pattern = @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]"; - Dictionary> keyValuePairs = Convert(argZero, propertyHolderCollections); - string eDistanceCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[_]"); - foreach (KeyValuePair> keyValuePair in keyValuePairs) + string eDistanceCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), $"[{ticks}]"); + List<(string, Shared.Models.PersonBirthday, Shared.Models.Properties.IFace)[]> collection = PropertyHolder.GetCollection(argZero, propertyHolderCollections, eDistanceCollectionDirectory); + foreach ((string, Shared.Models.PersonBirthday, Shared.Models.Properties.IFace)[] group in collection) { - collection = new(); + lowestIndex = 0; + rawEncodings = new(); + faceEncodings = new(); checkDirectories.Clear(); checkFile = string.Empty; - foreach ((string personKey, D_Face face) in keyValuePair.Value) + lowestAverage = double.MaxValue; + foreach ((string directory, Shared.Models.PersonBirthday personBirthday, Shared.Models.Properties.IFace @interface) in group) { + personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday); if (string.IsNullOrEmpty(personKey) || !peopleCollection.ContainsKey(personKey)) continue; + if (@interface is not D_Face face || !face.Populated) + continue; person = peopleCollection[personKey][0]; - directory = Path.Combine(eDistanceCollectionDirectory, $"{personKey}{keyValuePair.Key}"); - checkFile = Path.Combine(directory, Regex.Replace($"{Shared.Models.Stateless.Methods.IPersonName.GetFullName(person.Name)}.json", pattern, string.Empty)); + faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); + checkFile = string.Concat(directory, " - ", Regex.Replace(Shared.Models.Stateless.Methods.IPersonName.GetFullName(person.Name), pattern, string.Empty), ".json"); checkDirectories.Add(directory); - collection.Add(face); + faceEncodings.Add(faceEncoding); } - if (!string.IsNullOrEmpty(checkFile) && checkDirectories.Any()) + if (string.IsNullOrEmpty(checkFile) || !checkDirectories.Any() || faceEncodings.Count < 2) + continue; + foreach (string checkDirectory in checkDirectories.Distinct()) { - foreach (string checkDirectory in checkDirectories) - { - if (!Directory.Exists(checkDirectory)) - _ = Directory.CreateDirectory(checkDirectory); - } - json = JsonSerializer.Serialize(collection, new JsonSerializerOptions { WriteIndented = true }); - _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, compareBeforeWrite: true); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); } + for (int i = 0; i < faceEncodings.Count; i++) + { + faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncodings[i]); + average = faceDistances.Average(); + if (average > lowestAverage) + continue; + lowestIndex = i; + lowestAverage = average; + } + faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncodings[lowestIndex]); + average = faceDistances.Average(); + if (average != lowestAverage) + continue; + standardDeviation = GetStandardDeviation(faceDistances, average); + lcl = average - (standardDeviation * 3); + ucl = average + (standardDeviation * 3); + for (int i = 0; i < faceEncodings.Count; i++) + { + if (faceDistances[i] < lcl || faceDistances[i] > ucl) + continue; + rawEncodings.Add(faceEncodings[i].GetRawEncoding()); + } + // outOfControl = faceEncodings.Count - rawEncodings.Count; + json = JsonSerializer.Serialize(rawEncodings, new JsonSerializerOptions { WriteIndented = true }); + _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: true, compareBeforeWrite: true); } } diff --git a/Instance/Models/_F_Random.cs b/Instance/Models/_F_Random.cs index c9c980b..ff66d3f 100644 --- a/Instance/Models/_F_Random.cs +++ b/Instance/Models/_F_Random.cs @@ -29,7 +29,7 @@ internal class F_Random { bool result = false; if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); string? checkDirectory = Path.GetFullPath(directory); for (int i = 0; i < int.MaxValue; i++) { @@ -73,7 +73,7 @@ internal class F_Random relativePaths = (from l in relativePaths orderby random.NextDouble() select l).ToList(); jsonFile = Path.Combine(fRandomCollectionDirectory, $"{dateTime.AddDays(i):MM-dd}.json"); json = JsonSerializer.Serialize(relativePaths, _WriteIndentedJsonSerializerOptions); - _ = Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, compareBeforeWrite: false); + _ = Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: false, compareBeforeWrite: false); if (!_Configuration.SaveFullYearOfRandomFiles.Value) break; } @@ -83,7 +83,7 @@ internal class F_Random ignoreRelativePaths = (from l in ignoreRelativePaths orderby random.NextDouble() select l).ToList(); jsonFile = Path.Combine(fRandomCollectionDirectory, "01-01.txt"); json = JsonSerializer.Serialize(ignoreRelativePaths, _WriteIndentedJsonSerializerOptions); - _ = Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, compareBeforeWrite: false); + _ = Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: false, compareBeforeWrite: false); } } diff --git a/Instance/Models/_G2_Identify.cs b/Instance/Models/_G2_Identify.cs index bf4c07a..d0b0bec 100644 --- a/Instance/Models/_G2_Identify.cs +++ b/Instance/Models/_G2_Identify.cs @@ -103,7 +103,7 @@ public class G2_Identify : Shared.Models.Properties.IIdentify, IIdentify json = JsonSerializer.Serialize(resultKeyValuePairs, _WriteIndentedJsonSerializerOptions); if (!isEnvironment.DebuggerWasAttachedDuringConstructor) throw new Exception("Only allowed when debugger is attached during constructor!"); - _ = Property.Models.Stateless.IPath.WriteAllText(named.FullName, json, compareBeforeWrite: true); + _ = Property.Models.Stateless.IPath.WriteAllText(named.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true); } } @@ -221,7 +221,7 @@ public class G2_Identify : Shared.Models.Properties.IIdentify, IIdentify _ = Directory.CreateDirectory(directoryFullName); jsonFile = string.Concat(g2IdentifyCollectionDirectory, keyValuePair.Key, ".json"); json = JsonSerializer.Serialize(keyValuePair.Value, _WriteIndentedJsonSerializerOptions); - if (!Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, compareBeforeWrite: true)) + if (!Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: true, compareBeforeWrite: true)) continue; } } diff --git a/Instance/Models/_G_Index.cs b/Instance/Models/_G_Index.cs index bcb2848..86a54cc 100644 --- a/Instance/Models/_G_Index.cs +++ b/Instance/Models/_G_Index.cs @@ -99,7 +99,7 @@ public class G_Index : Shared.Models.Properties.IIndex, IIndex dateTime = (from l in dateTimes where l.HasValue select l.Value).Min(); indexInfo = new(dateTime, maxIndexPlusOne, tuple.Item1); json = JsonSerializer.Serialize(indexInfo, _WriteIndentedJsonSerializerOptions); - if (!Property.Models.Stateless.IPath.WriteAllText(tuple.Item2, json, compareBeforeWrite: true)) + if (!Property.Models.Stateless.IPath.WriteAllText(tuple.Item2, json, updateDateWhenMatches: true, compareBeforeWrite: true)) continue; } } @@ -114,7 +114,7 @@ public class G_Index : Shared.Models.Properties.IIndex, IIndex indices = (from l in tuple.Item2 select l.Value).ToArray(); directoryInfoCollection = Property.Models.Stateless.IResult.GetDirectoryInfoCollection(configuration, model, predictorModel, tuple.Item1, nameof(G_Index), outputResolution, includeResizeGroup: false, includeModel: false, includePredictorModel: false, contentDescription: string.Empty, singletonDescription: string.Empty, collectionDescription: "Unknown A"); json = JsonSerializer.Serialize(indices, _WriteIndentedJsonSerializerOptions); - if (!Property.Models.Stateless.IPath.WriteAllText(string.Concat(directoryInfoCollection[0].Replace("<>", "[]"), ".json"), json, compareBeforeWrite: true)) + if (!Property.Models.Stateless.IPath.WriteAllText(string.Concat(directoryInfoCollection[0].Replace("<>", "[]"), ".json"), json, updateDateWhenMatches: true, compareBeforeWrite: true)) continue; } } diff --git a/Instance/appsettings.Development.json b/Instance/appsettings.Development.json index dbec7cd..2df52bd 100644 --- a/Instance/appsettings.Development.json +++ b/Instance/appsettings.Development.json @@ -65,7 +65,8 @@ "MaxItemsInDistanceCollection": 50, "ModelDirectory": "C:/GitHub/dlib-models", "ModelName": "Hog", - "NumJitters": 1, + "NumberOfJitters": 1, + "NumberOfTimesToUpsample": 1, "OutputExtension": ".jpg", "OutputQuality": 95, "OverrideForFaceImages": false, diff --git a/Instance/appsettings.Staging.json b/Instance/appsettings.Staging.json index b22caa3..b98cb3a 100644 --- a/Instance/appsettings.Staging.json +++ b/Instance/appsettings.Staging.json @@ -65,7 +65,8 @@ "MaxItemsInDistanceCollection": 50, "ModelDirectory": "L:/GitHub/dlib-models", "ModelName": "Hog", - "NumJitters": 1, + "NumberOfJitters": 1, + "NumberOfTimesToUpsample": 1, "OutputExtension": ".jpg", "OutputQuality": 95, "OverrideForFaceImages": false, diff --git a/Instance/appsettings.json b/Instance/appsettings.json index 907c362..5c1042e 100644 --- a/Instance/appsettings.json +++ b/Instance/appsettings.json @@ -65,7 +65,8 @@ "MaxItemsInDistanceCollection": 50, "ModelDirectory": "C:/GitHub/dlib-models", "ModelName": "Hog", - "NumJitters": 1, + "NumberOfJitters": 1, + "NumberOfTimesToUpsample": 1, "OutputExtension": ".jpg", "OutputQuality": 95, "OverrideForFaceImages": false, diff --git a/Metadata/Models/B_Metadata.cs b/Metadata/Models/B_Metadata.cs index 1910154..6d8f8e7 100644 --- a/Metadata/Models/B_Metadata.cs +++ b/Metadata/Models/B_Metadata.cs @@ -39,7 +39,7 @@ public class B_Metadata { Dictionary>> results = new(); if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); try { object? @object; @@ -137,7 +137,9 @@ public class B_Metadata { dictionary = GetMetadataCollection(propertyHolder.ImageFileInfo.FullName); json = JsonSerializer.Serialize(dictionary, _WriteIndentedJsonSerializerOptions); - if (Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, compareBeforeWrite: true)) + bool updateDateWhenMatches = dateTimes.Any() && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime; + DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); + if (Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) { if (!_ForceMetadataLastWriteTimeToCreationTime && (!fileInfo.Exists || fileInfo.LastWriteTime == fileInfo.CreationTime)) subFileTuples.Add(new Tuple(nameof(B_Metadata), DateTime.Now)); diff --git a/Not-Copy-Copy/Not-Copy-Copy.cs b/Not-Copy-Copy/Not-Copy-Copy.cs index 8c2f6ba..d93d356 100644 --- a/Not-Copy-Copy/Not-Copy-Copy.cs +++ b/Not-Copy-Copy/Not-Copy-Copy.cs @@ -28,7 +28,7 @@ public class NotCopyCopy { } _AppSettings = appSettings; if (appSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(appSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(appSettings.MaxDegreeOfParallelism)); _IsEnvironment = isEnvironment; _Exceptions = new List(); _Log = Serilog.Log.ForContext(); @@ -43,7 +43,7 @@ public class NotCopyCopy PredictorModel? predictorModel = null; _Configuration = configuration; if (propertyConfiguration.PopulatePropertyId is null) - throw new Exception($"{nameof(propertyConfiguration.PopulatePropertyId)} is null!"); + throw new ArgumentNullException(nameof(propertyConfiguration.PopulatePropertyId)); if (!_IsEnvironment.Development) throw new Exception("This program only allows development environments!"); PropertyLogic propertyLogic = GetPropertyLogic(); @@ -100,22 +100,22 @@ public class NotCopyCopy private static void Verify(Models.Configuration configuration) { if (Path.GetPathRoot(configuration.SelectedSource) == configuration.SelectedSource) - throw new Exception($"{nameof(configuration.SelectedSource)} should have at least one level!"); + throw new ArgumentNullException(nameof(configuration.SelectedSource)); if (string.IsNullOrEmpty(configuration.CompareSource) || !Directory.Exists(configuration.CompareSource)) - throw new Exception($"{nameof(configuration.CompareSource)} must have a value and exits!"); + throw new ArgumentNullException(nameof(configuration.CompareSource)); if (string.IsNullOrEmpty(configuration.EmptyDestination) || Directory.Exists(configuration.EmptyDestination)) - throw new Exception($"{nameof(configuration.EmptyDestination)} can't exit!"); + throw new ArgumentNullException(nameof(configuration.EmptyDestination)); if (string.IsNullOrEmpty(configuration.SelectedSource) || !Directory.Exists(configuration.SelectedSource)) - throw new Exception($"{nameof(configuration.SelectedSource)} must have a value and exits!"); + throw new ArgumentNullException(nameof(configuration.SelectedSource)); if (configuration.SelectedSource.Length != configuration.CompareSource.Length) - throw new Exception($"{nameof(configuration.SelectedSource)} and {nameof(configuration.CompareSource)} must be the same length!"); + throw new ArgumentNullException(nameof(configuration.SelectedSource)); } private long LogDelta(long ticks, string methodName) { long result; if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); double delta = new TimeSpan(DateTime.Now.Ticks - ticks).TotalMilliseconds; _Log.Debug($"{methodName} took {Math.Floor(delta)} millisecond(s)"); result = DateTime.Now.Ticks; @@ -126,9 +126,9 @@ public class NotCopyCopy { PropertyLogic result; if (_AppSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(_AppSettings.MaxDegreeOfParallelism)); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); result = new(_AppSettings.MaxDegreeOfParallelism.Value, _Configuration.PropertyConfiguration); return result; } @@ -137,7 +137,7 @@ public class NotCopyCopy { List<(string Source, string[] Destination)> results = new(); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); string key; string fileName; A_Property? property; diff --git a/PrepareForOld/PrepareForOld.cs b/PrepareForOld/PrepareForOld.cs index ca28c10..0bca0c7 100644 --- a/PrepareForOld/PrepareForOld.cs +++ b/PrepareForOld/PrepareForOld.cs @@ -30,7 +30,7 @@ public class PrepareForOld string spellingB; _AppSettings = appSettings; if (appSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(appSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(appSettings.MaxDegreeOfParallelism)); _SpellingFindReplace = new(); _IsEnvironment = isEnvironment; _Exceptions = new List(); @@ -42,7 +42,7 @@ public class PrepareForOld Models.Configuration configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); Verify(configuration); if (propertyConfiguration.IgnoreExtensions is null) - throw new Exception($"{nameof(propertyConfiguration.IgnoreExtensions)} is null!"); + throw new ArgumentNullException(nameof(propertyConfiguration.IgnoreExtensions)); for (int i = 0; i < configuration.Spelling.Length; i++) { spellingA = configuration.Spelling[i]; @@ -109,7 +109,7 @@ public class PrepareForOld private static void Verify(Models.Configuration configuration) { if (configuration.Spelling is null || !configuration.Spelling.Any()) - throw new Exception($"{nameof(configuration.Spelling)} should have at least one!"); + throw new ArgumentNullException(nameof(configuration.Spelling)); } private static List GetExifCollection(string infoDirectory, string infoDirectoryExtra, bool checkDistinct) @@ -141,7 +141,7 @@ public class PrepareForOld { List<(int Index, long Ticks, string RelativeDirectory, string FileNameWithoutExtension, string Extension, string RegexResult)> results = new(); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); long ticks; string json; string extension; @@ -224,14 +224,14 @@ public class PrepareForOld private void SaveTabSeparatedValues(Property.Models.Configuration configuration, string aPropertySingletonDirectory) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); if (_AppSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(_AppSettings.MaxDegreeOfParallelism)); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); string? rootDirectoryParent = Path.GetDirectoryName(_Configuration.PropertyConfiguration.RootDirectory); if (string.IsNullOrEmpty(rootDirectoryParent)) - throw new Exception($"{nameof(rootDirectoryParent)} is null!"); + throw new ArgumentNullException(nameof(rootDirectoryParent)); int z = 0; int mappedIndex; int? propertyId; @@ -414,7 +414,7 @@ public class PrepareForOld JsonSerializerOptions jsonSerializerOptions = new() { WriteIndented = true }; Dictionary? source = JsonSerializer.Deserialize>(json); if (source is null) - throw new Exception($"{nameof(source)} is null!"); + throw new ArgumentNullException(nameof(source)); { int propertyId; foreach (KeyValuePair keyValuePair in source) @@ -469,12 +469,12 @@ public class PrepareForOld private void ReSaveJsonFiles() { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); string? rootDirectoryParent = Path.GetDirectoryName(_Configuration.PropertyConfiguration.RootDirectory); if (string.IsNullOrEmpty(rootDirectoryParent)) - throw new Exception($"{nameof(rootDirectoryParent)} is null!"); + throw new ArgumentNullException(nameof(rootDirectoryParent)); int z = 0; int propertyId; List missingIndices = new(); @@ -523,14 +523,14 @@ public class PrepareForOld private void CopyMissingImagesLogs() { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); string? rootDirectoryParent = Path.GetDirectoryName(_Configuration.PropertyConfiguration.RootDirectory); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); if (string.IsNullOrEmpty(rootDirectoryParent)) - throw new Exception($"{nameof(rootDirectoryParent)} is null!"); + throw new ArgumentNullException(nameof(rootDirectoryParent)); int z = 0; int propertyId; Dictionary findReplace = new(); @@ -591,14 +591,14 @@ public class PrepareForOld private void VerifyAgainstIndexInfoJsonFiles(Property.Models.Configuration configuration, string aPropertySingletonDirectory) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); if (_AppSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(_AppSettings.MaxDegreeOfParallelism)); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); string? rootDirectoryParent = Path.GetDirectoryName(_Configuration.PropertyConfiguration.RootDirectory); if (string.IsNullOrEmpty(rootDirectoryParent)) - throw new Exception($"{nameof(rootDirectoryParent)} is null!"); + throw new ArgumentNullException(nameof(rootDirectoryParent)); int z = 0; int? propertyId; long? propertyTicks; diff --git a/Property-Compare/Models/PropertyCompareLogic.cs b/Property-Compare/Models/PropertyCompareLogic.cs index cada82e..6e45e5f 100644 --- a/Property-Compare/Models/PropertyCompareLogic.cs +++ b/Property-Compare/Models/PropertyCompareLogic.cs @@ -33,7 +33,7 @@ public class PropertyCompareLogic { List results = new(); if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); int index; string value; long[] distinctNumberValues; @@ -81,7 +81,7 @@ public class PropertyCompareLogic { List fromThenToCollection = new(); if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); int z = 0; string to; string from; @@ -177,7 +177,7 @@ public class PropertyCompareLogic string json = File.ReadAllText(jsonFile); A_Property? property = JsonSerializer.Deserialize(json); if (property?.Id is null) - throw new Exception($"{nameof(property)} is null!"); + throw new ArgumentNullException(nameof(property)); DateTime minimumDateTime = Property.Models.Stateless.A_Property.GetMinimumDateTime(property); corrected = string.Concat(relativeDirectory, jsonFileNameWithoutExtension); if (_SpellingFindReplace is not null && (from l in _SpellingFindReplace where corrected.Contains(l.Find) select true).Any()) @@ -251,7 +251,7 @@ public class PropertyCompareLogic { List results = new(); if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); string[] files; int totalSeconds; string directory; @@ -319,7 +319,7 @@ public class PropertyCompareLogic private void MoveFiles(string[] directories, List fromThenToCollection) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); int z; string to; string from; @@ -406,7 +406,7 @@ public class PropertyCompareLogic public void SaveDiffFiles(string aPropertyCollectionDirectory, int loadLessThan, PropertyCompare[] propertyCompares, PropertyCompare[]? diffPropertyCompares) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); string text; string[] lines; string fileName; @@ -459,7 +459,7 @@ public class PropertyCompareLogic public void SaveLogAndMoveFiles(string aPropertyCollectionDirectory, int loadLessThan, PropertyCompare[] propertyCompares, PropertyCompare[]? diffPropertyCompares, int i) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); List lines; string checkDirectory; string[] toDirectories; @@ -498,7 +498,7 @@ public class PropertyCompareLogic public void WithSubdirectory(string propertyDirectory, bool subDirectoriesAny, string fileName, bool renameCompare, bool deleteArg) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); List fileCollection = new(); if (renameCompare && deleteArg) throw new Exception(); diff --git a/Property/Models/Configuration.cs b/Property/Models/Configuration.cs index fedca39..90f7588 100644 --- a/Property/Models/Configuration.cs +++ b/Property/Models/Configuration.cs @@ -65,37 +65,37 @@ public class Configuration public static void Verify(Configuration? propertyConfiguration) { if (propertyConfiguration is null) - throw new Exception($"{nameof(propertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(propertyConfiguration)); if (propertyConfiguration.ForcePropertyLastWriteTimeToCreationTime is null) - throw new Exception($"{nameof(propertyConfiguration.ForcePropertyLastWriteTimeToCreationTime)} must be set!"); + throw new ArgumentNullException(nameof(propertyConfiguration.ForcePropertyLastWriteTimeToCreationTime)); if (propertyConfiguration.IgnoreExtensions is null || !propertyConfiguration.IgnoreExtensions.Any()) - throw new Exception($"{nameof(propertyConfiguration.IgnoreExtensions)} must be set!"); + throw new ArgumentNullException(nameof(propertyConfiguration.IgnoreExtensions)); if (propertyConfiguration.PopulatePropertyId is null) - throw new Exception($"{nameof(propertyConfiguration.PopulatePropertyId)} must be set!"); + throw new ArgumentNullException(nameof(propertyConfiguration.PopulatePropertyId)); if (propertyConfiguration.PropertiesChangedForProperty is null) - throw new Exception($"{nameof(propertyConfiguration.PropertiesChangedForProperty)} must be set!"); + throw new ArgumentNullException(nameof(propertyConfiguration.PropertiesChangedForProperty)); if (propertyConfiguration.PropertyContentCollectionFiles is null) - throw new Exception($"{nameof(propertyConfiguration.PropertyContentCollectionFiles)} must be set!"); + throw new ArgumentNullException(nameof(propertyConfiguration.PropertyContentCollectionFiles)); if (propertyConfiguration.ValidImageFormatExtensions is null || !propertyConfiguration.ValidImageFormatExtensions.Any()) - throw new Exception($"{nameof(propertyConfiguration.ValidImageFormatExtensions)} must be set!"); + throw new ArgumentNullException(nameof(propertyConfiguration.ValidImageFormatExtensions)); if (propertyConfiguration.ValidMetadataExtensions is null || !propertyConfiguration.ValidMetadataExtensions.Any()) - throw new Exception($"{nameof(propertyConfiguration.ValidMetadataExtensions)} must be set!"); + throw new ArgumentNullException(nameof(propertyConfiguration.ValidMetadataExtensions)); if (propertyConfiguration.VerifyToSeason is null || !propertyConfiguration.VerifyToSeason.Any()) - throw new Exception($"{nameof(propertyConfiguration.VerifyToSeason)} must be set!"); + throw new ArgumentNullException(nameof(propertyConfiguration.VerifyToSeason)); if (propertyConfiguration.WriteBitmapDataBytes is null) - throw new Exception($"{nameof(propertyConfiguration.WriteBitmapDataBytes)} must be set!"); + throw new ArgumentNullException(nameof(propertyConfiguration.WriteBitmapDataBytes)); if (Path.GetPathRoot(propertyConfiguration.RootDirectory) == propertyConfiguration.RootDirectory) - throw new Exception($"{nameof(propertyConfiguration.RootDirectory)} should have at least one level!"); + throw new ArgumentNullException(nameof(propertyConfiguration.RootDirectory)); if (propertyConfiguration is null) - throw new Exception($"{nameof(propertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(propertyConfiguration)); if (string.IsNullOrEmpty(propertyConfiguration.DateGroup)) - throw new Exception($"{nameof(propertyConfiguration.DateGroup)} must have a value!"); + throw new ArgumentNullException(nameof(propertyConfiguration.DateGroup)); if (string.IsNullOrEmpty(propertyConfiguration.FileNameDirectorySeparator)) - throw new Exception($"{nameof(propertyConfiguration.FileNameDirectorySeparator)} must have a value!"); + throw new ArgumentNullException(nameof(propertyConfiguration.FileNameDirectorySeparator)); if (string.IsNullOrEmpty(propertyConfiguration.Pattern)) - throw new Exception($"{nameof(propertyConfiguration.Pattern)} must have a value!"); + throw new ArgumentNullException(nameof(propertyConfiguration.Pattern)); if (string.IsNullOrEmpty(propertyConfiguration.RootDirectory) || !Directory.Exists(propertyConfiguration.RootDirectory)) - throw new Exception($"{nameof(propertyConfiguration.RootDirectory)} must have a value and exits!"); + throw new ArgumentNullException(nameof(propertyConfiguration.RootDirectory)); } public void ChangeRootDirectory(string rootDirectory) => _RootDirectory = rootDirectory; diff --git a/Property/Models/PropertyHolder.cs b/Property/Models/PropertyHolder.cs index d5fb54e..ac523dd 100644 --- a/Property/Models/PropertyHolder.cs +++ b/Property/Models/PropertyHolder.cs @@ -1,4 +1,6 @@ using System.Text.Json.Serialization; +using View_by_Distance.Shared.Models; +using View_by_Distance.Shared.Models.Properties; namespace View_by_Distance.Property.Models; @@ -7,13 +9,13 @@ public class PropertyHolder protected readonly bool? _Abandoned; protected readonly bool? _Changed; - protected List _Faces; + protected List _Faces; protected readonly FileInfo? _ImageFileInfo; protected readonly string _ImageFileNameWithoutExtension; protected readonly int _G; protected DateTime? _MinimumDateTime; protected bool? _Moved; - protected List<(bool?, string, TimeSpan?)> _Named; + protected List<(bool?, DateTime, PersonBirthday, double?)> _Named; protected readonly bool? _NoJson; protected A_Property? _Property; protected readonly int _R; @@ -24,14 +26,14 @@ public class PropertyHolder protected bool? _ValidImageFormatExtension; public bool? Abandoned => _Abandoned; public bool? Changed => _Changed; - public List Faces => _Faces; + public List Faces => _Faces; public FileInfo? ImageFileInfo => _ImageFileInfo; public string ImageFileNameWithoutExtension => _ImageFileNameWithoutExtension; public int G => _G; public DateTime? MinimumDateTime => _MinimumDateTime; public bool? Moved => _Moved; public bool? NoJson => _NoJson; - public List<(bool? IsWrongYear, string PersonKey, TimeSpan? TimeSpan)> Named => _Named; + public List<(bool? isWrongYear, DateTime minimumDateTime, PersonBirthday personBirthday, double? pixelPercentage)> Named => _Named; public A_Property? Property => _Property; public int R => _R; public string RelativePath => _RelativePath; @@ -96,20 +98,15 @@ public class PropertyHolder _MinimumDateTime = Stateless.A_Property.GetMinimumDateTime(property); } - public static void AddToFaces(PropertyHolder[] filteredPropertyHolderCollection, object[] faces) - { - foreach (PropertyHolder propertyHolder in filteredPropertyHolderCollection) - propertyHolder.Faces.AddRange(faces); - } - public static void AddToNamed(PropertyLogic propertyLogic, PropertyHolder[] filteredPropertyHolderCollection) { bool? isWrongYear; - TimeSpan? timeSpan; - DateTime? birthDate; + string[] segments; string[] personKeys; + double? pixelPercentage; DateTime minimumDateTime; PropertyHolder propertyHolder; + PersonBirthday? personBirthday; for (int i = 0; i < filteredPropertyHolderCollection.Length; i++) { propertyHolder = filteredPropertyHolderCollection[i]; @@ -122,21 +119,187 @@ public class PropertyHolder minimumDateTime = Stateless.A_Property.GetMinimumDateTime(propertyHolder.Property); personKeys = propertyLogic.NamedFaceInfoDeterministicHashCodeIndices[propertyHolder.Property.Id.Value]; (isWrongYear, _) = propertyHolder.Property.IsWrongYear(propertyHolder.ImageFileInfo.FullName, minimumDateTime); - foreach (string personKey in personKeys) + for (int j = 0; j < personKeys.Length; j++) { - if (isWrongYear is null || isWrongYear.Value || personKey[..2] is not "19" and not "20") - timeSpan = null; + segments = Shared.Models.Stateless.Methods.IPersonBirthday.GetSegments(personKeys[j]); + personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKeys[j]); + if (personBirthday is null) + continue; + if (segments.Length <= 1 || !double.TryParse(segments[1], out double value)) + pixelPercentage = null; else - { - birthDate = Shared.Models.Stateless.Methods.IPersonBirthday.Get(personKey); - if (birthDate is null) - timeSpan = null; - else - timeSpan = new(minimumDateTime.Ticks - birthDate.Value.Ticks); - } - propertyHolder.Named.Add(new(isWrongYear, personKey, timeSpan)); + pixelPercentage = value; + propertyHolder.Named.Add(new(isWrongYear, minimumDateTime, personBirthday, pixelPercentage)); } } } + public static List<(PropertyHolder, (string, IFace?, (string, string, string, string))[])> GetCollection(PropertyLogic propertyLogic, PropertyHolder[] filteredPropertyHolderCollection, string dFacesContentDirectory) + { + List<(PropertyHolder, (string, IFace?, (string, string, string, string))[])> results = new(); + string[] keys; + string directory; + string personKey; + bool? isWrongYear; + string[] segments; + const int zero = 0; + TimeSpan? timeSpan; + string copyFileName; + string copyDirectory; + string? relativePath; + string isWrongYearFlag; + string shortcutFileName; + string subDirectoryName; + List indices = new(); + List faceCollection; + PropertyHolder propertyHolder; + PersonBirthday? personBirthday; + List<(string, IFace?, (string, string, string, string))> collection; + for (int i = 0; i < filteredPropertyHolderCollection.Length; i++) + { + indices.Clear(); + personKey = string.Empty; + copyFileName = string.Empty; + copyDirectory = string.Empty; + propertyHolder = filteredPropertyHolderCollection[i]; + if (propertyHolder.ImageFileInfo is null) + continue; + relativePath = Path.GetDirectoryName($"C:{propertyHolder.RelativePath}"); + if (string.IsNullOrEmpty(relativePath) || relativePath.Length < 3) + continue; + if (propertyHolder.Property?.Id is null || propertyHolder.MinimumDateTime is null || propertyHolder.ResizedFileInfo is null) + continue; + collection = new(); + if (!propertyLogic.NamedFaceInfoDeterministicHashCodeIndices.ContainsKey(propertyHolder.Property.Id.Value)) + { + faceCollection = new(); + directory = Path.Combine(dFacesContentDirectory, $"Unnamed{relativePath[2..]}"); + } + else + { + faceCollection = propertyHolder.Faces; + keys = propertyLogic.NamedFaceInfoDeterministicHashCodeIndices[propertyHolder.Property.Id.Value]; + (isWrongYear, _) = propertyHolder.Property.IsWrongYear(propertyHolder.ImageFileInfo.FullName, propertyHolder.MinimumDateTime.Value); + isWrongYearFlag = GetWrongYearFlag(isWrongYear); + subDirectoryName = $"{isWrongYearFlag}{propertyHolder.MinimumDateTime.Value:yyyy}"; + if (!faceCollection.Any()) + directory = Path.Combine(dFacesContentDirectory, $"None{relativePath[2..]}", subDirectoryName); + else if (keys.Length != 1) + directory = Path.Combine(dFacesContentDirectory, $"Not Supported{relativePath[2..]}", subDirectoryName); + else if (faceCollection.Count != 1) + directory = Path.Combine(dFacesContentDirectory, $"Many{relativePath[2..]}", subDirectoryName); + else + { + indices.Add(zero); + segments = Shared.Models.Stateless.Methods.IPersonBirthday.GetSegments(keys[zero]); + personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(keys[zero]); + if (personBirthday is null) + continue; + timeSpan = Shared.Models.Stateless.Methods.IPersonBirthday.GetTimeSpan(propertyHolder.MinimumDateTime.Value, isWrongYear, personBirthday); + if (timeSpan.HasValue) + { + if (timeSpan.Value.Ticks < 0) + subDirectoryName = "!---"; + else + subDirectoryName = $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}"; + } + personKey = segments[zero]; + directory = Path.Combine(dFacesContentDirectory, "Shortcuts", personKey, subDirectoryName); + if (faceCollection[zero].Populated) + copyDirectory = Path.Combine(dFacesContentDirectory, "Images", personKey, subDirectoryName); + else + copyDirectory = Path.Combine(dFacesContentDirectory, "ImagesBut", personKey, subDirectoryName); + copyFileName = Path.Combine(copyDirectory, $"{propertyHolder.Property.Id.Value}{propertyHolder.ResizedFileInfo.Extension}"); + } + } + shortcutFileName = Path.Combine(directory, $"{propertyHolder.Property.Id.Value}.lnk"); + if (string.IsNullOrEmpty(personKey) || !indices.Any()) + collection.Add(new(personKey, null, (directory, copyDirectory, copyFileName, shortcutFileName))); + else + { + foreach (int index in indices) + collection.Add(new(personKey, faceCollection[index], (directory, copyDirectory, copyFileName, shortcutFileName))); + } + results.Add(new(propertyHolder, collection.ToArray())); + } + return results; + } + + private static Dictionary> GetKeyValuePairs(string argZero, List propertyHolderCollections, string eDistanceCollectionDirectory) + { + Dictionary> results = new(); + string key; + string personKey; + TimeSpan? timeSpan; + string[] directories; + string isWrongYearFlag; + string facePopulatedKey; + foreach (PropertyHolder[] propertyHolderCollection in propertyHolderCollections) + { + if (!propertyHolderCollection.Any()) + continue; + if (!propertyHolderCollection[0].SourceDirectory.StartsWith(argZero)) + continue; + foreach (PropertyHolder propertyHolder in propertyHolderCollection) + { + if (propertyHolder.ImageFileInfo is null || propertyHolder.Property is null || !propertyHolder.Named.Any()) + continue; + foreach ((bool? isWrongYear, DateTime minimumDateTime, PersonBirthday personBirthday, double? pixelPercentage) in propertyHolder.Named) + { + if (propertyHolder.MinimumDateTime is null) + continue; + if (pixelPercentage is null && (propertyHolder.Named.Count != 1 || propertyHolder.Faces.Count != 1)) + continue; + foreach (IFace face in propertyHolder.Faces) + { + if (pixelPercentage.HasValue && pixelPercentage.Value != face.Location.PixelPercentage) + continue; + personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday); + timeSpan = Shared.Models.Stateless.Methods.IPersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday); + if (face.Populated) + facePopulatedKey = "Images"; + else + facePopulatedKey = "ImagesBut"; + if (timeSpan.HasValue && timeSpan.Value.Ticks < 0) + directories = new string[] { string.Empty, facePopulatedKey, personKey, "!---" }; + else if (timeSpan.HasValue) + directories = new string[] { string.Empty, facePopulatedKey, personKey, $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}" }; + else + { + isWrongYearFlag = GetWrongYearFlag(isWrongYear); + directories = new string[] { string.Empty, facePopulatedKey, personKey, $"{isWrongYearFlag}{propertyHolder.MinimumDateTime.Value:yyyy}" }; + } + key = string.Join('\t', directories); + if (!results.ContainsKey(key)) + results.Add(key, new()); + directories[0] = eDistanceCollectionDirectory; + results[key].Add(new(directories, personBirthday, face)); + if (pixelPercentage is null) + break; + } + } + } + } + return results; + } + + public static List<(string, PersonBirthday, IFace)[]> GetCollection(string argZero, List propertyHolderCollections, string eDistanceCollectionDirectory) + { + List<(string, PersonBirthday, IFace)[]> results = new(); + string directory; + List<(string, PersonBirthday, IFace)> group; + Dictionary> keyValuePairs = GetKeyValuePairs(argZero, propertyHolderCollections, eDistanceCollectionDirectory); + foreach (KeyValuePair> keyValuePair in keyValuePairs) + { + group = new(); + foreach ((string[] directories, PersonBirthday personBirthday, IFace face) in keyValuePair.Value) + { + directory = Path.Combine(directories); + group.Add(new(directory, personBirthday, face)); + } + results.Add(group.ToArray()); + } + return results; + } + } \ No newline at end of file diff --git a/Property/Models/PropertyLogic.cs b/Property/Models/PropertyLogic.cs index 36e1199..74c3ba0 100644 --- a/Property/Models/PropertyLogic.cs +++ b/Property/Models/PropertyLogic.cs @@ -57,7 +57,7 @@ public class PropertyLogic Dictionary? sixCharacterNamedFaceInfo; string? rootDirectoryParent = Path.GetDirectoryName(configuration.RootDirectory); if (string.IsNullOrEmpty(rootDirectoryParent)) - throw new Exception($"{nameof(rootDirectoryParent)} is null!"); + throw new ArgumentNullException(nameof(rootDirectoryParent)); files = Directory.GetFiles(rootDirectoryParent, "*DeterministicHashCode*.json", SearchOption.TopDirectoryOnly); if (files.Length != 1) namedFaceInfoDeterministicHashCodeIndices = new(); @@ -66,7 +66,7 @@ public class PropertyLogic json = File.ReadAllText(files[0]); namedFaceInfoDeterministicHashCodeIndices = JsonSerializer.Deserialize>(json); if (namedFaceInfoDeterministicHashCodeIndices is null) - throw new Exception($"{nameof(namedFaceInfoDeterministicHashCodeIndices)} is null!"); + throw new ArgumentNullException(nameof(namedFaceInfoDeterministicHashCodeIndices)); } if (namedFaceInfoDeterministicHashCodeIndices.Any()) sixCharacterNamedFaceInfo = new(); @@ -80,7 +80,7 @@ public class PropertyLogic json = File.ReadAllText(files[0]); sixCharacterNamedFaceInfo = JsonSerializer.Deserialize>(json); if (sixCharacterNamedFaceInfo is null) - throw new Exception($"{nameof(sixCharacterNamedFaceInfo)} is null!"); + throw new ArgumentNullException(nameof(sixCharacterNamedFaceInfo)); } } files = Directory.GetFiles(rootDirectoryParent, "*keyValuePairs*.json", SearchOption.TopDirectoryOnly); @@ -91,7 +91,7 @@ public class PropertyLogic json = File.ReadAllText(files[0]); keyValuePairs = JsonSerializer.Deserialize>(json); if (keyValuePairs is null) - throw new Exception($"{nameof(keyValuePairs)} is null!"); + throw new ArgumentNullException(nameof(keyValuePairs)); } foreach (string propertyContentCollectionFile in configuration.PropertyContentCollectionFiles) { @@ -103,7 +103,7 @@ public class PropertyLogic json = File.ReadAllText(fullPath); collection = JsonSerializer.Deserialize>>(json); if (collection is null) - throw new Exception($"{nameof(collection)} is null!"); + throw new ArgumentNullException(nameof(collection)); foreach (KeyValuePair keyValuePair in collection) { if (indicesFromNew.ContainsKey(keyValuePair.Key)) @@ -127,7 +127,7 @@ public class PropertyLogic { long result; if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); double delta = new TimeSpan(DateTime.Now.Ticks - ticks).TotalMilliseconds; _Log.Debug($"{methodName} took {Math.Floor(delta)} millisecond(s)"); result = DateTime.Now.Ticks; @@ -172,9 +172,9 @@ public class PropertyLogic { A_Property result; if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); if (_Configuration.WriteBitmapDataBytes is null) - throw new Exception($"{nameof(_Configuration.WriteBitmapDataBytes)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.WriteBitmapDataBytes)); long ticks; byte[] bytes; string value; @@ -340,11 +340,11 @@ public class PropertyLogic { A_Property? result; if (_Configuration.ForcePropertyLastWriteTimeToCreationTime is null) - throw new Exception($"{nameof(_Configuration.ForcePropertyLastWriteTimeToCreationTime)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.ForcePropertyLastWriteTimeToCreationTime)); if (_Configuration.PopulatePropertyId is null) - throw new Exception($"{nameof(_Configuration.PopulatePropertyId)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.PopulatePropertyId)); if (_Configuration.PropertiesChangedForProperty is null) - throw new Exception($"{nameof(_Configuration.PropertiesChangedForProperty)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.PropertiesChangedForProperty)); string json; int? id = null; List indices = new(); @@ -464,7 +464,7 @@ public class PropertyLogic throw new ArgumentException($"{propertyHolder.ImageFileInfo} is null!"); result = GetImageProperty(angleBracket, propertyHolder.ImageFileInfo, populateId, isIgnoreExtension, isValidImageFormatExtension, isValidMetadataExtensions, id, indices); json = JsonSerializer.Serialize(result, _WriteIndentedJsonSerializerOptions); - if (populateId && IPath.WriteAllText(fileInfo.FullName, json, compareBeforeWrite: true)) + if (populateId && IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true)) { if (!_Configuration.ForcePropertyLastWriteTimeToCreationTime.Value && (!fileInfo.Exists || fileInfo.LastWriteTime == fileInfo.CreationTime)) filteredSourceDirectoryFileTuples.Add(new Tuple(nameof(A_Property), DateTime.Now)); @@ -479,7 +479,7 @@ public class PropertyLogic else if (hasWrongYearProperty) { json = JsonSerializer.Serialize(result, _WriteIndentedJsonSerializerOptions); - if (IPath.WriteAllText(fileInfo.FullName, json, compareBeforeWrite: true)) + if (IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true)) { File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); fileInfo.Refresh(); @@ -493,7 +493,7 @@ public class PropertyLogic { bool result = false; if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); int season; string[] matches; string deleteFile; @@ -603,41 +603,10 @@ public class PropertyLogic return result; } - private void WriteGroup(int sourceDirectoryLength, PropertyHolder[] filteredPropertyHolderCollection, string angleBracket) - { - if (!(from l in filteredPropertyHolderCollection where l?.Property?.Width is null select true).Any()) - { - string key; - string json; - string checkFile; - string checkDirectory; - List> propertyCollectionKeyValuePairs = new(); - JsonSerializerOptions writeIndentedJsonSerializerOptions = new() { WriteIndented = false }; - (int level, List directories) = IPath.Get(_Configuration.RootDirectory, filteredPropertyHolderCollection[0].SourceDirectory); - string fileName = string.Concat(string.Join(_Configuration.FileNameDirectorySeparator, directories), ".json"); - foreach (PropertyHolder propertyHolder in filteredPropertyHolderCollection) - { - if (propertyHolder.Property is null) - continue; - if (propertyHolder.ImageFileInfo is null) - continue; - key = IPath.GetRelativePath(propertyHolder.ImageFileInfo.FullName, sourceDirectoryLength); - propertyCollectionKeyValuePairs.Add(new KeyValuePair(key, propertyHolder.Property)); - } - checkDirectory = IPath.GetDirectory(angleBracket, level, "[{}]"); - checkFile = Path.Combine(checkDirectory, fileName); - if (File.Exists(checkFile)) - File.Move(checkFile, Path.Combine(checkDirectory, fileName)); - checkFile = Path.Combine(checkDirectory, fileName); - json = JsonSerializer.Serialize(propertyCollectionKeyValuePairs, writeIndentedJsonSerializerOptions); - _ = IPath.WriteAllText(checkFile, json, compareBeforeWrite: true); - } - } - private void ParallelForWork(bool firstPass, string angleBracket, string sourceDirectory, List> filteredSourceDirectoryFileTuples, PropertyHolder propertyHolder) { if (propertyHolder.ImageFileInfo is null) - throw new Exception($"{nameof(propertyHolder.ImageFileInfo)} is null!"); + throw new ArgumentNullException(nameof(propertyHolder.ImageFileInfo)); A_Property property; List parseExceptions = new(); string extensionLowered = propertyHolder.ImageFileInfo.Extension.ToLower(); @@ -708,18 +677,18 @@ public class PropertyLogic public void ParallelWork(Configuration configuration, Model? model, PredictorModel? predictorModel, long ticks, List propertyHolderCollections, bool firstPass) { if (_Log is null) - throw new Exception($"{nameof(_Log)} is null!"); + throw new ArgumentNullException(nameof(_Log)); if (_Configuration.PopulatePropertyId is null) - throw new Exception($"{nameof(_Configuration.PopulatePropertyId)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.PopulatePropertyId)); int g; int r; int totalSeconds; + bool? anyFilesMoved; string angleBracket; string sourceDirectory; List exceptions = new(); PropertyHolder[] filteredPropertyHolderCollection; List> sourceDirectoryChanges = new(); - int sourceDirectoryLength = configuration.RootDirectory.Length; int propertyHolderCollectionsCount = propertyHolderCollections.Count; string propertyRoot = IResult.GetResultsGroupDirectory(configuration, nameof(A_Property)); foreach (PropertyHolder[] propertyHolderCollection in propertyHolderCollections) @@ -745,13 +714,10 @@ public class PropertyLogic throw new Exception(string.Concat("All in [", sourceDirectory, "]failed!")); if (exceptions.Count != 0) _ExceptionsDirectories.Add(sourceDirectory); - bool? anyFilesMoved; if (!firstPass || exceptions.Count != 0) anyFilesMoved = null; else anyFilesMoved = AnyFilesMoved(sourceDirectory, filteredPropertyHolderCollection); - if (exceptions.Count == 0 && !firstPass && _Configuration.PopulatePropertyId.Value && (anyFilesMoved is null || !anyFilesMoved.Value)) - WriteGroup(sourceDirectoryLength, filteredPropertyHolderCollection, angleBracket); if (Directory.GetFiles(propertyRoot, "*.txt", SearchOption.TopDirectoryOnly).Any()) { for (int y = 0; y < int.MaxValue; y++) @@ -843,7 +809,7 @@ public class PropertyLogic string[] keys; string? rootDirectoryParent = Path.GetDirectoryName(_Configuration.RootDirectory); if (string.IsNullOrEmpty(rootDirectoryParent)) - throw new Exception($"{nameof(rootDirectoryParent)} is null!"); + throw new ArgumentNullException(nameof(rootDirectoryParent)); Dictionary namedFaceInfoDeterministicHashCodeIndices = new(); List<(int, string[])> allCollection = _AllCollection.OrderBy(l => l.Item1).ToList(); foreach ((int deterministicHashCode, string[] values) in allCollection) @@ -859,7 +825,7 @@ public class PropertyLogic } string json = JsonSerializer.Serialize(namedFaceInfoDeterministicHashCodeIndices, new JsonSerializerOptions { WriteIndented = true }); string checkFile = Path.Combine(rootDirectoryParent, "NamedFaceInfoDeterministicHashCodeIndices.json"); - _ = IPath.WriteAllText(checkFile, json, compareBeforeWrite: true); + _ = IPath.WriteAllText(checkFile, json, updateDateWhenMatches: true, compareBeforeWrite: true); } } diff --git a/Property/Models/Stateless/A_Property.cs b/Property/Models/Stateless/A_Property.cs index 66e6f29..cec123a 100644 --- a/Property/Models/Stateless/A_Property.cs +++ b/Property/Models/Stateless/A_Property.cs @@ -119,7 +119,7 @@ public static class A_Property public static List<(int g, string sourceDirectory, FileInfo[] sourceDirectoryFiles, int r)> GetFileInfoGroupCollection(Models.Configuration configuration, bool reverse, string searchPattern, List topDirectories) { if (configuration.MaxImagesInDirectoryForTopLevelFirstPass is null) - throw new Exception($"{nameof(configuration.MaxImagesInDirectoryForTopLevelFirstPass)} is null!"); + throw new ArgumentNullException(nameof(configuration.MaxImagesInDirectoryForTopLevelFirstPass)); List<(int g, string sourceDirectory, FileInfo[] sourceDirectoryFiles, int r)> results = new(); List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)>? collection = GetGroupCollection(configuration.RootDirectory, searchPattern, topDirectories, configuration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse); foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) in collection) diff --git a/Property/Models/Stateless/IPath.cs b/Property/Models/Stateless/IPath.cs index 591d8cb..ef4f140 100644 --- a/Property/Models/Stateless/IPath.cs +++ b/Property/Models/Stateless/IPath.cs @@ -12,8 +12,8 @@ public interface IPath List TestStatic_GetDirectoryNames(string directory); static List GetDirectoryNames(string directory) => XPath.GetDirectoryNames(directory); - bool TestStatic_WriteAllText(string path, string contents, bool compareBeforeWrite); - static bool WriteAllText(string path, string contents, bool compareBeforeWrite) => XPath.WriteAllText(path, contents, compareBeforeWrite); + bool TestStatic_WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite); + static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches = null) => XPath.WriteAllText(path, contents, updateDateWhenMatches, compareBeforeWrite, updateToWhenMatches); (int level, List directories) TestStatic_Get(string rootDirectory, string sourceDirectory); static (int level, List directories) Get(string rootDirectory, string sourceDirectory) => XPath.Get(rootDirectory, sourceDirectory); diff --git a/Property/Models/Stateless/Path.cs b/Property/Models/Stateless/Path.cs index 184668c..5048328 100644 --- a/Property/Models/Stateless/Path.cs +++ b/Property/Models/Stateless/Path.cs @@ -46,7 +46,7 @@ internal class XPath return result; } - internal static bool WriteAllText(string path, string contents, bool compareBeforeWrite) + internal static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches) { bool result; string text; @@ -59,6 +59,13 @@ internal class XPath else text = File.ReadAllText(path); result = text != contents; + if (!result && updateDateWhenMatches) + { + if (updateToWhenMatches is null) + File.SetLastWriteTime(path, DateTime.Now); + else + File.SetLastWriteTime(path, updateToWhenMatches.Value); + } } if (result) { @@ -85,7 +92,7 @@ internal class XPath string? pathRoot = Path.GetPathRoot(directory); string extension = Path.GetExtension(directory); if (string.IsNullOrEmpty(pathRoot)) - throw new Exception($"{nameof(pathRoot)} is null!"); + throw new ArgumentNullException(nameof(pathRoot)); if (Directory.Exists(directory)) results.Add(Path.GetFileName(directory)); else if ((string.IsNullOrEmpty(extension) || extension.Length > 3) && !File.Exists(directory)) diff --git a/Resize/Models/_C_Resize.cs b/Resize/Models/_C_Resize.cs index 4c55769..334f3ff 100644 --- a/Resize/Models/_C_Resize.cs +++ b/Resize/Models/_C_Resize.cs @@ -485,7 +485,9 @@ public class C_Resize { results = GetImageResizes(property, metadataCollection, original); json = JsonSerializer.Serialize(results, _WriteIndentedJsonSerializerOptions); - if (Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, compareBeforeWrite: true)) + bool updateDateWhenMatches = dateTimes.Any() && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime; + DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); + if (Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) { if (!_ForceResizeLastWriteTimeToCreationTime && (!fileInfo.Exists || fileInfo.LastWriteTime == fileInfo.CreationTime)) subFileTuples.Add(new Tuple(nameof(C_Resize), DateTime.Now)); diff --git a/Shared/Models/Location.cs b/Shared/Models/Location.cs index c3b3dcb..e52213c 100644 --- a/Shared/Models/Location.cs +++ b/Shared/Models/Location.cs @@ -1,4 +1,3 @@ -using System.Drawing; using System.Text.Json; using System.Text.Json.Serialization; using View_by_Distance.Shared.Models.Methods; @@ -8,37 +7,40 @@ namespace View_by_Distance.Shared.Models; public class Location : Properties.ILocation, ILocation, IEquatable { + public double Confidence => _Confidence; protected double _Confidence; protected int _Bottom; protected int _Left; + protected double? _PixelPercentage; protected int _Right; protected int _Top; - public double Confidence => _Confidence; public int Bottom => _Bottom; public int Left => _Left; + public double? PixelPercentage => _PixelPercentage; public int Right => _Right; public int Top => _Top; [JsonConstructor] - public Location(double confidence, int bottom, int left, int right, int top) + public Location(double confidence, int bottom, int left, double? pixelPercentage, int right, int top) { _Confidence = confidence; _Bottom = bottom; _Left = left; + _PixelPercentage = pixelPercentage; _Right = right; _Top = top; } - public Location(int left, int top, int right, int bottom) : - this(-1.0d, bottom, left, right, top) + public Location(double confidence, int bottom, int left, int right, int top, int width, int height) : + this(confidence, bottom, left, GetPixelPercentage(bottom, left, right, top, width, height), right, top) { } - public Location(Rectangle rectangle, double confidence) : - this(-1.0d, rectangle.Bottom, rectangle.Left, rectangle.Right, rectangle.Top) + public Location(double confidence, Location location, int width, int height) : + this(confidence, location.Bottom, location.Left, location.Right, location.Top, width, height) { } - public Location(Location location, double confidence) : - this(-1.0d, location.Bottom, location.Left, location.Right, location.Top) + public Location(int left, int top, int right, int bottom, int width, int height) : + this(-1.0d, bottom, left, right, top, width, height) { } public override bool Equals(object? obj) => Equals(obj as Location); @@ -59,6 +61,15 @@ public class Location : Properties.ILocation, ILocation, IEquatable return hashCode; } + public static double GetPixelPercentage(int left, int top, int right, int bottom, int width, int height) + { + double result; + double xCenter = left + ((right - left) / 2); + double yCenter = top + ((bottom - top) / 2); + result = ((yCenter * width) + xCenter) / (width * height); + return (double)Math.Round((decimal)result, 4); + } + public bool Equals(Location? location) { return location is not null diff --git a/Shared/Models/Properties/IConfiguration.cs b/Shared/Models/Properties/IConfiguration.cs index a1ac3b2..2fa7554 100644 --- a/Shared/Models/Properties/IConfiguration.cs +++ b/Shared/Models/Properties/IConfiguration.cs @@ -26,7 +26,7 @@ // public int? mappedMaxIndex; // public int? maxImagesInDirectoryForTopLevelFirstPass; // public int? maxItemsInDistanceCollection; -// public int? numJitters; +// public int? numberOfJitters; // public int? outputQuality; // public int? paddingLoops; // public string dateGroup; diff --git a/Shared/Models/Stateless/FacePart.cs b/Shared/Models/Stateless/FacePart.cs index 30931b1..5d07928 100644 --- a/Shared/Models/Stateless/FacePart.cs +++ b/Shared/Models/Stateless/FacePart.cs @@ -9,51 +9,46 @@ public enum FacePart /// /// Specifies the chin. /// - Chin, + Chin = 0, /// /// Specifies the left eyebrow. /// - LeftEyebrow, + LeftEyebrow = 17, /// /// Specifies the right eyebrow. /// - RightEyebrow, + RightEyebrow = 22, /// /// Specifies the nose bridge. /// - NoseBridge, + NoseBridge = 27, /// /// Specifies the nose tip. /// - NoseTip, + NoseTip = 31, /// /// Specifies the left eye. /// - LeftEye, + LeftEye = 36, /// /// Specifies the right eye. /// - RightEye, + RightEye = 42, /// /// Specifies the top lip. /// - TopLip, + TopLip = 48, /// /// Specifies the bottom lip. /// - BottomLip, - - /// - /// Specifies the nose. - /// - Nose, + BottomLip = 55 } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IPersonBirthday.cs b/Shared/Models/Stateless/Methods/IPersonBirthday.cs index 234f7eb..ef6f60f 100644 --- a/Shared/Models/Stateless/Methods/IPersonBirthday.cs +++ b/Shared/Models/Stateless/Methods/IPersonBirthday.cs @@ -12,17 +12,23 @@ public interface IPersonBirthday string TestStatic_GetFormat() => PersonBirthday.GetFormat(); static string GetFormat() => PersonBirthday.GetFormat(); - Models.PersonBirthday TestStatic_GetNextBirthDate(Properties.IStorage storage) => PersonBirthday.GetNextBirthDate(storage); - static Models.PersonBirthday GetNextBirthDate(Properties.IStorage storage) => PersonBirthday.GetNextBirthDate(storage); + string[] TestStatic_GetSegments(string personKey) => PersonBirthday.GetSegments(personKey); + static string[] GetSegments(string personKey) => PersonBirthday.GetSegments(personKey); + + DateTime? TestStatic_GetDateTime(string personKey) => PersonBirthday.GetDateTime(personKey); + static DateTime? GetDateTime(string personKey) => PersonBirthday.GetDateTime(personKey); + + string TestStatic_GetFileName(Models.PersonBirthday personBirthday) => PersonBirthday.GetFileName(personBirthday); + static string GetFileName(Models.PersonBirthday personBirthday) => PersonBirthday.GetFileName(personBirthday); + + Models.PersonBirthday? TestStatic_GetPersonBirthday(string personKey) => PersonBirthday.GetPersonBirthday(personKey); + static Models.PersonBirthday? GetPersonBirthday(string personKey) => PersonBirthday.GetPersonBirthday(personKey); string TestStatic_GetFormatted(Models.PersonBirthday personBirthday) => PersonBirthday.GetFormatted(personBirthday); static string GetFormatted(Models.PersonBirthday personBirthday) => PersonBirthday.GetFormatted(personBirthday); - DateTime? TestStatic_Get(string personKey) => PersonBirthday.Get(personKey); - static DateTime? Get(string personKey) => PersonBirthday.Get(personKey); - - string TestStatic_GetFileName(Models.PersonBirthday personBirthday) => PersonBirthday.GetFileName(personBirthday); - static string GetFileName(Models.PersonBirthday personBirthday) => PersonBirthday.GetFileName(personBirthday); + Models.PersonBirthday TestStatic_GetNextBirthDate(Properties.IStorage storage) => PersonBirthday.GetNextBirthDate(storage); + static Models.PersonBirthday GetNextBirthDate(Properties.IStorage storage) => PersonBirthday.GetNextBirthDate(storage); bool TestStatic_DoesBirthDateExits(Properties.IStorage storage, Models.PersonBirthday personBirthday) => DoesBirthDateExits(storage, personBirthday); static bool DoesBirthDateExits(Properties.IStorage storage, Models.PersonBirthday personBirthday) => DoesBirthDateExits(storage, personBirthday); @@ -30,4 +36,7 @@ public interface IPersonBirthday string TestStatic_GetFileFullName(Properties.IStorage storage, Models.PersonBirthday personBirthday) => PersonBirthday.GetFileFullName(storage, personBirthday); static string GetFileFullName(Properties.IStorage storage, Models.PersonBirthday personBirthday) => PersonBirthday.GetFileFullName(storage, personBirthday); + TimeSpan? TestStatic_Get(DateTime minimumDateTime, bool? isWrongYear, Models.PersonBirthday personBirthday) => PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday); + static TimeSpan? GetTimeSpan(DateTime minimumDateTime, bool? isWrongYear, Models.PersonBirthday personBirthday) => PersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday); + } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IStorage.cs b/Shared/Models/Stateless/Methods/IStorage.cs index 340b432..9fb69b9 100644 --- a/Shared/Models/Stateless/Methods/IStorage.cs +++ b/Shared/Models/Stateless/Methods/IStorage.cs @@ -5,8 +5,8 @@ public interface IStorage // ... - bool TestStatic_WriteAllText(string path, string contents, bool compareBeforeWrite); - static bool WriteAllText(string path, string contents, bool compareBeforeWrite) => Storage.WriteAllText(path, contents, compareBeforeWrite); + bool TestStatic_WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite); + static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite) => Storage.WriteAllText(path, contents, updateDateWhenMatches, compareBeforeWrite); (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) TestStatic_GetTuple(Properties.IStorage storage); static (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) GetTuple(Properties.IStorage storage) => new(new Uri(storage.RootResultsDirectory).AbsoluteUri, Path.Combine(storage.ResizeRootDirectory, "()"), Path.Combine(storage.FaceRootDirectory, "()"), Path.Combine(storage.DistanceResultRootDirectory, "[]")); diff --git a/Shared/Models/Stateless/Methods/Person.cs b/Shared/Models/Stateless/Methods/Person.cs index c9a0d88..c8f9b3c 100644 --- a/Shared/Models/Stateless/Methods/Person.cs +++ b/Shared/Models/Stateless/Methods/Person.cs @@ -130,7 +130,7 @@ internal abstract class Person { string fileName = IPerson.GetFileFullName(storage, person); string json = JsonSerializer.Serialize(person, new JsonSerializerOptions { WriteIndented = true }); - _ = IStorage.WriteAllText(fileName, json, compareBeforeWrite: true); + _ = IStorage.WriteAllText(fileName, json, updateDateWhenMatches: true, compareBeforeWrite: true); } private static List GetPeopleFromText(Properties.IStorage storage, string localKnownPeopleFile) @@ -189,7 +189,7 @@ internal abstract class Person _ = Directory.CreateDirectory(directory); string? rootDirectoryParent = Path.GetDirectoryName(storage.RootDirectory); if (string.IsNullOrEmpty(rootDirectoryParent)) - throw new Exception($"{nameof(rootDirectoryParent)} is null!"); + throw new ArgumentNullException(nameof(rootDirectoryParent)); if (!Directory.Exists(rootDirectoryParent)) localKnownPeopleFile = string.Empty; else diff --git a/Shared/Models/Stateless/Methods/PersonBirthday.cs b/Shared/Models/Stateless/Methods/PersonBirthday.cs index 4404bae..985f7ca 100644 --- a/Shared/Models/Stateless/Methods/PersonBirthday.cs +++ b/Shared/Models/Stateless/Methods/PersonBirthday.cs @@ -10,10 +10,33 @@ internal abstract class PersonBirthday // ... internal static string GetFormat() => "yyyy-MM-dd_HH"; - internal static Models.PersonBirthday GetNextBirthDate(Properties.IStorage storage) => throw new Exception(storage.ToString()); // Person.GetNextBirthDate(storage); + internal static string[] GetSegments(string personKey) => personKey.Split('\t'); internal static string GetFormatted(Models.PersonBirthday personBirthday) => personBirthday.Value.ToString(GetFormat()); internal static string GetFileName(Models.PersonBirthday personBirthday) => $"{personBirthday.Value.ToString(GetFormat())}.json"; internal static bool DoesBirthDateExits(Properties.IStorage storage, Models.PersonBirthday personBirthday) => File.Exists(GetFileFullName(storage, personBirthday)); + internal static Models.PersonBirthday GetNextBirthDate(Properties.IStorage storage) => throw new Exception(storage.ToString()); // Person.GetNextBirthDate(storage); internal static string GetFileFullName(Properties.IStorage storage, Models.PersonBirthday personBirthday) => Path.Combine(storage.PeopleRootDirectory, "{}", GetFileName(personBirthday)); - internal static DateTime? Get(string personKey) => DateTime.TryParseExact(personKey, GetFormat(), CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime) ? dateTime : null; + internal static DateTime? GetDateTime(string personKey) => DateTime.TryParseExact(personKey, GetFormat(), CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime) ? dateTime : null; + + internal static Models.PersonBirthday? GetPersonBirthday(string personKey) + { + Models.PersonBirthday? result; + string[] segments = GetSegments(personKey); + DateTime? dateTime = GetDateTime(segments[0]); + if (dateTime is null) + result = null; + else + result = new(dateTime.Value); + return result; + } + + internal static TimeSpan? GetTimeSpan(DateTime minimumDateTime, bool? isWrongYear, Models.PersonBirthday personBirthday) + { + TimeSpan? timeSpan; + if (isWrongYear is null || isWrongYear.Value || personBirthday.Value.Year < 1900) + timeSpan = null; + else + timeSpan = new(minimumDateTime.Ticks - personBirthday.Value.Ticks); + return timeSpan; + } } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/Storage.cs b/Shared/Models/Stateless/Methods/Storage.cs index 94718ac..316c512 100644 --- a/Shared/Models/Stateless/Methods/Storage.cs +++ b/Shared/Models/Stateless/Methods/Storage.cs @@ -5,7 +5,7 @@ internal abstract class Storage // ... - internal static bool WriteAllText(string path, string contents, bool compareBeforeWrite) + internal static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite) { bool result; string text; @@ -18,9 +18,24 @@ internal abstract class Storage else text = File.ReadAllText(path); result = text != contents; + if (!result && updateDateWhenMatches) + File.SetLastWriteTime(path, DateTime.Now); } if (result) - File.WriteAllText(path, contents); + { + if (path.Contains("()")) + File.WriteAllText(path, contents); + else if (path.Contains("{}") && !path.EndsWith(".json")) + File.WriteAllText(path, contents); + else if (path.Contains("[]") && !path.EndsWith(".json")) + File.WriteAllText(path, contents); + else if (path.Contains("{}") && path.EndsWith(".json") && contents[0] == '{') + File.WriteAllText(path, contents); + else if (path.Contains("[]") && path.EndsWith(".json") && contents[0] == '[') + File.WriteAllText(path, contents); + else + File.WriteAllText(path, contents); + } return result; } diff --git a/Tests/Models/Binder/Configuration.cs b/Tests/Models/Binder/Configuration.cs index 9ecc447..9c890ba 100644 --- a/Tests/Models/Binder/Configuration.cs +++ b/Tests/Models/Binder/Configuration.cs @@ -24,7 +24,8 @@ public class Configuration [Display(Name = "Mixed Year Relative Paths"), Required] public string[] MixedYearRelativePaths { get; set; } [Display(Name = "Model Directory"), Required] public string ModelDirectory { get; set; } [Display(Name = "Model Name"), Required] public string ModelName { get; set; } - [Display(Name = "Num Jitters"), Required] public int? NumJitters { get; set; } + [Display(Name = "Number Jitters"), Required] public int? NumberOfJitters { get; set; } + [Display(Name = "Number of Times To Up Sample"), Required] public int? NumberOfTimesToUpsample { get; set; } [Display(Name = "Output Extension"), Required] public string OutputExtension { get; set; } [Display(Name = "Output Quality"), Required] public int? OutputQuality { get; set; } [Display(Name = "Output Resolutions"), Required] public string[] OutputResolutions { get; set; } @@ -68,7 +69,8 @@ public class Configuration MixedYearRelativePaths = Array.Empty(); ModelDirectory = string.Empty; ModelName = string.Empty; - NumJitters = null; + NumberOfJitters = null; + NumberOfTimesToUpsample = null; OutputExtension = string.Empty; OutputQuality = null; OutputResolutions = Array.Empty(); diff --git a/Tests/Models/Configuration.cs b/Tests/Models/Configuration.cs index 79f8fca..db73b3d 100644 --- a/Tests/Models/Configuration.cs +++ b/Tests/Models/Configuration.cs @@ -24,7 +24,8 @@ public class Configuration protected readonly string[] _MixedYearRelativePaths; protected readonly string _ModelDirectory; protected readonly string _ModelName; - protected readonly int? _NumJitters; + protected readonly int? _NumberOfJitters; + protected readonly int? _NumberOfTimesToUpsample; protected readonly string _OutputExtension; protected readonly int? _OutputQuality; protected readonly string[] _OutputResolutions; @@ -65,7 +66,8 @@ public class Configuration public string[] MixedYearRelativePaths => _MixedYearRelativePaths; public string ModelDirectory => _ModelDirectory; public string ModelName => _ModelName; - public int? NumJitters => _NumJitters; + public int? NumberOfJitters => _NumberOfJitters; + public int? NumberOfTimesToUpsample => _NumberOfTimesToUpsample; public string OutputExtension => _OutputExtension; public int? OutputQuality => _OutputQuality; public string[] OutputResolutions => _OutputResolutions; @@ -90,7 +92,7 @@ public class Configuration public string[] ValidResolutions => _ValidResolutions; [JsonConstructor] - public Configuration(bool? checkJsonForDistanceResults, int? crossDirectoryMaxItemsInDistanceCollection, int? distanceFactor, bool? forceMetadataLastWriteTimeToCreationTime, bool? forceResizeLastWriteTimeToCreationTime, string[] ignoreExtensions, string[] ignoreRelativePaths, string[] juliePhares, string[] loadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions, string[] loadOrCreateThenSaveDistanceResultsForOutputResolutions, string[] loadOrCreateThenSaveImageFacesResultsForOutputResolutions, bool? loadOrCreateThenSaveIndex, int? locationConfidenceFactor, int? mappedMaxIndex, int? maxItemsInDistanceCollection, string[] mixedYearRelativePaths, string modelDirectory, string modelName, int? numJitters, 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, Property.Models.Configuration? propertyConfiguration, bool? reverse, string[] saveFaceLandmarkForOutputResolutions, bool? saveFullYearOfRandomFiles, bool? saveResizedSubfiles, string[] saveShortcutsForOutputResolutions, bool? skipSearch, bool? testDistanceResults, string[] validResolutions) + public Configuration(bool? checkJsonForDistanceResults, int? crossDirectoryMaxItemsInDistanceCollection, int? distanceFactor, bool? forceMetadataLastWriteTimeToCreationTime, bool? forceResizeLastWriteTimeToCreationTime, string[] ignoreExtensions, string[] ignoreRelativePaths, string[] juliePhares, string[] loadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions, 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, Property.Models.Configuration? propertyConfiguration, bool? reverse, string[] saveFaceLandmarkForOutputResolutions, bool? saveFullYearOfRandomFiles, bool? saveResizedSubfiles, string[] saveShortcutsForOutputResolutions, bool? skipSearch, bool? testDistanceResults, string[] validResolutions) { _CheckJsonForDistanceResults = checkJsonForDistanceResults; _CrossDirectoryMaxItemsInDistanceCollection = crossDirectoryMaxItemsInDistanceCollection; @@ -110,7 +112,8 @@ public class Configuration _MixedYearRelativePaths = mixedYearRelativePaths; _ModelDirectory = modelDirectory; _ModelName = modelName; - _NumJitters = numJitters; + _NumberOfJitters = numberOfJitters; + _NumberOfTimesToUpsample = numberOfTimesToUpsample; _OutputExtension = outputExtension; _OutputQuality = outputQuality; _OutputResolutions = outputResolutions; diff --git a/Tests/UnitTestResize.cs b/Tests/UnitTestResize.cs index 21f19bb..d66c229 100644 --- a/Tests/UnitTestResize.cs +++ b/Tests/UnitTestResize.cs @@ -76,9 +76,9 @@ public class UnitTestResize { Property.Models.PropertyLogic result; if (_AppSettings.MaxDegreeOfParallelism is null) - throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); + throw new ArgumentNullException(nameof(_AppSettings.MaxDegreeOfParallelism)); if (_Configuration?.PropertyConfiguration is null) - throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); result = new(_AppSettings.MaxDegreeOfParallelism.Value, _Configuration.PropertyConfiguration); return result; } @@ -91,17 +91,17 @@ public class UnitTestResize string sourceFileName = "Fall 2005 (113).jpg"; string sourceDirectoryName = "=2005.3 Fall"; if (_Configuration.ForceMetadataLastWriteTimeToCreationTime is null) - throw new Exception($"{nameof(_Configuration.ForceMetadataLastWriteTimeToCreationTime)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.ForceMetadataLastWriteTimeToCreationTime)); if (_Configuration.ForceResizeLastWriteTimeToCreationTime is null) - throw new Exception($"{nameof(_Configuration.ForceResizeLastWriteTimeToCreationTime)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.ForceResizeLastWriteTimeToCreationTime)); if (_Configuration.OutputQuality is null) - throw new Exception($"{nameof(_Configuration.OutputQuality)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.OutputQuality)); if (_Configuration.OverrideForResizeImages is null) - throw new Exception($"{nameof(_Configuration.OverrideForResizeImages)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.OverrideForResizeImages)); if (_Configuration.PropertiesChangedForMetadata is null) - throw new Exception($"{nameof(_Configuration.PropertiesChangedForMetadata)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.PropertiesChangedForMetadata)); if (_Configuration.PropertiesChangedForResize is null) - throw new Exception($"{nameof(_Configuration.PropertiesChangedForResize)} is null!"); + throw new ArgumentNullException(nameof(_Configuration.PropertiesChangedForResize)); int g = 1; int r = 1; Model? model = null; diff --git a/Tests/appsettings.Development.json b/Tests/appsettings.Development.json index 5c3d965..7dad0ee 100644 --- a/Tests/appsettings.Development.json +++ b/Tests/appsettings.Development.json @@ -65,7 +65,8 @@ "MaxItemsInDistanceCollection": 50, "ModelDirectory": "C:/GitHub/dlib-models", "ModelName": "Hog", - "NumJitters": 1, + "NumberOfJitters": 1, + "NumberOfTimesToUpsample": 1, "OutputExtension": ".jpg", "OutputQuality": 95, "OverrideForFaceImages": false, diff --git a/Tests/appsettings.json b/Tests/appsettings.json index 907c362..5c1042e 100644 --- a/Tests/appsettings.json +++ b/Tests/appsettings.json @@ -65,7 +65,8 @@ "MaxItemsInDistanceCollection": 50, "ModelDirectory": "C:/GitHub/dlib-models", "ModelName": "Hog", - "NumJitters": 1, + "NumberOfJitters": 1, + "NumberOfTimesToUpsample": 1, "OutputExtension": ".jpg", "OutputQuality": 95, "OverrideForFaceImages": false, diff --git a/TestsWithFaceRecognitionDotNet/Models/AppSettings.cs b/TestsWithFaceRecognitionDotNet/Models/AppSettings.cs new file mode 100644 index 0000000..7399204 --- /dev/null +++ b/TestsWithFaceRecognitionDotNet/Models/AppSettings.cs @@ -0,0 +1,35 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.TestsWithFaceRecognitionDotNet.Models; + +public class AppSettings +{ + + protected string _Company; + protected string _WorkingDirectoryName; + protected int? _MaxDegreeOfParallelism; + public string Company => _Company; + public string WorkingDirectoryName => _WorkingDirectoryName; + public int? MaxDegreeOfParallelism => _MaxDegreeOfParallelism; + + // public AppSettings() + // { + + // } + + [JsonConstructor] + public AppSettings(string company, string workingDirectoryName, int? maxDegreeOfParallelism) + { + _Company = company; + _WorkingDirectoryName = workingDirectoryName; + _MaxDegreeOfParallelism = maxDegreeOfParallelism; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/Models/Binder/AppSettings.cs b/TestsWithFaceRecognitionDotNet/Models/Binder/AppSettings.cs new file mode 100644 index 0000000..7019998 --- /dev/null +++ b/TestsWithFaceRecognitionDotNet/Models/Binder/AppSettings.cs @@ -0,0 +1,26 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json; + +namespace View_by_Distance.TestsWithFaceRecognitionDotNet.Models.Binder; + +public class AppSettings +{ + + [Display(Name = "Company"), Required] public string Company { get; set; } + [Display(Name = "Working Directory Name"), Required] public string WorkingDirectoryName { get; set; } + [Display(Name = "Max Degree Of Parallelism"), Required] public int? MaxDegreeOfParallelism { get; set; } + + public AppSettings() + { + Company = string.Empty; + WorkingDirectoryName = string.Empty; + MaxDegreeOfParallelism = -1; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs b/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs new file mode 100644 index 0000000..2efa8d0 --- /dev/null +++ b/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs @@ -0,0 +1,103 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json; + +namespace View_by_Distance.TestsWithFaceRecognitionDotNet.Models.Binder; + +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 = "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; } + [Display(Name = "Ignore Extensions"), Required] public string[] IgnoreExtensions { get; set; } + [Display(Name = "Ignore Relative Paths"), Required] public string[] IgnoreRelativePaths { get; set; } + [Display(Name = "Julie Phares Copy Birthdays"), Required] public string[] JuliePhares { get; set; } + [Display(Name = "Load Or Create Then Save Directory Distance Results"), Required] public string[] LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions { get; set; } + [Display(Name = "Load Or Create Then Save Distance Results"), Required] public string[] LoadOrCreateThenSaveDistanceResultsForOutputResolutions { get; set; } + [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 = "Mapped Max Index"), Required] public int? MappedMaxIndex { 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; } + [Display(Name = "Model Name"), Required] public string ModelName { get; set; } + [Display(Name = "Number Jitters"), Required] public int? NumberOfJitters { get; set; } + [Display(Name = "Number of Times To Up Sample"), Required] public int? NumberOfTimesToUpsample { get; set; } + [Display(Name = "Output Extension"), Required] public string OutputExtension { get; set; } + [Display(Name = "Output Quality"), Required] public int? OutputQuality { get; set; } + [Display(Name = "Output Resolutions"), Required] public string[] OutputResolutions { get; set; } + [Display(Name = "Override For Face Images"), Required] public bool? OverrideForFaceImages { get; set; } + [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 = "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; } + [Display(Name = "Properties Changed For Index"), Required] public bool? PropertiesChangedForIndex { get; set; } + [Display(Name = "Properties Changed For Metadata"), Required] public bool? PropertiesChangedForMetadata { get; set; } + [Display(Name = "Properties Changed For Resize"), Required] public bool? PropertiesChangedForResize { get; set; } + [Display(Name = "Property Configuration"), Required] public Property.Models.Configuration? PropertyConfiguration { get; set; } + [Display(Name = "Reverse"), Required] public bool? Reverse { get; set; } + [Display(Name = "Save Face Landmark For Output Resolutions"), Required] public string[] SaveFaceLandmarkForOutputResolutions { get; set; } + [Display(Name = "Save Full Year Of Random Files"), Required] public bool? SaveFullYearOfRandomFiles { get; set; } + [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 = "Test Distance Results"), Required] public bool? TestDistanceResults { get; set; } + [Display(Name = "Valid Resolutions"), Required] public string[] ValidResolutions { get; set; } + + public Configuration() + { + CheckJsonForDistanceResults = null; + CrossDirectoryMaxItemsInDistanceCollection = null; + DistanceFactor = null; + ForceMetadataLastWriteTimeToCreationTime = null; + ForceResizeLastWriteTimeToCreationTime = null; + IgnoreExtensions = Array.Empty(); + IgnoreRelativePaths = Array.Empty(); + JuliePhares = Array.Empty(); + LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions = Array.Empty(); + LoadOrCreateThenSaveDistanceResultsForOutputResolutions = Array.Empty(); + LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = Array.Empty(); + LoadOrCreateThenSaveIndex = null; + LocationConfidenceFactor = null; + MappedMaxIndex = null; + MaxItemsInDistanceCollection = null; + MixedYearRelativePaths = Array.Empty(); + ModelDirectory = string.Empty; + ModelName = string.Empty; + NumberOfJitters = null; + NumberOfTimesToUpsample = null; + OutputExtension = string.Empty; + OutputQuality = null; + OutputResolutions = Array.Empty(); + OverrideForFaceImages = null; + OverrideForFaceLandmarkImages = null; + OverrideForResizeImages = null; + PaddingLoops = null; + PredictorModelName = string.Empty; + PropertiesChangedForDistance = null; + PropertiesChangedForFaces = null; + PropertiesChangedForIndex = null; + PropertiesChangedForMetadata = null; + PropertiesChangedForResize = null; + Reverse = null; + SaveFaceLandmarkForOutputResolutions = Array.Empty(); + SaveFullYearOfRandomFiles = null; + SaveResizedSubfiles = null; + SaveShortcutsForOutputResolutions = Array.Empty(); + SkipSearch = null; + TestDistanceResults = null; + ValidResolutions = Array.Empty(); + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/Models/Configuration.cs b/TestsWithFaceRecognitionDotNet/Models/Configuration.cs new file mode 100644 index 0000000..1ded4df --- /dev/null +++ b/TestsWithFaceRecognitionDotNet/Models/Configuration.cs @@ -0,0 +1,151 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.TestsWithFaceRecognitionDotNet.Models; + +public class Configuration +{ + + protected readonly bool? _CheckJsonForDistanceResults; + protected readonly int? _CrossDirectoryMaxItemsInDistanceCollection; + protected readonly int? _DistanceFactor; + protected readonly bool? _ForceMetadataLastWriteTimeToCreationTime; + protected readonly bool? _ForceResizeLastWriteTimeToCreationTime; + protected readonly string[] _IgnoreExtensions; + protected readonly string[] _IgnoreRelativePaths; + protected readonly string[] _JuliePhares; + protected readonly string[] _LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions; + protected readonly string[] _LoadOrCreateThenSaveDistanceResultsForOutputResolutions; + protected readonly string[] _LoadOrCreateThenSaveImageFacesResultsForOutputResolutions; + protected readonly bool? _LoadOrCreateThenSaveIndex; + protected readonly int? _LocationConfidenceFactor; + protected readonly int? _MappedMaxIndex; + protected readonly int? _MaxItemsInDistanceCollection; + protected readonly string[] _MixedYearRelativePaths; + protected readonly string _ModelDirectory; + protected readonly string _ModelName; + protected readonly int? _NumberOfJitters; + protected readonly int? _NumberOfTimesToUpsample; + protected readonly string _OutputExtension; + protected readonly int? _OutputQuality; + protected readonly string[] _OutputResolutions; + protected readonly bool? _OverrideForFaceImages; + protected readonly bool? _OverrideForFaceLandmarkImages; + protected readonly bool? _OverrideForResizeImages; + protected readonly int? _PaddingLoops; + protected readonly string _PredictorModelName; + protected readonly bool? _PropertiesChangedForDistance; + protected readonly bool? _PropertiesChangedForFaces; + protected readonly bool? _PropertiesChangedForIndex; + protected readonly bool? _PropertiesChangedForMetadata; + protected readonly bool? _PropertiesChangedForResize; + protected Property.Models.Configuration? _PropertyConfiguration; + protected readonly bool? _Reverse; + protected readonly string[] _SaveFaceLandmarkForOutputResolutions; + protected readonly bool? _SaveFullYearOfRandomFiles; + protected readonly bool? _SaveResizedSubfiles; + protected readonly string[] _SaveShortcutsForOutputResolutions; + protected readonly bool? _SkipSearch; + protected readonly bool? _TestDistanceResults; + protected readonly string[] _ValidResolutions; + public bool? CheckJsonForDistanceResults => _CheckJsonForDistanceResults; + public int? CrossDirectoryMaxItemsInDistanceCollection => _CrossDirectoryMaxItemsInDistanceCollection; + public int? DistanceFactor => _DistanceFactor; + public bool? ForceMetadataLastWriteTimeToCreationTime => _ForceMetadataLastWriteTimeToCreationTime; + public bool? ForceResizeLastWriteTimeToCreationTime => _ForceResizeLastWriteTimeToCreationTime; + public string[] IgnoreExtensions => _IgnoreExtensions; + public string[] IgnoreRelativePaths => _IgnoreRelativePaths; + public string[] JuliePhares => _JuliePhares; + public string[] LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions => _LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions; + public string[] LoadOrCreateThenSaveDistanceResultsForOutputResolutions => _LoadOrCreateThenSaveDistanceResultsForOutputResolutions; + public string[] LoadOrCreateThenSaveImageFacesResultsForOutputResolutions => _LoadOrCreateThenSaveImageFacesResultsForOutputResolutions; + public bool? LoadOrCreateThenSaveIndex => _LoadOrCreateThenSaveIndex; + public int? LocationConfidenceFactor => _LocationConfidenceFactor; + public int? MappedMaxIndex => _MappedMaxIndex; + public int? MaxItemsInDistanceCollection => _MaxItemsInDistanceCollection; + public string[] MixedYearRelativePaths => _MixedYearRelativePaths; + public string ModelDirectory => _ModelDirectory; + public string ModelName => _ModelName; + public int? NumberOfJitters => _NumberOfJitters; + public int? NumberOfTimesToUpsample => _NumberOfTimesToUpsample; + public string OutputExtension => _OutputExtension; + public int? OutputQuality => _OutputQuality; + public string[] OutputResolutions => _OutputResolutions; + public bool? OverrideForFaceImages => _OverrideForFaceImages; + public bool? OverrideForFaceLandmarkImages => _OverrideForFaceLandmarkImages; + public bool? OverrideForResizeImages => _OverrideForResizeImages; + public int? PaddingLoops => _PaddingLoops; + public string PredictorModelName => _PredictorModelName; + public bool? PropertiesChangedForDistance => _PropertiesChangedForDistance; + public bool? PropertiesChangedForFaces => _PropertiesChangedForFaces; + public bool? PropertiesChangedForIndex => _PropertiesChangedForIndex; + public bool? PropertiesChangedForMetadata => _PropertiesChangedForMetadata; + public bool? PropertiesChangedForResize => _PropertiesChangedForResize; + public Property.Models.Configuration? PropertyConfiguration => _PropertyConfiguration; + public bool? Reverse => _Reverse; + public string[] SaveFaceLandmarkForOutputResolutions => _SaveFaceLandmarkForOutputResolutions; + public bool? SaveFullYearOfRandomFiles => _SaveFullYearOfRandomFiles; + public bool? SaveResizedSubfiles => _SaveResizedSubfiles; + public string[] SaveShortcutsForOutputResolutions => _SaveShortcutsForOutputResolutions; + public bool? SkipSearch => _SkipSearch; + public bool? TestDistanceResults => _TestDistanceResults; + public string[] ValidResolutions => _ValidResolutions; + + [JsonConstructor] + public Configuration(bool? checkJsonForDistanceResults, int? crossDirectoryMaxItemsInDistanceCollection, int? distanceFactor, bool? forceMetadataLastWriteTimeToCreationTime, bool? forceResizeLastWriteTimeToCreationTime, string[] ignoreExtensions, string[] ignoreRelativePaths, string[] juliePhares, string[] loadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions, 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, Property.Models.Configuration? propertyConfiguration, bool? reverse, string[] saveFaceLandmarkForOutputResolutions, bool? saveFullYearOfRandomFiles, bool? saveResizedSubfiles, string[] saveShortcutsForOutputResolutions, bool? skipSearch, bool? testDistanceResults, string[] validResolutions) + { + _CheckJsonForDistanceResults = checkJsonForDistanceResults; + _CrossDirectoryMaxItemsInDistanceCollection = crossDirectoryMaxItemsInDistanceCollection; + _DistanceFactor = distanceFactor; + _ForceMetadataLastWriteTimeToCreationTime = forceMetadataLastWriteTimeToCreationTime; + _ForceResizeLastWriteTimeToCreationTime = forceResizeLastWriteTimeToCreationTime; + _IgnoreExtensions = ignoreExtensions; + _IgnoreRelativePaths = ignoreRelativePaths; + _JuliePhares = juliePhares; + _LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions = loadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions; + _LoadOrCreateThenSaveDistanceResultsForOutputResolutions = loadOrCreateThenSaveDistanceResultsForOutputResolutions; + _LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = loadOrCreateThenSaveImageFacesResultsForOutputResolutions; + _LoadOrCreateThenSaveIndex = loadOrCreateThenSaveIndex; + _LocationConfidenceFactor = locationConfidenceFactor; + _MappedMaxIndex = mappedMaxIndex; + _MaxItemsInDistanceCollection = maxItemsInDistanceCollection; + _MixedYearRelativePaths = mixedYearRelativePaths; + _ModelDirectory = modelDirectory; + _ModelName = modelName; + _NumberOfJitters = numberOfJitters; + _NumberOfTimesToUpsample = numberOfTimesToUpsample; + _OutputExtension = outputExtension; + _OutputQuality = outputQuality; + _OutputResolutions = outputResolutions; + _OverrideForFaceImages = overrideForFaceImages; + _OverrideForFaceLandmarkImages = overrideForFaceLandmarkImages; + _OverrideForResizeImages = overrideForResizeImages; + _PaddingLoops = paddingLoops; + _PredictorModelName = predictorModelName; + _PropertiesChangedForDistance = propertiesChangedForDistance; + _PropertiesChangedForFaces = propertiesChangedForFaces; + _PropertiesChangedForIndex = propertiesChangedForIndex; + _PropertiesChangedForMetadata = propertiesChangedForMetadata; + _PropertiesChangedForResize = propertiesChangedForResize; + _PropertyConfiguration = propertyConfiguration; + _Reverse = reverse; + _SaveFaceLandmarkForOutputResolutions = saveFaceLandmarkForOutputResolutions; + _SaveFullYearOfRandomFiles = saveFullYearOfRandomFiles; + _SaveResizedSubfiles = saveResizedSubfiles; + _SaveShortcutsForOutputResolutions = saveShortcutsForOutputResolutions; + _SkipSearch = skipSearch; + _TestDistanceResults = testDistanceResults; + _ValidResolutions = validResolutions; + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + public void Set(Property.Models.Configuration configuration) => _PropertyConfiguration = configuration; + + public void Update() => _PropertyConfiguration?.Update(); + +} \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/Models/Stateless/AppSettings.cs b/TestsWithFaceRecognitionDotNet/Models/Stateless/AppSettings.cs new file mode 100644 index 0000000..b32222d --- /dev/null +++ b/TestsWithFaceRecognitionDotNet/Models/Stateless/AppSettings.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.Configuration; +using System.Text.Json; + +namespace View_by_Distance.TestsWithFaceRecognitionDotNet.Models.Stateless; + +public abstract class AppSettings +{ + + public static Models.AppSettings Get(IConfigurationRoot configurationRoot) + { + Models.AppSettings? result; + Binder.AppSettings appSettings = configurationRoot.Get(); + string json = JsonSerializer.Serialize(appSettings, new JsonSerializerOptions() { WriteIndented = true }); + result = JsonSerializer.Deserialize(json); + if (result is null) + throw new Exception(json); + if (string.IsNullOrEmpty(result.Company)) + throw new Exception(json); + string jsonThis = result.ToString(); + if (jsonThis != json) + { + int? check = null; + int min = new int[] { json.Length, jsonThis.Length }.Min(); + for (int i = 0; i < min; i++) + { + if (json[i] == jsonThis[i]) + continue; + check = i; + break; + } + if (check is null) + throw new Exception(); + string a = json[..check.Value].Split(',')[^1]; + string b = json[check.Value..].Split(',')[0]; + throw new Exception($"{a}{b}"); + } + return result; + } + +} \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/Models/Stateless/Configuration.cs b/TestsWithFaceRecognitionDotNet/Models/Stateless/Configuration.cs new file mode 100644 index 0000000..6fa49df --- /dev/null +++ b/TestsWithFaceRecognitionDotNet/Models/Stateless/Configuration.cs @@ -0,0 +1,44 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; +using System.Text.Json; + +namespace View_by_Distance.TestsWithFaceRecognitionDotNet.Models.Stateless; + +public abstract class Configuration +{ + + public static Models.Configuration Get(IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, string workingDirectory, Property.Models.Configuration propertyConfiguration) + { + Models.Configuration? result; + string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); + string section = string.Concat(environmentName, ":", nameof(Binder.Configuration)); + IConfigurationSection configurationSection = configurationRoot.GetSection(section); + Binder.Configuration configuration = configurationSection.Get(); + string json = JsonSerializer.Serialize(configuration, new JsonSerializerOptions() { WriteIndented = true }); + result = JsonSerializer.Deserialize(json); + if (result is null) + throw new Exception(json); + string jsonThis = result.ToString(); + result.Set(propertyConfiguration); + result.Update(); + if (jsonThis != json) + { + int? check = null; + int min = new int[] { json.Length, jsonThis.Length }.Min(); + for (int i = 0; i < min; i++) + { + if (json[i] == jsonThis[i]) + continue; + check = i; + break; + } + if (check is null) + throw new Exception(); + string a = json[..check.Value].Split(',')[^1]; + string b = json[check.Value..].Split(',')[0]; + throw new Exception($"{a}{b}"); + } + return result; + } + +} \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/TestsWithFaceRecognitionDotNet.csproj b/TestsWithFaceRecognitionDotNet/TestsWithFaceRecognitionDotNet.csproj new file mode 100644 index 0000000..acb603a --- /dev/null +++ b/TestsWithFaceRecognitionDotNet/TestsWithFaceRecognitionDotNet.csproj @@ -0,0 +1,53 @@ + + + enable + false + 10.0 + enable + win-x64 + net6.0 + + + true + true + true + + + Windows + + + OSX + + + Linux + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + Always + + + \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/UnitTestExample.cs b/TestsWithFaceRecognitionDotNet/UnitTestExample.cs new file mode 100644 index 0000000..6ae182f --- /dev/null +++ b/TestsWithFaceRecognitionDotNet/UnitTestExample.cs @@ -0,0 +1,71 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Phares.Shared; +using Serilog; +using System.Diagnostics; +using System.Reflection; +using View_by_Distance.Shared.Models.Stateless.Methods; +using View_by_Distance.TestsWithFaceRecognitionDotNet.Models; + +namespace View_by_Distance.TestsWithFaceRecognitionDotNet; + +[TestClass] +public class UnitTestExample +{ + + private readonly ILogger _Logger; + private readonly AppSettings _AppSettings; + private readonly string _WorkingDirectory; + private readonly Configuration _Configuration; + private readonly IsEnvironment _IsEnvironment; + private readonly IConfigurationRoot _ConfigurationRoot; + private readonly Property.Models.Configuration _PropertyConfiguration; + + public UnitTestExample() + { + ILogger logger; + AppSettings appSettings; + string workingDirectory; + Configuration configuration; + IsEnvironment isEnvironment; + IConfigurationRoot configurationRoot; + LoggerConfiguration loggerConfiguration = new(); + Property.Models.Configuration propertyConfiguration; + Assembly assembly = Assembly.GetExecutingAssembly(); + bool debuggerWasAttachedAtLineZero = Debugger.IsAttached || assembly.Location.Contains(@"\bin\Debug"); + isEnvironment = new(processesCount: null, nullASPNetCoreEnvironmentIsDevelopment: debuggerWasAttachedAtLineZero, nullASPNetCoreEnvironmentIsProduction: !debuggerWasAttachedAtLineZero); + IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() + .AddEnvironmentVariables() + .AddJsonFile(isEnvironment.AppSettingsFileName); + configurationRoot = configurationBuilder.Build(); + appSettings = Models.Stateless.AppSettings.Get(configurationRoot); + workingDirectory = IWorkingDirectory.GetWorkingDirectory(assembly.GetName().Name, appSettings.WorkingDirectoryName); + Environment.SetEnvironmentVariable(nameof(workingDirectory), workingDirectory); + _ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, configurationRoot); + Log.Logger = loggerConfiguration.CreateLogger(); + logger = Log.ForContext(); + propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); + configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); + logger.Information("Complete"); + _Logger = logger; + _AppSettings = appSettings; + _Configuration = configuration; + _IsEnvironment = isEnvironment; + _WorkingDirectory = workingDirectory; + _ConfigurationRoot = configurationRoot; + _PropertyConfiguration = propertyConfiguration; + } + + [TestMethod] + public void TestMethodNull() + { + Assert.IsFalse(_Logger is null); + Assert.IsFalse(_AppSettings is null); + Assert.IsFalse(_Configuration is null); + Assert.IsFalse(_IsEnvironment is null); + Assert.IsFalse(_WorkingDirectory is null); + Assert.IsFalse(_ConfigurationRoot is null); + Assert.IsFalse(_PropertyConfiguration is null); + } + +} \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs new file mode 100644 index 0000000..ce3f5f7 --- /dev/null +++ b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs @@ -0,0 +1,253 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Phares.Shared; +using Serilog; +using System.Diagnostics; +using System.Drawing.Imaging; +using System.Reflection; +using View_by_Distance.FaceRecognitionDotNet; +using View_by_Distance.Metadata.Models; +using View_by_Distance.Resize.Models; +using View_by_Distance.Shared.Models; +using View_by_Distance.Shared.Models.Stateless; +using View_by_Distance.Shared.Models.Stateless.Methods; +using View_by_Distance.TestsWithFaceRecognitionDotNet.Models; + +namespace View_by_Distance.TestsWithFaceRecognitionDotNet; + +[TestClass] +public class UnitTestFace +{ + + private readonly ILogger _Logger; + private readonly AppSettings _AppSettings; + private readonly string _WorkingDirectory; + private readonly Configuration _Configuration; + private readonly IsEnvironment _IsEnvironment; + private readonly IConfigurationRoot _ConfigurationRoot; + private readonly Property.Models.Configuration _PropertyConfiguration; + + public UnitTestFace() + { + ILogger logger; + AppSettings appSettings; + string workingDirectory; + Configuration configuration; + IsEnvironment isEnvironment; + IConfigurationRoot configurationRoot; + LoggerConfiguration loggerConfiguration = new(); + Property.Models.Configuration propertyConfiguration; + Assembly assembly = Assembly.GetExecutingAssembly(); + bool debuggerWasAttachedAtLineZero = Debugger.IsAttached || assembly.Location.Contains(@"\bin\Debug"); + isEnvironment = new(processesCount: null, nullASPNetCoreEnvironmentIsDevelopment: debuggerWasAttachedAtLineZero, nullASPNetCoreEnvironmentIsProduction: !debuggerWasAttachedAtLineZero); + IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() + .AddEnvironmentVariables() + .AddJsonFile(isEnvironment.AppSettingsFileName); + configurationRoot = configurationBuilder.Build(); + appSettings = Models.Stateless.AppSettings.Get(configurationRoot); + workingDirectory = IWorkingDirectory.GetWorkingDirectory(assembly.GetName().Name, appSettings.WorkingDirectoryName); + Environment.SetEnvironmentVariable(nameof(workingDirectory), workingDirectory); + _ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, configurationRoot); + Log.Logger = loggerConfiguration.CreateLogger(); + logger = Log.ForContext(); + propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); + configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); + logger.Information("Complete"); + _Logger = logger; + _AppSettings = appSettings; + _Configuration = configuration; + _IsEnvironment = isEnvironment; + _WorkingDirectory = workingDirectory; + _ConfigurationRoot = configurationRoot; + _PropertyConfiguration = propertyConfiguration; + } + + [TestMethod] + public void TestMethodNull() + { + Assert.IsFalse(_Logger is null); + Assert.IsFalse(_AppSettings is null); + Assert.IsFalse(_Configuration is null); + Assert.IsFalse(_IsEnvironment is null); + Assert.IsFalse(_WorkingDirectory is null); + Assert.IsFalse(_ConfigurationRoot is null); + Assert.IsFalse(_PropertyConfiguration is null); + } + + private Property.Models.PropertyLogic GetPropertyLogic() + { + Property.Models.PropertyLogic result; + if (_AppSettings.MaxDegreeOfParallelism is null) + throw new ArgumentNullException(nameof(_AppSettings.MaxDegreeOfParallelism)); + if (_Configuration?.PropertyConfiguration is null) + throw new ArgumentNullException(nameof(_Configuration.PropertyConfiguration)); + result = new(_AppSettings.MaxDegreeOfParallelism.Value, _Configuration.PropertyConfiguration); + return result; + } + + private static (Model model, PredictorModel predictorModel, ModelParameter modelParameter) GetModel(Configuration configuration) + { + (Model, PredictorModel, ModelParameter) result; + Array array; + Model? model = null; + PredictorModel? predictorModel = null; + array = Enum.GetValues(typeof(Model)); + foreach (Model check in array) + { + if (configuration.ModelName.Contains(check.ToString())) + { + model = check; + break; + } + } + if (model is null) + throw new Exception("Destination directory must have Model name!"); + model = model.Value; + array = Enum.GetValues(typeof(PredictorModel)); + foreach (PredictorModel check in array) + { + if (configuration.PredictorModelName.Contains(check.ToString())) + { + predictorModel = check; + break; + } + } + if (predictorModel is null) + throw new Exception("Destination directory must have Predictor Model name!"); + predictorModel = predictorModel.Value; + ModelParameter modelParameter = new() + { + CnnFaceDetectorModel = File.ReadAllBytes(Path.Combine(configuration.ModelDirectory, "mmod_human_face_detector.dat")), + FaceRecognitionModel = File.ReadAllBytes(Path.Combine(configuration.ModelDirectory, "dlib_face_recognition_resnet_model_v1.dat")), + PosePredictor5FaceLandmarksModel = File.ReadAllBytes(Path.Combine(configuration.ModelDirectory, "shape_predictor_5_face_landmarks.dat")), + PosePredictor68FaceLandmarksModel = File.ReadAllBytes(Path.Combine(configuration.ModelDirectory, "shape_predictor_68_face_landmarks.dat")) + }; + result = new(model.Value, predictorModel.Value, modelParameter); + return result; + } + + [TestMethod] + public void TestGetPixelPercentage() + { + double pixelPercentage; + pixelPercentage = Location.GetPixelPercentage(1, 1, 10, 10, 100, 100); + Assert.IsTrue(pixelPercentage == 0.0505d); + pixelPercentage = Location.GetPixelPercentage(50, 50, 60, 60, 100, 100); + Assert.IsTrue(pixelPercentage == 0.5555d); + } + + [TestMethod] + public void TestMethodFace() + { + string sourceFileName = "IMG_0067.jpg"; + string sourceDirectoryName = "Mackenzie Prom 2017"; + // string sourceFileName = "Fall 2005 (113).jpg"; + // string sourceDirectoryName = "=2005.3 Fall"; + // string sourceFileName = "DSCN0534.jpg"; + // string sourceDirectoryName = "Logan Swimming Lessons 2013"; + // string sourceFileName = "DSC_4913.jpg"; + // string sourceDirectoryName = "Disneyland 2014"; + // string sourceFileName = "Logan Michael Sept 08 (193).jpg"; + // string sourceDirectoryName = "=2008.2 Summer Logan Michael"; + if (_Configuration.ForceMetadataLastWriteTimeToCreationTime is null) + throw new ArgumentNullException(nameof(_Configuration.ForceMetadataLastWriteTimeToCreationTime)); + if (_Configuration.ForceResizeLastWriteTimeToCreationTime is null) + throw new ArgumentNullException(nameof(_Configuration.ForceResizeLastWriteTimeToCreationTime)); + if (_Configuration.OutputQuality is null) + throw new ArgumentNullException(nameof(_Configuration.OutputQuality)); + if (_Configuration.OverrideForResizeImages is null) + throw new ArgumentNullException(nameof(_Configuration.OverrideForResizeImages)); + if (_Configuration.PropertiesChangedForMetadata is null) + throw new ArgumentNullException(nameof(_Configuration.PropertiesChangedForMetadata)); + if (_Configuration.PropertiesChangedForResize is null) + throw new ArgumentNullException(nameof(_Configuration.PropertiesChangedForResize)); + if (_Configuration.NumberOfJitters is null) + throw new ArgumentNullException(nameof(_Configuration.NumberOfJitters)); + if (_Configuration.NumberOfTimesToUpsample is null) + throw new ArgumentNullException(nameof(_Configuration.NumberOfTimesToUpsample)); + int g = 1; + int r = 1; + string original = "Original"; + List parseExceptions = new(); + Property.Models.A_Property? property = null; + Property.Models.PropertyHolder propertyHolder; + Dictionary imageResizeKeyValuePairs; + List> subFileTuples = new(); + List> metadataCollection; + int length = _PropertyConfiguration.RootDirectory.Length; + string outputResolution = _Configuration.OutputResolutions[0]; + Property.Models.PropertyLogic propertyLogic = GetPropertyLogic(); + (Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(_Configuration); + string sourceDirectory = Path.Combine(_PropertyConfiguration.RootDirectory, sourceDirectoryName); + _Logger.Information(_Configuration.ModelDirectory); + string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_PropertyConfiguration, nameof(Property.Models.A_Property), "{}"); + B_Metadata metadata = new(_Configuration.ForceMetadataLastWriteTimeToCreationTime.Value, _Configuration.PropertiesChangedForMetadata.Value); + (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters) = C_Resize.GetTuple(_Configuration.OutputExtension, _Configuration.OutputQuality.Value); + C_Resize resize = new(_Configuration.ForceResizeLastWriteTimeToCreationTime.Value, _Configuration.OverrideForResizeImages.Value, _Configuration.PropertiesChangedForResize.Value, _Configuration.ValidResolutions, imageCodecInfo, encoderParameters); + propertyLogic.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection(_PropertyConfiguration, + model, + predictorModel, + sourceDirectory, + nameof(Property.Models.A_Property), + outputResolution, + includeResizeGroup: false, + includeModel: false, + includePredictorModel: false, + contentDescription: string.Empty, + singletonDescription: "Properties for each image", + collectionDescription: string.Empty)); + metadata.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection(_PropertyConfiguration, + model, + predictorModel, + sourceDirectory, + nameof(B_Metadata), + outputResolution, + includeResizeGroup: false, + includeModel: false, + includePredictorModel: false, + contentDescription: string.Empty, + singletonDescription: "Metadata as key value pairs", + collectionDescription: string.Empty)); + resize.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection(_PropertyConfiguration, + model, + predictorModel, + sourceDirectory, + nameof(C_Resize), + outputResolution, + includeResizeGroup: true, + includeModel: false, + includePredictorModel: false, + contentDescription: "Resized image", + singletonDescription: "Resize dimensions for each resolution", + collectionDescription: string.Empty)); + string sourceDirectoryFile = ".json"; + FileInfo fileInfo = new(Path.Combine(sourceDirectory, sourceFileName)); + string relativePath = Property.Models.Stateless.IPath.GetRelativePath(fileInfo.FullName, length); + sourceDirectory = Path.Combine(aPropertySingletonDirectory, sourceDirectoryName); + propertyHolder = new(g, sourceDirectory, sourceDirectoryFile, relativePath, r, fileInfo, property, false, false, null, null); + Assert.IsNotNull(propertyHolder.ImageFileInfo); + property = propertyLogic.GetProperty(propertyLogic.AngleBracketCollection[0], propertyHolder, subFileTuples, parseExceptions); + (int _, metadataCollection) = metadata.GetMetadataCollection(subFileTuples, parseExceptions, propertyHolder); + imageResizeKeyValuePairs = resize.GetResizeKeyValuePairs(subFileTuples, parseExceptions, original, metadataCollection, property, propertyHolder); + FileInfo resizedFileInfo = new(Path.Combine(resize.AngleBracketCollection[0].Replace("<>", "()"), Path.GetFileName(propertyHolder.ImageFileInfo.FullName))); + propertyHolder.SetResizedFileInfo(resizedFileInfo); + resize.SaveResizedSubfile(outputResolution, subFileTuples, propertyHolder, original, property, imageResizeKeyValuePairs); + resizedFileInfo.Refresh(); + Assert.IsNotNull(propertyHolder.ResizedFileInfo); + Image? image = FaceRecognition.LoadImageFile(propertyHolder.ResizedFileInfo.FullName); + Assert.IsNotNull(image); + FaceRecognition faceRecognition = FaceRecognition.Create(modelParameter); + List locations = faceRecognition.FaceLocations(model, image, _Configuration.NumberOfTimesToUpsample.Value, sortByPixelPercentage: true); + Assert.IsTrue(locations.Count == 2); + List<(FacePart, FacePoint[])[]> faceLandmarks = faceRecognition.GetFaceLandmarkCollection(image, _Configuration.NumberOfTimesToUpsample.Value, locations, predictorModel, model); + Assert.IsTrue(faceLandmarks.Count == 2); + faceLandmarks = faceRecognition.GetFaceLandmarkCollection(image, _Configuration.NumberOfTimesToUpsample.Value, faceLocations: null, predictorModel, model); + Assert.IsTrue(faceLandmarks.Count == 2); + List faceEncodings = faceRecognition.FaceEncodings(image, _Configuration.NumberOfTimesToUpsample.Value, knownFaceLocation: null, _Configuration.NumberOfJitters.Value, predictorModel, model); + Assert.IsTrue(faceEncodings.Count == 2); + List faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncodings[0]); + Assert.IsTrue(faceDistances.Count == 2); + Assert.IsNotNull(sourceFileName); + } + +} \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/appsettings.Development.json b/TestsWithFaceRecognitionDotNet/appsettings.Development.json new file mode 100644 index 0000000..7dad0ee --- /dev/null +++ b/TestsWithFaceRecognitionDotNet/appsettings.Development.json @@ -0,0 +1,526 @@ +{ + "Company": "Mike Phares", + "Linux": {}, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Log4netProvider": "Debug", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "MaxDegreeOfParallelism": 6, + "Serilog": { + "Using": [ + "Serilog.Sinks.Console", + "Serilog.Sinks.File" + ], + "MinimumLevel": "Debug", + "WriteTo": [ + { + "Name": "Debug", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "Console", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "%workingDirectory% - Log/log-.txt", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}", + "rollingInterval": "Hour" + } + } + ], + "Enrich": [ + "FromLogContext", + "WithMachineName", + "WithThreadId" + ], + "Properties": { + "Application": "Sample" + } + }, + "WorkingDirectoryName": "PharesApps", + "Windows": { + "Configuration": { + "CheckJsonForDistanceResults": true, + "CrossDirectoryMaxItemsInDistanceCollection": 7, + "DateGroup": "2022-07-27", + "DistanceFactor": 8, + "FileNameDirectorySeparator": ".Z.", + "ForceMetadataLastWriteTimeToCreationTime": true, + "ForcePropertyLastWriteTimeToCreationTime": false, + "ForceResizeLastWriteTimeToCreationTime": true, + "LoadOrCreateThenSaveIndex": false, + "LocationConfidenceFactor": 2, + "MappedMaxIndex": 1034720, + "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "MaxItemsInDistanceCollection": 50, + "ModelDirectory": "C:/GitHub/dlib-models", + "ModelName": "Hog", + "NumberOfJitters": 1, + "NumberOfTimesToUpsample": 1, + "OutputExtension": ".jpg", + "OutputQuality": 95, + "OverrideForFaceImages": false, + "OverrideForFaceLandmarkImages": false, + "OverrideForResizeImages": false, + "PaddingLoops": 5, + "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", + "PredictorModelName": "Large", + "PopulatePropertyId": true, + "PropertiesChangedForDistance": false, + "PropertiesChangedForFaces": false, + "PropertiesChangedForIndex": false, + "PropertiesChangedForMetadata": false, + "PropertiesChangedForProperty": false, + "PropertiesChangedForResize": false, + "Reverse": false, + "xRootDirectory": "C:/Tmp/phares/Pictures", + "RootDirectory": "F:/Tmp/Phares/Compare/Images 2022-07-27 - f642c5669a1d89d598a2efd70da9dc7129d02c15 - III", + "SaveFullYearOfRandomFiles": true, + "SaveResizedSubFiles": true, + "SkipSearch": false, + "TestDistanceResults": true, + "WriteBitmapDataBytes": false, + "IgnoreExtensions": [ + ".gif", + ".GIF" + ], + "JuliePhares": [ + "1500-01-16_00", + "1500-01-19_00", + "1500-01-20_00", + "1500-01-21_00", + "1500-01-25_00", + "1500-01-26_00", + "1500-01-27_00", + "1500-02-13_00", + "1500-02-17_00", + "1500-02-24_00", + "1500-02-25_00", + "1500-04-03_00", + "1500-04-06_00", + "1500-04-19_00", + "1500-05-03_00", + "1500-05-18_00", + "1500-05-28_00", + "1500-06-16_00", + "1500-06-26_00", + "1500-06-27_00", + "1500-07-07_00", + "1500-07-16_00", + "1720-09-30_05", + "1500-07-26_00", + "1500-08-03_00", + "1500-08-23_00", + "1500-08-24_00", + "1500-09-16_00", + "1500-09-21_00", + "1500-09-28_00", + "1500-10-14_00", + "1500-11-07_00", + "1500-11-09_00", + "1720-09-28_20", + "1501-01-08_00", + "1501-01-12_00", + "1501-01-13_00", + "1501-01-30_00", + "1501-03-09_00", + "1501-03-14_00", + "1501-03-22_00", + "1501-04-07_00", + "1501-04-10_00", + "1501-04-19_00", + "1501-05-06_00", + "1956-09-19_00", + "2012-09-17_00", + "1998-05-21_00", + "1960-03-01_00", + "1976-03-08_00", + "2007-09-07_00", + "2000-04-07_00", + "1980-01-17_00", + "1958-01-30_00", + "1976-01-05_00", + "1982-05-02_00" + ], + "LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions": [ + "1920 x 1080" + ], + "LoadOrCreateThenSaveDistanceResultsForOutputResolutions": [ + "1920 x 1080" + ], + "LoadOrCreateThenSaveImageFacesResultsForOutputResolutions": [ + "1920 x 1080" + ], + "OutputResolutions": [ + "176 x 176", + "256 x 256", + "353 x 353", + "1024 x 768", + "1920 x 1080" + ], + "PropertyContentCollectionFiles": [], + "SaveFaceLandmarkForOutputResolutions": [ + "176 x 176", + "256 x 256" + ], + "SaveShortcutsForOutputResolutions": [ + "1920 x 1080" + ], + "ValidImageFormatExtensions": [ + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "ValidMetadataExtensions": [ + ".3gp", + ".3GP", + ".amr", + ".AMR", + ".avi", + ".AVI", + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".ico", + ".ICO", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".m4v", + ".M4V", + ".mov", + ".MOV", + ".mp4", + ".MP4", + ".mta", + ".MTA", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "ValidResolutions": [ + "176 x 176", + "256 x 256", + "353 x 353", + "1024 x 768", + "1280 x 720", + "1280 x 800", + "1376 x 768", + "1600 x 1200", + "1920 x 1080", + "2256 x 1496", + "3840 x 2160", + "7680 x 4320" + ], + "VerifyToSeason": [ + ". 2000", + ". 2001", + ". 2002", + ". 2003", + ". 2004", + ". 2005", + ". 2006", + ". 2007", + ". 2008", + ". 2009", + ". 2010", + ". 2011", + ". 2012", + ". 2013", + ". 2014", + ". 2015", + ". 2016", + ". 2017", + ". 2018", + ". 2019", + ". 2020", + ". 2021", + ". 2022", + ". 2023", + ". 2024", + ". 2025", + ". 2026", + ". 2027", + ". 2028", + ". 2029", + "=2000.0 Winter", + "=2002.1 Spring", + "=2002.4 Winter", + "=2003.0 Winter", + "=2003.1 Spring", + "=2003.3 Fall", + "=2003.4 Winter", + "=2004.0 Winter", + "=2005.1 Spring", + "=2005.2 Summer", + "=2005.3 Fall", + "=2005.4 Winter", + "=2006.0 Winter", + "=2006.1 Spring", + "=2006.3 Fall", + "=2007.0 Winter", + "=2007.2 Summer Logan Michael", + "=2007.2 Summer", + "=2007.3 Fall Logan Michael", + "=2007.4 Winter Logan Michael", + "=2008.0 Winter Logan Michael", + "=2008.1 Spring Logan Michael", + "=2008.2 Summer Logan Michael", + "=2008.2 Summer", + "=2008.3 Fall Logan Michael", + "=2009.0 Winter Logan Michael", + "=2009.0 Winter", + "=2009.1 Spring Logan Michael", + "=2009.1 Spring", + "=2009.2 Summer Logan Michael", + "=2009.2 Summer", + "=2009.3 Fall Logan Michael", + "=2009.3 Fall", + "=2009.4 Winter Logan Michael", + "=2009.4 Winter", + "=2010.0 Winter Logan Michael", + "=2010.0 Winter", + "=2010.1 Spring Logan Michael", + "=2010.1 Spring", + "=2010.2 Summer", + "=2010.3 Fall Logan Michael", + "=2010.3 Fall", + "=2010.4 Winter", + "=2011.0 Winter", + "=2011.1 Spring", + "=2011.2 Summer", + "=2011.3 Fall", + "=2011.4 Winter", + "=2012.0 Winter Chelsea 2012", + "=2012.0 Winter Chelsea", + "=2012.0 Winter", + "=2012.1 Spring Chelsea", + "=2012.1 Spring", + "=2012.2 Summer Chelsea", + "=2012.2 Summer", + "=2012.3 Fall Chelsea", + "=2012.3 Fall", + "=2012.4 Winter Chelsea", + "=2012.4 Winter", + "=2013.0 Winter Chelsea 2013", + "=2013.0 Winter Chelsea", + "=2013.0 Winter", + "=2013.1 Spring", + "=2013.2 Summer Chelsea", + "=2013.2 Summer", + "=2013.3 Fall Chelsea", + "=2013.3 Fall", + "=2013.4 Winter", + "=2014.0 Winter", + "=2014.1 Spring", + "=2014.2 Summer", + "=2014.3 Fall", + "=2014.4 Winter", + "=2015.0 Winter", + "=2015.1 Spring", + "=2015.2 Summer", + "=2015.3 Fall", + "=2015.4 Winter", + "=2016.0 Winter", + "=2016.1 Spring", + "=2016.2 Summer", + "=2016.3 Fall", + "=2016.4 Winter", + "=2017.1 Spring", + "=2017.2 Summer", + "=2017.3 Fall", + "=2017.4 Winter", + "=2018.0 Winter", + "=2018.1 Spring", + "=2018.3 Fall", + "=2018.4 Winter", + "=2019.0 Winter", + "=2019.1 Spring", + "=2019.2 Summer", + "=2019.3 Fall", + "=2019.4 Winter", + "=2020.0 Winter", + "=2020.1 Spring", + "=2020.2 Summer", + "=2020.3 Fall", + "=2020.4 Winter", + "=2021.1 Spring", + "=2021.2 Summer", + "=2021.3 Fall", + "=2021.4 Winter", + "=2022.0 Winter", + "=2022.1 Spring", + "Anthem 2015", + "April 2010", + "April 2013", + "December 2006", + "December 2010", + "Fall 2005", + "Fall 2015", + "Fall 2016", + "Fall 2017", + "Fall 2018", + "Fall 2019", + "Fall 2020", + "Fall 2021", + "February 2010", + "January 2015", + "July 2010", + "June 2010", + "Kids 2005", + "March 2013", + "May 2010", + "May 2011", + "May 2013", + "October 2005", + "October 2014", + "Spring 2013", + "Spring 2014", + "Spring 2016", + "Spring 2018", + "Spring 2019", + "Spring 2020", + "Summer 2011", + "Summer 2012", + "Summer 2013", + "Summer 2014", + "Summer 2015", + "Summer 2016", + "Summer 2017", + "Summer 2018", + "Summer 2020", + "Summer 2021", + "Winter 2015", + "Winter 2016", + "Winter 2017", + "Winter 2018", + "Winter 2019-2020", + "Winter 2020", + "zzz =2005.0 Winter Tracy Pictures", + "zzz =2005.1 Spring Tracy Pictures", + "zzz =2005.2 Summer Tracy Pictures", + "zzz =2005.3 Fall Tracy Pictures", + "zzz =2005.4 Winter Tracy Pictures", + "zzz =2006.1 Spring Tracy Pictures", + "zzz =2007.0 Winter Tracy Pictures", + "zzz =2007.2 Summer Tracy Pictures", + "zzz =2008.0 Winter Tracy Pictures", + "zzz =2008.2 Summer Tracy Pictures", + "zzz =2009.0 Winter Tracy Pictures", + "zzz =2009.2 Summer Tracy Pictures", + "zzz =2009.3 Fall Tracy Pictures", + "zzz =2009.4 Winter Tracy Pictures", + "zzz =2010.0 Winter Tracy Pictures", + "zzz =2010.1 Spring Tracy Pictures", + "zzz =2010.2 Summer Tracy Pictures", + "zzz =2010.3 Fall Tracy Pictures", + "zzz =2011.0 Winter Tracy Pictures", + "zzz =2011.1 Spring Tracy Pictures", + "zzz =2011.2 Summer Tracy Pictures", + "zzz =2011.3 Fall Tracy Pictures", + "zzz =2011.4 Winter Tracy Pictures", + "zzz =2012.0 Winter Tracy Pictures", + "zzz =2012.1 Spring Tracy Pictures", + "zzz =2012.2 Summer Tracy Pictures", + "zzz =2012.3 Fall Tracy Pictures", + "zzz =2012.4 Winter Tracy Pictures", + "zzz =2013.0 Winter Tracy Pictures", + "zzz =2013.1 Spring Tracy Pictures", + "zzz =2013.2 Summer Tracy Pictures", + "zzz =2013.3 Fall Tracy Pictures", + "zzz =2013.4 Winter Tracy Pictures", + "zzz =2014.0 Winter Tracy Pictures", + "zzz =2014.1 Spring Tracy Pictures", + "zzz =2014.2 Summer Tracy Pictures", + "zzz =2014.3 Fall Tracy Pictures", + "zzz =2014.4 Winter Tracy Pictures", + "zzz =2015.0 Winter Tracy Pictures" + ], + "MixedYearRelativePaths": [ + "Edited", + "Phares Slides", + "Rex Memorial", + "Scanned Grandma's Quilt", + "Scanned Pictures Of Kids", + "Scanned Prints", + "Slide in Name Order Originals (622)", + "Slides Pictures" + ], + "IgnoreRelativePaths": [ + "3757 W Whitman 2017", + "501 Playful Meadows 2006", + "501 Playful Meadows 2007", + "501 Playful Meadows 2008", + "501 Playful Meadows 2009", + "501 Playful Meadows 2010", + "501 Playful Meadows 2013", + "501 Playful Meadows 2015", + "6309 Evesham 2003", + "6309 Evesham 2004", + "Crystal's Wedding 2003", + "Danny's Wedding 2009", + "Door images 2019", + "Family Pictures 2006", + "Family Pictures 2007", + "Family Pictures 2011", + "Family Pictures 2013", + "GrandPrix 2004", + "Kids School Pictures 2004", + "Kristy 2002", + "Kristy Parents Wedding 2005", + "Logan Ultrasound 2007", + "Mandy's Dogs 2008", + "Motorcycles 2010", + "Motorcycles 2013", + "Motorcycles 2014", + "Phares Slides", + "Portrait Innovations April 2008", + "Portrait Innovations December 2007", + "Portrait Innovations June 2008", + "Portrait Innovations March 2012", + "The guys house 2000", + "Tracy Pictures 2005", + "Tracy Pictures 2006", + "Tracy Pictures 2007", + "Tracy Pictures 2008", + "Tracy Pictures 2009", + "Tracy Pictures 2010", + "Tracy Pictures 2011", + "Tracy Pictures 2012", + "Tracy Pictures 2013 Jan-July", + "Tracy Pictures 2013 July- Dec", + "Tracy Pictures 2014", + "Tracy Pictures 2015", + "Tracy Took The Kids 2006", + "Tracy's Bday 2012", + "Tracy's Wedding 2002", + "Trip to Colorado 10 2002", + "Trip to Colorado June 2002", + "Tub 2002", + "Vericruz 2011" + ] + } + } +} \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/appsettings.json b/TestsWithFaceRecognitionDotNet/appsettings.json new file mode 100644 index 0000000..5c1042e --- /dev/null +++ b/TestsWithFaceRecognitionDotNet/appsettings.json @@ -0,0 +1,525 @@ +{ + "Company": "Mike Phares", + "Linux": {}, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Log4netProvider": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "MaxDegreeOfParallelism": 12, + "Serilog": { + "Using": [ + "Serilog.Sinks.Console", + "Serilog.Sinks.File" + ], + "MinimumLevel": "Debug", + "WriteTo": [ + { + "Name": "Debug", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "Console", + "Args": { + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "%workingDirectory% - Log/log-.txt", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}", + "rollingInterval": "Hour" + } + } + ], + "Enrich": [ + "FromLogContext", + "WithMachineName", + "WithThreadId" + ], + "Properties": { + "Application": "Sample" + } + }, + "WorkingDirectoryName": "PharesApps", + "Windows": { + "Configuration": { + "CheckJsonForDistanceResults": true, + "CrossDirectoryMaxItemsInDistanceCollection": 7, + "DateGroup": "2022-07-27", + "DistanceFactor": 8, + "FileNameDirectorySeparator": ".Z.", + "ForceMetadataLastWriteTimeToCreationTime": false, + "ForcePropertyLastWriteTimeToCreationTime": false, + "ForceResizeLastWriteTimeToCreationTime": false, + "LoadOrCreateThenSaveIndex": false, + "LocationConfidenceFactor": 2, + "MappedMaxIndex": 1034720, + "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "MaxItemsInDistanceCollection": 50, + "ModelDirectory": "C:/GitHub/dlib-models", + "ModelName": "Hog", + "NumberOfJitters": 1, + "NumberOfTimesToUpsample": 1, + "OutputExtension": ".jpg", + "OutputQuality": 95, + "OverrideForFaceImages": false, + "OverrideForFaceLandmarkImages": false, + "OverrideForResizeImages": false, + "PaddingLoops": 5, + "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", + "PopulatePropertyId": true, + "PredictorModelName": "Large", + "PropertiesChangedForDistance": false, + "PropertiesChangedForFaces": false, + "PropertiesChangedForIndex": false, + "PropertiesChangedForMetadata": false, + "PropertiesChangedForProperty": false, + "PropertiesChangedForResize": false, + "Reverse": false, + "RootDirectory": "D:/Images", + "SaveFullYearOfRandomFiles": true, + "SaveResizedSubFiles": true, + "SkipSearch": false, + "TestDistanceResults": true, + "WriteBitmapDataBytes": false, + "IgnoreExtensions": [ + ".gif", + ".GIF" + ], + "JuliePhares": [ + "1500-01-16_00", + "1500-01-19_00", + "1500-01-20_00", + "1500-01-21_00", + "1500-01-25_00", + "1500-01-26_00", + "1500-01-27_00", + "1500-02-13_00", + "1500-02-17_00", + "1500-02-24_00", + "1500-02-25_00", + "1500-04-03_00", + "1500-04-06_00", + "1500-04-19_00", + "1500-05-03_00", + "1500-05-18_00", + "1500-05-28_00", + "1500-06-16_00", + "1500-06-26_00", + "1500-06-27_00", + "1500-07-07_00", + "1500-07-16_00", + "1720-09-30_05", + "1500-07-26_00", + "1500-08-03_00", + "1500-08-23_00", + "1500-08-24_00", + "1500-09-16_00", + "1500-09-21_00", + "1500-09-28_00", + "1500-10-14_00", + "1500-11-07_00", + "1500-11-09_00", + "1720-09-28_20", + "1501-01-08_00", + "1501-01-12_00", + "1501-01-13_00", + "1501-01-30_00", + "1501-03-09_00", + "1501-03-14_00", + "1501-03-22_00", + "1501-04-07_00", + "1501-04-10_00", + "1501-04-19_00", + "1501-05-06_00", + "1956-09-19_00", + "2012-09-17_00", + "1998-05-21_00", + "1960-03-01_00", + "1976-03-08_00", + "2007-09-07_00", + "2000-04-07_00", + "1980-01-17_00", + "1958-01-30_00", + "1976-01-05_00", + "1982-05-02_00" + ], + "LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions": [ + "1920 x 1080" + ], + "LoadOrCreateThenSaveDistanceResultsForOutputResolutions": [ + "1920 x 1080" + ], + "LoadOrCreateThenSaveImageFacesResultsForOutputResolutions": [ + "1920 x 1080" + ], + "OutputResolutions": [ + "176 x 176", + "256 x 256", + "353 x 353", + "1024 x 768", + "1920 x 1080" + ], + "PropertyContentCollectionFiles": [], + "SaveFaceLandmarkForOutputResolutions": [ + "176 x 176", + "256 x 256" + ], + "SaveShortcutsForOutputResolutions": [ + "1920 x 1080" + ], + "ValidImageFormatExtensions": [ + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "ValidMetadataExtensions": [ + ".3gp", + ".3GP", + ".amr", + ".AMR", + ".avi", + ".AVI", + ".bmp", + ".BMP", + ".gif", + ".GIF", + ".ico", + ".ICO", + ".jpeg", + ".JPEG", + ".jpg", + ".JPG", + ".m4v", + ".M4V", + ".mov", + ".MOV", + ".mp4", + ".MP4", + ".mta", + ".MTA", + ".png", + ".PNG", + ".tiff", + ".TIFF" + ], + "ValidResolutions": [ + "176 x 176", + "256 x 256", + "353 x 353", + "1024 x 768", + "1280 x 720", + "1280 x 800", + "1376 x 768", + "1600 x 1200", + "1920 x 1080", + "2256 x 1496", + "3840 x 2160", + "7680 x 4320" + ], + "VerifyToSeason": [ + ". 2000", + ". 2001", + ". 2002", + ". 2003", + ". 2004", + ". 2005", + ". 2006", + ". 2007", + ". 2008", + ". 2009", + ". 2010", + ". 2011", + ". 2012", + ". 2013", + ". 2014", + ". 2015", + ". 2016", + ". 2017", + ". 2018", + ". 2019", + ". 2020", + ". 2021", + ". 2022", + ". 2023", + ". 2024", + ". 2025", + ". 2026", + ". 2027", + ". 2028", + ". 2029", + "=2000.0 Winter", + "=2002.1 Spring", + "=2002.4 Winter", + "=2003.0 Winter", + "=2003.1 Spring", + "=2003.3 Fall", + "=2003.4 Winter", + "=2004.0 Winter", + "=2005.1 Spring", + "=2005.2 Summer", + "=2005.3 Fall", + "=2005.4 Winter", + "=2006.0 Winter", + "=2006.1 Spring", + "=2006.3 Fall", + "=2007.0 Winter", + "=2007.2 Summer Logan Michael", + "=2007.2 Summer", + "=2007.3 Fall Logan Michael", + "=2007.4 Winter Logan Michael", + "=2008.0 Winter Logan Michael", + "=2008.1 Spring Logan Michael", + "=2008.2 Summer Logan Michael", + "=2008.2 Summer", + "=2008.3 Fall Logan Michael", + "=2009.0 Winter Logan Michael", + "=2009.0 Winter", + "=2009.1 Spring Logan Michael", + "=2009.1 Spring", + "=2009.2 Summer Logan Michael", + "=2009.2 Summer", + "=2009.3 Fall Logan Michael", + "=2009.3 Fall", + "=2009.4 Winter Logan Michael", + "=2009.4 Winter", + "=2010.0 Winter Logan Michael", + "=2010.0 Winter", + "=2010.1 Spring Logan Michael", + "=2010.1 Spring", + "=2010.2 Summer", + "=2010.3 Fall Logan Michael", + "=2010.3 Fall", + "=2010.4 Winter", + "=2011.0 Winter", + "=2011.1 Spring", + "=2011.2 Summer", + "=2011.3 Fall", + "=2011.4 Winter", + "=2012.0 Winter Chelsea 2012", + "=2012.0 Winter Chelsea", + "=2012.0 Winter", + "=2012.1 Spring Chelsea", + "=2012.1 Spring", + "=2012.2 Summer Chelsea", + "=2012.2 Summer", + "=2012.3 Fall Chelsea", + "=2012.3 Fall", + "=2012.4 Winter Chelsea", + "=2012.4 Winter", + "=2013.0 Winter Chelsea 2013", + "=2013.0 Winter Chelsea", + "=2013.0 Winter", + "=2013.1 Spring", + "=2013.2 Summer Chelsea", + "=2013.2 Summer", + "=2013.3 Fall Chelsea", + "=2013.3 Fall", + "=2013.4 Winter", + "=2014.0 Winter", + "=2014.1 Spring", + "=2014.2 Summer", + "=2014.3 Fall", + "=2014.4 Winter", + "=2015.0 Winter", + "=2015.1 Spring", + "=2015.2 Summer", + "=2015.3 Fall", + "=2015.4 Winter", + "=2016.0 Winter", + "=2016.1 Spring", + "=2016.2 Summer", + "=2016.3 Fall", + "=2016.4 Winter", + "=2017.1 Spring", + "=2017.2 Summer", + "=2017.3 Fall", + "=2017.4 Winter", + "=2018.0 Winter", + "=2018.1 Spring", + "=2018.3 Fall", + "=2018.4 Winter", + "=2019.0 Winter", + "=2019.1 Spring", + "=2019.2 Summer", + "=2019.3 Fall", + "=2019.4 Winter", + "=2020.0 Winter", + "=2020.1 Spring", + "=2020.2 Summer", + "=2020.3 Fall", + "=2020.4 Winter", + "=2021.1 Spring", + "=2021.2 Summer", + "=2021.3 Fall", + "=2021.4 Winter", + "=2022.0 Winter", + "=2022.1 Spring", + "Anthem 2015", + "April 2010", + "April 2013", + "December 2006", + "December 2010", + "Fall 2005", + "Fall 2015", + "Fall 2016", + "Fall 2017", + "Fall 2018", + "Fall 2019", + "Fall 2020", + "Fall 2021", + "February 2010", + "January 2015", + "July 2010", + "June 2010", + "Kids 2005", + "March 2013", + "May 2010", + "May 2011", + "May 2013", + "October 2005", + "October 2014", + "Spring 2013", + "Spring 2014", + "Spring 2016", + "Spring 2018", + "Spring 2019", + "Spring 2020", + "Summer 2011", + "Summer 2012", + "Summer 2013", + "Summer 2014", + "Summer 2015", + "Summer 2016", + "Summer 2017", + "Summer 2018", + "Summer 2020", + "Summer 2021", + "Winter 2015", + "Winter 2016", + "Winter 2017", + "Winter 2018", + "Winter 2019-2020", + "Winter 2020", + "zzz =2005.0 Winter Tracy Pictures", + "zzz =2005.1 Spring Tracy Pictures", + "zzz =2005.2 Summer Tracy Pictures", + "zzz =2005.3 Fall Tracy Pictures", + "zzz =2005.4 Winter Tracy Pictures", + "zzz =2006.1 Spring Tracy Pictures", + "zzz =2007.0 Winter Tracy Pictures", + "zzz =2007.2 Summer Tracy Pictures", + "zzz =2008.0 Winter Tracy Pictures", + "zzz =2008.2 Summer Tracy Pictures", + "zzz =2009.0 Winter Tracy Pictures", + "zzz =2009.2 Summer Tracy Pictures", + "zzz =2009.3 Fall Tracy Pictures", + "zzz =2009.4 Winter Tracy Pictures", + "zzz =2010.0 Winter Tracy Pictures", + "zzz =2010.1 Spring Tracy Pictures", + "zzz =2010.2 Summer Tracy Pictures", + "zzz =2010.3 Fall Tracy Pictures", + "zzz =2011.0 Winter Tracy Pictures", + "zzz =2011.1 Spring Tracy Pictures", + "zzz =2011.2 Summer Tracy Pictures", + "zzz =2011.3 Fall Tracy Pictures", + "zzz =2011.4 Winter Tracy Pictures", + "zzz =2012.0 Winter Tracy Pictures", + "zzz =2012.1 Spring Tracy Pictures", + "zzz =2012.2 Summer Tracy Pictures", + "zzz =2012.3 Fall Tracy Pictures", + "zzz =2012.4 Winter Tracy Pictures", + "zzz =2013.0 Winter Tracy Pictures", + "zzz =2013.1 Spring Tracy Pictures", + "zzz =2013.2 Summer Tracy Pictures", + "zzz =2013.3 Fall Tracy Pictures", + "zzz =2013.4 Winter Tracy Pictures", + "zzz =2014.0 Winter Tracy Pictures", + "zzz =2014.1 Spring Tracy Pictures", + "zzz =2014.2 Summer Tracy Pictures", + "zzz =2014.3 Fall Tracy Pictures", + "zzz =2014.4 Winter Tracy Pictures", + "zzz =2015.0 Winter Tracy Pictures" + ], + "MixedYearRelativePaths": [ + "Edited", + "Phares Slides", + "Rex Memorial", + "Scanned Grandma's Quilt", + "Scanned Pictures Of Kids", + "Scanned Prints", + "Slide in Name Order Originals (622)", + "Slides Pictures" + ], + "IgnoreRelativePaths": [ + "3757 W Whitman 2017", + "501 Playful Meadows 2006", + "501 Playful Meadows 2007", + "501 Playful Meadows 2008", + "501 Playful Meadows 2009", + "501 Playful Meadows 2010", + "501 Playful Meadows 2013", + "501 Playful Meadows 2015", + "6309 Evesham 2003", + "6309 Evesham 2004", + "Crystal's Wedding 2003", + "Danny's Wedding 2009", + "Door images 2019", + "Family Pictures 2006", + "Family Pictures 2007", + "Family Pictures 2011", + "Family Pictures 2013", + "GrandPrix 2004", + "Kids School Pictures 2004", + "Kristy 2002", + "Kristy Parents Wedding 2005", + "Logan Ultrasound 2007", + "Mandy's Dogs 2008", + "Motorcycles 2010", + "Motorcycles 2013", + "Motorcycles 2014", + "Phares Slides", + "Portrait Innovations April 2008", + "Portrait Innovations December 2007", + "Portrait Innovations June 2008", + "Portrait Innovations March 2012", + "The guys house 2000", + "Tracy Pictures 2005", + "Tracy Pictures 2006", + "Tracy Pictures 2007", + "Tracy Pictures 2008", + "Tracy Pictures 2009", + "Tracy Pictures 2010", + "Tracy Pictures 2011", + "Tracy Pictures 2012", + "Tracy Pictures 2013 Jan-July", + "Tracy Pictures 2013 July- Dec", + "Tracy Pictures 2014", + "Tracy Pictures 2015", + "Tracy Took The Kids 2006", + "Tracy's Bday 2012", + "Tracy's Wedding 2002", + "Trip to Colorado 10 2002", + "Trip to Colorado June 2002", + "Tub 2002", + "Vericruz 2011" + ] + } + } +} \ No newline at end of file diff --git a/View-by-Distance-MKLink-Console.sln b/View-by-Distance-MKLink-Console.sln index 3dfaebb..12ddf8d 100644 --- a/View-by-Distance-MKLink-Console.sln +++ b/View-by-Distance-MKLink-Console.sln @@ -27,6 +27,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FaceRecognitionDotNet", "FaceRecognitionDotNet\FaceRecognitionDotNet.csproj", "{FAD03DA9-E8B1-4BBE-B8D0-2ADD2F2BC758}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestsWithFaceRecognitionDotNet", "TestsWithFaceRecognitionDotNet\TestsWithFaceRecognitionDotNet.csproj", "{A67D73C7-A1A1-4443-B681-776339CFA08A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -84,5 +86,9 @@ Global {FAD03DA9-E8B1-4BBE-B8D0-2ADD2F2BC758}.Debug|Any CPU.Build.0 = Debug|Any CPU {FAD03DA9-E8B1-4BBE-B8D0-2ADD2F2BC758}.Release|Any CPU.ActiveCfg = Release|Any CPU {FAD03DA9-E8B1-4BBE-B8D0-2ADD2F2BC758}.Release|Any CPU.Build.0 = Release|Any CPU + {A67D73C7-A1A1-4443-B681-776339CFA08A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A67D73C7-A1A1-4443-B681-776339CFA08A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A67D73C7-A1A1-4443-B681-776339CFA08A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A67D73C7-A1A1-4443-B681-776339CFA08A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal