diff --git a/.kanbn/index.md b/.kanbn/index.md index 9e37da4..3297951 100644 --- a/.kanbn/index.md +++ b/.kanbn/index.md @@ -15,7 +15,6 @@ completedColumns: - [nef-support](tasks/nef-support.md) - [determine-if-location-container-collection-is-needed-in-get-faces](tasks/determine-if-location-container-collection-is-needed-in-get-faces.md) -- [use-eyes-to-find-orientation](tasks/use-eyes-to-find-orientation.md) - [use-photo-prism-to-map](tasks/use-photo-prism-to-map.md) - [import-face-region-metadata](tasks/import-face-region-metadata.md) @@ -26,6 +25,7 @@ completedColumns: - [run-scan-originals](tasks/run-scan-originals.md) - [find-incorrectly-mapped-faces](tasks/find-incorrectly-mapped-faces.md) - [shrink-percent](tasks/shrink-percent.md) +- [use-eyes-to-find-orientation](tasks/use-eyes-to-find-orientation.md) ## Done diff --git a/.kanbn/tasks/use-eyes-to-find-orientation.md b/.kanbn/tasks/use-eyes-to-find-orientation.md index 4f97d08..2870bf7 100644 --- a/.kanbn/tasks/use-eyes-to-find-orientation.md +++ b/.kanbn/tasks/use-eyes-to-find-orientation.md @@ -10,4 +10,4 @@ tags: [] ## Sub-tasks -- [ ] asdf +- [ ] 1006207980 diff --git a/FaceParts/Models/_D2_FaceParts.cs b/FaceParts/Models/_D2_FaceParts.cs index 74215c6..3e25801 100644 --- a/FaceParts/Models/_D2_FaceParts.cs +++ b/FaceParts/Models/_D2_FaceParts.cs @@ -216,7 +216,7 @@ public class D2_FaceParts } if (saveRotated && face.FaceParts is not null) { - α = Shared.Models.Stateless.Methods.IFace.Getα(face.FaceParts); + (_, α) = Shared.Models.Stateless.Methods.IFace.GetEyeα(face.FaceParts); if (α is null) continue; using Image image = Image.FromFile(resizedFileHolder.FullName); diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index cfcc717..49b3069 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -290,6 +290,9 @@ public partial class DlibDotNet private void SetMapping(MapLogic mapLogic, Item item, bool? isFocusRelativePath, bool? isIgnoreRelativePath, MappingFromItem mappingFromItem, List? mappingFromPhotoPrismCollection, List faces) { + double? α; + int? eyeα; + bool? eyeReview; Mapping mapping; int faceAreaPermyriad; int confidencePercent; @@ -309,11 +312,18 @@ public partial class DlibDotNet } else { + if (face.FaceParts is null) + (eyeα, eyeReview) = (null, null); + else + { + (eyeReview, α) = Shared.Models.Stateless.Methods.IFace.GetEyeα(face.FaceParts); + eyeα = α is null ? null : (int)Math.Round(Math.Abs(α.Value)); + } confidencePercent = Shared.Models.Stateless.Methods.ILocation.GetConfidencePercent(_Configuration.FaceConfidencePercent, _Configuration.RangeFaceConfidence, face.Location.Confidence); faceAreaPermyriad = Shared.Models.Stateless.Methods.IMapping.GetAreaPermyriad(_Configuration.FaceAreaPermyriad, face.Location, face.OutputResolution); wholePercentRectangle = Shared.Models.Stateless.Methods.ILocation.GetWholePercentages(face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); - mappingFromLocation = new(faceAreaPermyriad, confidencePercent, deterministicHashCodeKey, wholePercentRectangle); + mappingFromLocation = new(faceAreaPermyriad, confidencePercent, deterministicHashCodeKey, eyeα, eyeReview, wholePercentRectangle); inSkipCollection = mapLogic.InSkipCollection(item.Property.Id.Value, mappingFromLocation); mappingFromFilter = new(isFocusModel, isFocusRelativePath, isIgnoreRelativePath, inSkipCollection); } @@ -326,6 +336,8 @@ public partial class DlibDotNet private Mapping GetMapping(MapLogic mapLogic, Item item, bool? isFocusRelativePath, bool? isIgnoreRelativePath, MappingFromItem mappingFromItem) { Mapping result; + int? eyeα = null; + bool? eyeReview = null; bool? inSkipCollection; int wholePercentRectangle; int faceAreaPermyriad = 0; @@ -344,7 +356,7 @@ public partial class DlibDotNet { wholePercentRectangle = Shared.Models.Stateless.Methods.ILocation.GetWholePercentages(Shared.Models.Stateless.ILocation.Digits); deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, Shared.Models.Stateless.ILocation.Digits); - mappingFromLocation = new(faceAreaPermyriad, confidencePercent, deterministicHashCodeKey, wholePercentRectangle); + mappingFromLocation = new(faceAreaPermyriad, confidencePercent, deterministicHashCodeKey, eyeα, eyeReview, wholePercentRectangle); inSkipCollection = mapLogic.InSkipCollection(item.Property.Id.Value, mappingFromLocation); mappingFromFilter = new(isFocusModel, isFocusRelativePath, isIgnoreRelativePath, inSkipCollection); } @@ -381,6 +393,7 @@ public partial class DlibDotNet string outputResolution, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, + string d2ResultsFullGroupDirectory, List> sourceDirectoryChanges, Dictionary> fileNameToCollection, Container container, @@ -436,8 +449,8 @@ public partial class DlibDotNet if (property is null || item.Property is null) throw new NullReferenceException(nameof(property)); item.SetResizedFileHolder(_Resize.FileNameExtension, resizedFileHolder); - string facesDirectory = _Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution) ? _Faces.GetFacesDirectory(dResultsFullGroupDirectory, item) : string.Empty; - string facePartsDirectory = _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution) ? _FaceParts.GetFacePartsDirectory(_Configuration.PropertyConfiguration, dResultsFullGroupDirectory, item, includeNameWithoutExtension: true) : string.Empty; + string? facesDirectory = !_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution) ? null : _Faces.GetFacesDirectory(dResultsFullGroupDirectory, item); + string? facePartsDirectory = !_Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution) ? null : _FaceParts.GetFacePartsDirectory(_Configuration.PropertyConfiguration, dResultsFullGroupDirectory, item, includeNameWithoutExtension: true); MappingFromItem mappingFromItem = Shared.Models.Stateless.Methods.IMappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder); (int metadataGroups, metadataCollection) = metadata.GetMetadataCollection(subFileTuples, parseExceptions, mappingFromItem); if (_AppSettings.MaxDegreeOfParallelism < 2) @@ -451,9 +464,9 @@ public partial class DlibDotNet if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(C_Resize.SaveResizedSubfile)); } - if (!mappingFromItem.ResizedFileHolder.Exists && !File.Exists(mappingFromItem.ResizedFileHolder.FullName)) + if (facesDirectory is null) faces = new(); - else if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution)) + else if (!mappingFromItem.ResizedFileHolder.Exists && !File.Exists(mappingFromItem.ResizedFileHolder.FullName)) faces = new(); else { @@ -468,8 +481,8 @@ public partial class DlibDotNet faces = _Faces.GetFaces(outputResolution, dResultsFullGroupDirectory, subFileTuples, parseExceptions, property, mappingFromItem, outputResolutionToResize, locationContainers, mappingFromPhotoPrismCollection); if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(D_Face.GetFaces)); - List<(Shared.Models.Face, FileInfo?, string, bool Saved)> faceCollection = _Faces.SaveFaces(_FaceParts.FileNameExtension, dResultsFullGroupDirectory, subFileTuples, parseExceptions, mappingFromItem, facesDirectory, faces); SetMapping(mapLogic, item, isFocusRelativePath, isIgnoreRelativePath, mappingFromItem, mappingFromPhotoPrismCollection, faces); + List<(Shared.Models.Face, FileInfo?, string, bool Saved)> faceCollection = _Faces.SaveFaces(_FaceParts.FileNameExtension, dResultsFullGroupDirectory, subFileTuples, parseExceptions, mappingFromItem, facesDirectory, faces); if (_Configuration.CopyFacesAndSaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) _FaceParts.CopyFacesAndSaveFaceLandmarkImage(facePartsCollectionDirectory, mappingFromItem, faceCollection); if (_AppSettings.MaxDegreeOfParallelism < 2) @@ -478,10 +491,14 @@ public partial class DlibDotNet && _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution) && locationContainers is not null && faceCollection.All(l => !l.Saved)) _Distance.LookForMatchFacesAndPossiblyRename(_Faces.FileNameExtension, mappingFromItem, faces, locationContainers); - if (_Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) + (bool review, int[] eyesCollection) = Shared.Models.Stateless.Methods.IFace.GetEyeCollection(_Configuration.EyeThreshold, faces); + if (review || _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) { bool saveRotated = false; + if (!_Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) + _FaceParts.SetAngleBracketCollection(_Configuration.PropertyConfiguration, d2ResultsFullGroupDirectory, container.SourceDirectory); string sourceDirectorySegment = Property.Models.Stateless.IResult.GetRelativePath(_Configuration.PropertyConfiguration, container.SourceDirectory); + facePartsDirectory ??= _FaceParts.GetFacePartsDirectory(_Configuration.PropertyConfiguration, dResultsFullGroupDirectory, item, includeNameWithoutExtension: true); _FaceParts.SaveFaceLandmarkImages(_Configuration.PropertyConfiguration, facePartsDirectory, subFileTuples, parseExceptions, mappingFromItem, faces, saveRotated); if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(D2_FaceParts.SaveFaceLandmarkImages)); @@ -517,8 +534,8 @@ public partial class DlibDotNet ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; string focusRelativePath = Path.GetFullPath(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, _Configuration.FocusDirectory)); bool? isFocusRelativePath = string.IsNullOrEmpty(_Configuration.FocusDirectory) ? null : container.SourceDirectory.StartsWith(focusRelativePath); + string facePartsCollectionDirectory = _Configuration.CopyFacesAndSaveFaceLandmarkForOutputResolutions.Contains(outputResolution) ? _FaceParts.GetFacePartsDirectory(_Configuration.PropertyConfiguration, d2ResultsFullGroupDirectory, item: filteredItems.First(), includeNameWithoutExtension: false) : string.Empty; bool? isIgnoreRelativePath = !_Configuration.IgnoreRelativePaths.Any() ? null : _Configuration.IgnoreRelativePaths.Any(l => container.SourceDirectory.Contains(l)) && Shared.Models.Stateless.Methods.IContainer.IsIgnoreRelativePath(_Configuration.PropertyConfiguration, _Configuration.IgnoreRelativePaths, container.SourceDirectory); - string facePartsCollectionDirectory = _Configuration.CopyFacesAndSaveFaceLandmarkForOutputResolutions.Contains(outputResolution) || _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution) ? _FaceParts.GetFacePartsDirectory(_Configuration.PropertyConfiguration, d2ResultsFullGroupDirectory, item: filteredItems.First(), includeNameWithoutExtension: false) : string.Empty; using ProgressBar progressBar = new(filteredItems.Length, message, options); _ = Parallel.For(0, filteredItems.Length, parallelOptions, (i, state) => { @@ -531,6 +548,7 @@ public partial class DlibDotNet outputResolution, cResultsFullGroupDirectory, dResultsFullGroupDirectory, + d2ResultsFullGroupDirectory, sourceDirectoryChanges, fileNameToCollection, container, diff --git a/Instance/Models/Binder/Configuration.cs b/Instance/Models/Binder/Configuration.cs index 1b96d50..ace89cc 100644 --- a/Instance/Models/Binder/Configuration.cs +++ b/Instance/Models/Binder/Configuration.cs @@ -19,6 +19,7 @@ public class Configuration [Display(Name = "Distance Move Unable to Match by 1 Tick"), Required] public bool? DistanceMoveUnableToMatch { get; set; } [Display(Name = "Distance Pixel Distance Tolerance"), Required] public int? DistancePixelDistanceTolerance { get; set; } [Display(Name = "Distance Rename to Match"), Required] public bool? DistanceRenameToMatch { get; set; } + [Display(Name = "Eye Threshold"), Required] public int? EyeThreshold { get; set; } [Display(Name = "Face Area Permille"), Required] public int? FaceAreaPermyriad { get; set; } [Display(Name = "Face Distance Hidden Image Factor"), Required] public int? FaceDistanceHiddenImageFactor { get; set; } [Display(Name = "Face Confidence Percent"), Required] public int? FaceConfidencePercent { get; set; } @@ -121,6 +122,8 @@ public class Configuration throw new NullReferenceException(nameof(configuration.DistancePixelDistanceTolerance)); if (configuration.DistanceRenameToMatch is null) throw new NullReferenceException(nameof(configuration.DistanceRenameToMatch)); + if (configuration.EyeThreshold is null) + throw new NullReferenceException(nameof(configuration.EyeThreshold)); if (configuration.FaceAreaPermyriad is null) throw new NullReferenceException(nameof(configuration.FaceAreaPermyriad)); if (configuration.FaceDistanceHiddenImageFactor is null) @@ -249,6 +252,7 @@ public class Configuration configuration.DistanceMoveUnableToMatch.Value, configuration.DistancePixelDistanceTolerance.Value, configuration.DistanceRenameToMatch.Value, + configuration.EyeThreshold.Value, configuration.FaceAreaPermyriad.Value, configuration.FaceConfidencePercent.Value, configuration.FaceDistanceHiddenImageFactor.Value, diff --git a/Instance/Models/Configuration.cs b/Instance/Models/Configuration.cs index a5e69ce..a9b9b7e 100644 --- a/Instance/Models/Configuration.cs +++ b/Instance/Models/Configuration.cs @@ -7,6 +7,7 @@ public class Configuration { protected Property.Models.Configuration _PropertyConfiguration; + public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration; public bool CheckDFaceAndUpWriteDates { init; get; } @@ -18,6 +19,7 @@ public class Configuration public bool DistanceMoveUnableToMatch { init; get; } public int DistancePixelDistanceTolerance { init; get; } public bool DistanceRenameToMatch { init; get; } + public int EyeThreshold { init; get; } public int FaceAreaPermyriad { init; get; } public int FaceDistanceHiddenImageFactor { init; get; } public int FaceConfidencePercent { init; get; } @@ -98,6 +100,7 @@ public class Configuration bool distanceMoveUnableToMatch, int distancePixelDistanceTolerance, bool distanceRenameToMatch, + int eyeThreshold, int faceAreaPermyriad, int faceConfidencePercent, int faceDistanceHiddenImageFactor, @@ -177,6 +180,7 @@ public class Configuration DistanceMoveUnableToMatch = distanceMoveUnableToMatch; DistancePixelDistanceTolerance = distancePixelDistanceTolerance; DistanceRenameToMatch = distanceRenameToMatch; + EyeThreshold = eyeThreshold; FaceAreaPermyriad = faceAreaPermyriad; FaceDistanceHiddenImageFactor = faceDistanceHiddenImageFactor; FaceConfidencePercent = faceConfidencePercent; diff --git a/Instance/appsettings.json b/Instance/appsettings.json index 061eab2..504d6bb 100644 --- a/Instance/appsettings.json +++ b/Instance/appsettings.json @@ -59,6 +59,7 @@ "DistanceMoveUnableToMatch": false, "DistancePixelDistanceTolerance": 1, "DistanceRenameToMatch": false, + "EyeThreshold": 33, "FaceAreaPermyriad": 10000, "FaceDistanceHiddenImageFactor": 2, "FaceConfidencePercent": 100, diff --git a/Rename/Rename.cs b/Rename/Rename.cs index c435833..f6810b4 100644 --- a/Rename/Rename.cs +++ b/Rename/Rename.cs @@ -154,12 +154,14 @@ public class Rename DateTime dateTime; string seasonName; string? directory; + bool? isWrongYear; TimeSpan? timeSpan; + string directoryName; DateTime?[] dateTimes; FileHolder fileHolder; string[]? ffmpegFiles; - string seasonDirectory; bool isIgnoreExtension; + string? seasonDirectory; const string jpg = ".jpg"; DateTime? minimumDateTime; string checkFileExtension; @@ -167,6 +169,7 @@ public class Rename DateTime? dateTimeOriginal; const string jpeg = ".jpeg"; List distinct = new(); + string[] directoryNameSegments; bool isValidImageFormatExtension; bool nameWithoutExtensionIsIdFormat; DateTime? metadataMinimumDateTime = null; @@ -272,7 +275,10 @@ public class Rename if (minimumDateTime is null) break; if (dateTimeOriginal is not null && dateTimeFromName is not null) - timeSpan = new(Math.Abs(minimumDateTime.Value.Ticks - new long[] { dateTimeOriginal.Value.Ticks, dateTimeFromName.Value.Ticks }.Min())); + { + timeSpan = new(Math.Abs(dateTimeOriginal.Value.Ticks - dateTimeFromName.Value.Ticks)); + timeSpan = timeSpan.Value.TotalMinutes > _AppSettings.MaxMinutesDelta ? null : new(Math.Abs(minimumDateTime.Value.Ticks - new long[] { dateTimeOriginal.Value.Ticks, dateTimeFromName.Value.Ticks }.Min())); + } else if (dateTimeFromName is not null) timeSpan = new(Math.Abs(minimumDateTime.Value.Ticks - dateTimeFromName.Value.Ticks)); else if (dateTimeOriginal is not null) @@ -290,7 +296,18 @@ public class Rename else timeSpan = new(Math.Abs(minimumDateTime.Value.Ticks - metadataMinimumDateTime.Value.Ticks)); } - if (timeSpan is null || timeSpan.Value.TotalMinutes >= _AppSettings.MaxMinutesDelta) + if (timeSpan is null || timeSpan.Value.TotalMinutes > _AppSettings.MaxMinutesDelta) + (isWrongYear, seasonDirectory) = (null, null); + else + { + directoryName = Path.GetFileName(fileHolder.DirectoryName); + directoryNameSegments = directoryName.Split(' '); + (isWrongYear, _) = Shared.Models.Stateless.Methods.IProperty.IsWrongYear(directoryNameSegments, string.Empty); + dateTime = minimumDateTime.Value.AddTicks(timeSpan.Value.Ticks); + (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); + seasonDirectory = Path.Combine(fileHolder.DirectoryName, $"{dateTime.Year}.{season} {seasonName}"); + } + if (seasonDirectory is null || isWrongYear is null || isWrongYear.Value) { if (metadataMinimumDateTime is null) break; @@ -312,9 +329,6 @@ public class Rename { if (id is null) continue; - dateTime = minimumDateTime.Value.AddTicks(timeSpan.Value.Ticks); - (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); - seasonDirectory = Path.Combine(fileHolder.DirectoryName, $"{dateTime.Year}.{season} {seasonName}"); if (ffmpegFiles is not null) { foreach (string ffmpegFile in ffmpegFiles) diff --git a/Shared/Models/MappingFromLocation.cs b/Shared/Models/MappingFromLocation.cs index ea65b53..c1586a0 100644 --- a/Shared/Models/MappingFromLocation.cs +++ b/Shared/Models/MappingFromLocation.cs @@ -9,14 +9,18 @@ public class MappingFromLocation : Properties.IMappingFromLocation public int AreaPermyriad { init; get; } public int ConfidencePercent { init; get; } public string DeterministicHashCodeKey { init; get; } + public int? Eyeα { init; get; } + public bool? EyeReview { init; get; } public int WholePercentages { init; get; } [JsonConstructor] - public MappingFromLocation(int areaPermyriad, int confidencePercent, string deterministicHashCodeKey, int wholePercentages) + public MappingFromLocation(int areaPermyriad, int confidencePercent, string deterministicHashCodeKey, int? eyeα, bool? eyeReview, int wholePercentages) { AreaPermyriad = areaPermyriad; ConfidencePercent = confidencePercent; DeterministicHashCodeKey = deterministicHashCodeKey; + Eyeα = eyeα; + EyeReview = eyeReview; WholePercentages = wholePercentages; } diff --git a/Shared/Models/Properties/IMappingFromLocation.cs b/Shared/Models/Properties/IMappingFromLocation.cs index f86df94..a1502ed 100644 --- a/Shared/Models/Properties/IMappingFromLocation.cs +++ b/Shared/Models/Properties/IMappingFromLocation.cs @@ -6,6 +6,8 @@ public interface IMappingFromLocation public int AreaPermyriad { init; get; } public int ConfidencePercent { init; get; } public string DeterministicHashCodeKey { init; get; } + public int? Eyeα { init; get; } + public bool? EyeReview { init; get; } public int WholePercentages { init; get; } } diff --git a/Shared/Models/Stateless/Methods/Face.cs b/Shared/Models/Stateless/Methods/Face.cs index 81a6821..11ecef4 100644 --- a/Shared/Models/Stateless/Methods/Face.cs +++ b/Shared/Models/Stateless/Methods/Face.cs @@ -94,9 +94,11 @@ internal abstract class Face return result; } - internal static double? Getα(Dictionary faceParts) + internal static (bool?, double?) GetEyeα(Dictionary faceParts) { + bool? review; double? result; + int? lipY = null; int? leftEyeX = null; int? leftEyeY = null; int? rightEyeX = null; @@ -115,12 +117,32 @@ internal abstract class Face rightEyeX = (int)(from l in facePoints select l.X).Average(); rightEyeY = (int)(from l in facePoints select l.Y).Average(); } + if (facePart is FacePart.BottomLip or FacePart.TopLip) + lipY ??= (int)(from l in facePoints select l.X).Average(); } if (rightEyeX is null || leftEyeX is null || rightEyeY is null || leftEyeY is null) - result = null; + (result, review) = (null, null); else + { + review = lipY < rightEyeY || lipY < leftEyeY; result = Getα(rightEyeX.Value, leftEyeX.Value, rightEyeY.Value, leftEyeY.Value); - return result; + } + return (review, result); + } + + internal static (bool, int[]) GetEyeCollection(int threshold, List faces) + { + bool result = false; + List results = new(); + foreach (Shared.Models.Face face in faces) + { + if (face.Mapping?.MappingFromLocation?.Eyeα is null || face.Mapping.MappingFromLocation.EyeReview is null) + continue; + results.Add(face.Mapping.MappingFromLocation.Eyeα.Value); + if (!result && face.Mapping.MappingFromLocation.EyeReview.Value || face.Mapping.MappingFromLocation.Eyeα.Value > threshold) + result = true; + } + return (result, results.ToArray()); } } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IFace.cs b/Shared/Models/Stateless/Methods/IFace.cs index 3f9e597..01d84a8 100644 --- a/Shared/Models/Stateless/Methods/IFace.cs +++ b/Shared/Models/Stateless/Methods/IFace.cs @@ -23,9 +23,14 @@ public interface IFace static Models.Face[] GetFaces(string jsonFileFullName) => Face.GetFaces(jsonFileFullName); - double? TestStatic_Getα(Dictionary faceParts) => - Getα(faceParts); - static double? Getα(Dictionary faceParts) => - Face.Getα(faceParts); + (bool?, double?) TestStatic_Getα(Dictionary faceParts) => + GetEyeα(faceParts); + static (bool?, double?) GetEyeα(Dictionary faceParts) => + Face.GetEyeα(faceParts); + + (bool, int[]) TestStatic_GetEyeCollection(int threshold, List faces) => + GetEyeCollection(threshold, faces); + static (bool, int[]) GetEyeCollection(int threshold, List faces) => + Face.GetEyeCollection(threshold, faces); } \ No newline at end of file