MapFaceFileLogic
Author:
This commit is contained in:
parent
7f8b09e66c
commit
dca487deb3
@ -1,10 +1,13 @@
|
|||||||
using ShellProgressBar;
|
using ShellProgressBar;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Data;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using View_by_Distance.FaceRecognitionDotNet;
|
using View_by_Distance.FaceRecognitionDotNet;
|
||||||
|
using View_by_Distance.Map.Models;
|
||||||
using View_by_Distance.Property.Models.Stateless;
|
using View_by_Distance.Property.Models.Stateless;
|
||||||
using View_by_Distance.Shared.Models;
|
using View_by_Distance.Shared.Models;
|
||||||
using View_by_Distance.Shared.Models.Methods;
|
using View_by_Distance.Shared.Models.Methods;
|
||||||
|
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
namespace View_by_Distance.Distance.Models;
|
namespace View_by_Distance.Distance.Models;
|
||||||
|
|
||||||
@ -136,11 +139,11 @@ public partial class E_Distance : IDistance
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<(Face, double?)> GetMatchingFacesByFaceEncoding(Face[] filteredFaces, string? json)
|
private static List<(Face, double?)> GetMatchingFacesByFaceEncoding(List<Face> faces, string? json)
|
||||||
{
|
{
|
||||||
List<(Face, double?)> results = [];
|
List<(Face, double?)> results = [];
|
||||||
string check;
|
string check;
|
||||||
foreach (Face face in filteredFaces)
|
foreach (Face face in faces)
|
||||||
{
|
{
|
||||||
if (json is null || face.FaceEncoding is null)
|
if (json is null || face.FaceEncoding is null)
|
||||||
continue;
|
continue;
|
||||||
@ -169,7 +172,7 @@ public partial class E_Distance : IDistance
|
|||||||
mappedFaceDirectory = Path.GetDirectoryName(file);
|
mappedFaceDirectory = Path.GetDirectoryName(file);
|
||||||
if (mappedFaceDirectory is null)
|
if (mappedFaceDirectory is null)
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
|
deterministicHashCodeKey = IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
|
||||||
checkFile = Path.Combine(mappedFaceDirectory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{facesFileNameExtension}");
|
checkFile = Path.Combine(mappedFaceDirectory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{facesFileNameExtension}");
|
||||||
if (checkFile == file)
|
if (checkFile == file)
|
||||||
continue;
|
continue;
|
||||||
@ -205,7 +208,7 @@ public partial class E_Distance : IDistance
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LookForMatchFacesAndPossiblyRename(IDistanceLimits distanceLimits, Shared.Models.Stateless.Methods.IFaceD dFace, FilePath filePath, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Face> faces, ReadOnlyCollection<LocationContainer> locationContainers)
|
public void LookForMatchFacesAndPossiblyRename(bool overrideForFaceImages, IDistanceLimits distanceLimits, IFaceD dFace, FilePath filePath, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Face> faces, ReadOnlyCollection<LocationContainer> locationContainers)
|
||||||
{
|
{
|
||||||
string? json;
|
string? json;
|
||||||
string[] matches;
|
string[] matches;
|
||||||
@ -213,9 +216,6 @@ public partial class E_Distance : IDistance
|
|||||||
List<Face> intersectFaces;
|
List<Face> intersectFaces;
|
||||||
Shared.Models.FaceEncoding? modelsFaceEncoding;
|
Shared.Models.FaceEncoding? modelsFaceEncoding;
|
||||||
List<(Face Face, double? Distance)> checkFaces = [];
|
List<(Face Face, double? Distance)> checkFaces = [];
|
||||||
Face[] filteredFaces = (from l in faces where l.FaceEncoding is not null && l.Location is not null && l.OutputResolution is not null select l).ToArray();
|
|
||||||
if (filteredFaces.Length != faces.Count)
|
|
||||||
checkFaces.Clear();
|
|
||||||
foreach (LocationContainer locationContainer in locationContainers)
|
foreach (LocationContainer locationContainer in locationContainers)
|
||||||
{
|
{
|
||||||
if (_Renamed.Contains(locationContainer.FilePath.FullName))
|
if (_Renamed.Contains(locationContainer.FilePath.FullName))
|
||||||
@ -236,8 +236,8 @@ public partial class E_Distance : IDistance
|
|||||||
MoveUnableToMatch(locationContainer.FilePath);
|
MoveUnableToMatch(locationContainer.FilePath);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (filteredFaces.Length > 0)
|
if (faces.Count > 0)
|
||||||
checkFaces.AddRange(GetMatchingFacesByFaceEncoding(filteredFaces, json));
|
checkFaces.AddRange(GetMatchingFacesByFaceEncoding(faces, json));
|
||||||
if (checkFaces.Count == 1)
|
if (checkFaces.Count == 1)
|
||||||
_Debug.Add(0);
|
_Debug.Add(0);
|
||||||
if (checkFaces.Count != 1 && !string.IsNullOrEmpty(json))
|
if (checkFaces.Count != 1 && !string.IsNullOrEmpty(json))
|
||||||
@ -246,9 +246,9 @@ public partial class E_Distance : IDistance
|
|||||||
modelsFaceEncoding = JsonSerializer.Deserialize<Shared.Models.FaceEncoding>(json);
|
modelsFaceEncoding = JsonSerializer.Deserialize<Shared.Models.FaceEncoding>(json);
|
||||||
if (modelsFaceEncoding is null)
|
if (modelsFaceEncoding is null)
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
if (filteredFaces.Length > 0)
|
if (faces.Count > 0)
|
||||||
{
|
{
|
||||||
intersectFaces = Shared.Models.Stateless.Methods.ILocation.FilterByIntersect(filteredFaces, _RectangleIntersectMinimum, locationContainer.WholePercentages);
|
intersectFaces = Shared.Models.Stateless.Methods.ILocation.FilterByIntersect(faces, _RectangleIntersectMinimum, locationContainer.WholePercentages);
|
||||||
if (intersectFaces.Count > 0)
|
if (intersectFaces.Count > 0)
|
||||||
checkFaces.AddRange(GetClosestFaceByDistanceIgnoringTolerance(distanceLimits, mappingFromItem, intersectFaces, modelsFaceEncoding));
|
checkFaces.AddRange(GetClosestFaceByDistanceIgnoringTolerance(distanceLimits, mappingFromItem, intersectFaces, modelsFaceEncoding));
|
||||||
}
|
}
|
||||||
@ -279,11 +279,14 @@ public partial class E_Distance : IDistance
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (checkFaces.Count == 1)
|
if (overrideForFaceImages)
|
||||||
{
|
{
|
||||||
json = Metadata.Models.Stateless.Methods.IMetadata.GetOutputResolution(locationContainer.ExifDirectory);
|
json = Metadata.Models.Stateless.Methods.IMetadata.GetOutputResolution(locationContainer.ExifDirectory);
|
||||||
if (json is null || json.Contains(nameof(DateTime)))
|
if (json is null || !json.Contains(nameof(DateTime)))
|
||||||
dFace.ReSaveFace(exifDirectory, locationContainer, checkFaces[0].Face);
|
{
|
||||||
|
if (checkFaces.Count == 1)
|
||||||
|
dFace.ReSaveFace(exifDirectory, locationContainer.FilePath, checkFaces[0].Face, mappedFile: true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (_AllMappedFaceFileNames.Contains(locationContainer.FilePath.Name))
|
if (_AllMappedFaceFileNames.Contains(locationContainer.FilePath.Name))
|
||||||
{
|
{
|
||||||
@ -332,7 +335,85 @@ public partial class E_Distance : IDistance
|
|||||||
File.WriteAllLines(eDistanceContentFileName, results);
|
File.WriteAllLines(eDistanceContentFileName, results);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void PreFilterSetFaceDistances(int maxDegreeOfParallelism, Map.Models.Configuration configuration, long ticks, ReadOnlyCollection<Face> distinctValidImageFaces)
|
public static ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> GetMappedWithEncoding(ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mapped)
|
||||||
|
{
|
||||||
|
Dictionary<int, ReadOnlyDictionary<int, LocationContainer>> results = [];
|
||||||
|
string? json;
|
||||||
|
LocationContainer? locationContainer;
|
||||||
|
Shared.Models.FaceEncoding? faceEncoding;
|
||||||
|
FaceRecognitionDotNet.FaceEncoding? encoding;
|
||||||
|
Dictionary<int, LocationContainer> keyValuePairs;
|
||||||
|
foreach (KeyValuePair<int, ReadOnlyDictionary<int, LocationContainer>> keyValuePair in mapped)
|
||||||
|
{
|
||||||
|
keyValuePairs = [];
|
||||||
|
foreach (KeyValuePair<int, LocationContainer> keyValue in keyValuePair.Value)
|
||||||
|
{
|
||||||
|
json = Metadata.Models.Stateless.Methods.IMetadata.GetFaceEncoding(keyValue.Value.ExifDirectory);
|
||||||
|
faceEncoding = json is null ? null : JsonSerializer.Deserialize<Shared.Models.FaceEncoding>(json);
|
||||||
|
if (faceEncoding is null)
|
||||||
|
continue;
|
||||||
|
encoding = FaceRecognition.LoadFaceEncoding(faceEncoding.RawEncoding);
|
||||||
|
locationContainer = LocationContainer.Get(keyValue.Value, encoding, keepExifDirectory: false);
|
||||||
|
keyValuePairs.Add(keyValue.Key, locationContainer);
|
||||||
|
}
|
||||||
|
results.Add(keyValuePair.Key, new(keyValuePairs));
|
||||||
|
}
|
||||||
|
return new(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<LocationContainer> GetPreFilterLocationContainer(int maxDegreeOfParallelism, Configuration configuration, string focusDirectory, string focusModel, int? skipPersonWithMoreThen, long ticks, MapLogic mapLogic, long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mapped, List<LocationContainer> available)
|
||||||
|
{
|
||||||
|
List<LocationContainer> results = [];
|
||||||
|
string? json;
|
||||||
|
string? model;
|
||||||
|
bool? canReMap;
|
||||||
|
bool? isFocusPerson;
|
||||||
|
bool? inSkipCollection;
|
||||||
|
Shared.Models.FaceEncoding? faceEncoding;
|
||||||
|
FaceRecognitionDotNet.FaceEncoding? encoding;
|
||||||
|
ReadOnlyDictionary<int, LocationContainer>? keyValuePairs;
|
||||||
|
ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers;
|
||||||
|
foreach (LocationContainer locationContainer in available)
|
||||||
|
{
|
||||||
|
if (mapped.TryGetValue(locationContainer.Id, out keyValuePairs))
|
||||||
|
{
|
||||||
|
if (keyValuePairs.ContainsKey(locationContainer.WholePercentages))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (locationContainer.ExifDirectory is null || locationContainer.FaceFile is null)
|
||||||
|
continue;
|
||||||
|
inSkipCollection = mapLogic.InSkipCollection(locationContainer.Id, locationContainer.WholePercentages);
|
||||||
|
if (inSkipCollection is not null && inSkipCollection.Value)
|
||||||
|
continue;
|
||||||
|
wholePercentagesToPersonContainers = mapLogic.GetWholePercentagesToPersonContainers(locationContainer.Id);
|
||||||
|
canReMap = Map.Models.Stateless.Methods.IMapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, locationContainer.WholePercentages);
|
||||||
|
if (canReMap is not null && !canReMap.Value)
|
||||||
|
continue;
|
||||||
|
isFocusPerson = mapLogic.IsFocusPerson(skipPersonWithMoreThen, jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, locationContainer.WholePercentages);
|
||||||
|
if (isFocusPerson is not null && !isFocusPerson.Value)
|
||||||
|
continue;
|
||||||
|
if (!string.IsNullOrEmpty(focusModel))
|
||||||
|
{
|
||||||
|
model = Metadata.Models.Stateless.Methods.IMetadata.GetModel(locationContainer.ExifDirectory);
|
||||||
|
if (string.IsNullOrEmpty(model) || !model.Contains(focusModel))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(focusDirectory))
|
||||||
|
{
|
||||||
|
if (!locationContainer.FilePath.DirectoryName.Contains(focusDirectory))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
json = Metadata.Models.Stateless.Methods.IMetadata.GetFaceEncoding(locationContainer.ExifDirectory);
|
||||||
|
faceEncoding = json is null ? null : JsonSerializer.Deserialize<Shared.Models.FaceEncoding>(json);
|
||||||
|
if (faceEncoding is null)
|
||||||
|
continue;
|
||||||
|
encoding = FaceRecognition.LoadFaceEncoding(faceEncoding.RawEncoding);
|
||||||
|
results.Add(LocationContainer.Get(locationContainer, encoding, keepExifDirectory: false));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PreFilterSetFaceDistances(int maxDegreeOfParallelism, Configuration configuration, long ticks, ReadOnlyCollection<Face> distinctValidImageFaces)
|
||||||
{
|
{
|
||||||
List<Face> faces = [];
|
List<Face> faces = [];
|
||||||
foreach (Face face in distinctValidImageFaces)
|
foreach (Face face in distinctValidImageFaces)
|
||||||
@ -372,12 +453,12 @@ public partial class E_Distance : IDistance
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<SortingContainer> GetSortingContainers(Map.Models.Configuration mapConfiguration, IDistanceLimits distanceLimits, Face face, FaceDistance faceDistanceEncoding, List<Sorting> sortingCollection)
|
private static List<SortingContainer> GetSortingContainers(Configuration mapConfiguration, IDistanceLimits distanceLimits, Face face, FaceDistance faceDistanceEncoding, List<Sorting> sortingCollection)
|
||||||
{
|
{
|
||||||
List<SortingContainer> results = [];
|
List<SortingContainer> results = [];
|
||||||
int days = 0, distance = 0;
|
int days = 0, distance = 0;
|
||||||
SortingContainer sortingContainer;
|
SortingContainer sortingContainer;
|
||||||
Sorting[] collection = Shared.Models.Stateless.Methods.ISorting.Sort(sortingCollection);
|
Sorting[] collection = ISorting.Sort(sortingCollection);
|
||||||
foreach (Sorting sorting in collection)
|
foreach (Sorting sorting in collection)
|
||||||
{
|
{
|
||||||
if (face.Mapping?.MappingFromLocation is null || faceDistanceEncoding.WholePercentages is null)
|
if (face.Mapping?.MappingFromLocation is null || faceDistanceEncoding.WholePercentages is null)
|
||||||
@ -403,11 +484,11 @@ public partial class E_Distance : IDistance
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Sorting> GetSortingCollection(Map.Models.MapLogic mapLogic, IDistanceLimits distanceLimits, ReadOnlyCollection<FaceDistance> faceDistanceEncodings, int i, Face face, FaceDistance faceDistanceEncoding)
|
private static List<Sorting> GetSortingCollection(MapLogic mapLogic, ReadOnlyCollection<FaceDistance> faceDistanceEncodings, int i, Face face, FaceDistance faceDistanceEncoding)
|
||||||
{
|
{
|
||||||
List<Sorting> results;
|
List<Sorting> results;
|
||||||
List<FaceDistance> faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncoding);
|
List<FaceDistance> faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncoding);
|
||||||
results = mapLogic.GetSortingCollection(distanceLimits, i, face, faceDistanceEncoding, faceDistanceLengths);
|
results = mapLogic.GetSortingCollection(i, face, faceDistanceEncoding, faceDistanceLengths);
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,7 +514,23 @@ public partial class E_Distance : IDistance
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FaceDistanceContainer[] FilteredPostLoadFaceDistanceContainers(Map.Models.MapLogic mapLogic, ReadOnlyCollection<FaceDistanceContainer> faceDistanceContainers, long? skipOlderThan, DistanceLimits distanceLimits)
|
public static List<LocationContainer> GetPostFilterLocationContainer(MapLogic mapLogic, List<LocationContainer> preFiltered, DistanceLimits distanceLimits)
|
||||||
|
{
|
||||||
|
List<LocationContainer> results = [];
|
||||||
|
foreach (LocationContainer locationContainer in preFiltered)
|
||||||
|
{
|
||||||
|
if (locationContainer.FaceFile is null)
|
||||||
|
continue;
|
||||||
|
if (locationContainer.FaceFile.AreaPermyriad < distanceLimits.FaceAreaPermyriad)
|
||||||
|
continue;
|
||||||
|
if (locationContainer.FaceFile.ConfidencePercent < distanceLimits.FaceConfidencePercent)
|
||||||
|
continue;
|
||||||
|
results.Add(locationContainer);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FaceDistanceContainer[] FilteredPostLoadFaceDistanceContainers(MapLogic mapLogic, ReadOnlyCollection<FaceDistanceContainer> faceDistanceContainers, long? skipOlderThan, DistanceLimits distanceLimits)
|
||||||
{
|
{
|
||||||
List<FaceDistanceContainer> results = [];
|
List<FaceDistanceContainer> results = [];
|
||||||
foreach (FaceDistanceContainer faceDistanceContainer in faceDistanceContainers)
|
foreach (FaceDistanceContainer faceDistanceContainer in faceDistanceContainers)
|
||||||
@ -462,7 +559,46 @@ public partial class E_Distance : IDistance
|
|||||||
return results.ToArray();
|
return results.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ReadOnlyCollection<SortingContainer> SetFaceMappingSortingCollectionThenGetSortedSortingContainers(int maxDegreeOfParallelism, Map.Models.Configuration mapConfiguration, long ticks, Map.Models.MapLogic mapLogic, IDistanceLimits distanceLimits, ReadOnlyCollection<FaceDistance> faceDistanceEncodings, FaceDistanceContainer[] filteredFaceDistanceContainers)
|
private static ReadOnlyCollection<LocationContainer> GetReadOnlyLocationContainer(ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedWithEncoding, List<LocationContainer> postFiltered)
|
||||||
|
{
|
||||||
|
List<LocationContainer> results = [];
|
||||||
|
foreach (LocationContainer locationContainer in postFiltered)
|
||||||
|
results.Add(locationContainer);
|
||||||
|
foreach (KeyValuePair<int, ReadOnlyDictionary<int, LocationContainer>> keyValuePair in mappedWithEncoding)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<int, LocationContainer> keyValue in keyValuePair.Value)
|
||||||
|
results.Add(keyValue.Value);
|
||||||
|
}
|
||||||
|
return new(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ReadOnlyCollection<LocationContainer> GetMatrixLocationContainers(IDlibDotNet dlibDotNet, Configuration mapConfiguration, long ticks, MapLogic mapLogic, ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedWithEncoding, List<LocationContainer> preFiltered, DistanceLimits distanceLimits, List<LocationContainer> postFiltered)
|
||||||
|
{
|
||||||
|
List<LocationContainer> results = [];
|
||||||
|
ReadOnlyCollection<LocationContainer> locationContainers;
|
||||||
|
ReadOnlyCollection<LocationContainer> readOnlyLocationContainers = GetReadOnlyLocationContainer(mappedWithEncoding, postFiltered);
|
||||||
|
foreach (LocationContainer locationContainer in postFiltered)
|
||||||
|
{
|
||||||
|
dlibDotNet.Tick();
|
||||||
|
locationContainers = FaceRecognition.GetLocationContainers(mapConfiguration.FaceDistancePermyriad, readOnlyLocationContainers, locationContainer);
|
||||||
|
foreach (LocationContainer item in locationContainers)
|
||||||
|
{
|
||||||
|
if (item.LengthPermyriad is null)
|
||||||
|
continue;
|
||||||
|
if (item.LengthPermyriad > distanceLimits.FaceDistancePermyriad)
|
||||||
|
break;
|
||||||
|
if (!mapConfiguration.SaveSortingWithoutPerson && item.PersonKey is null)
|
||||||
|
continue;
|
||||||
|
if (item.Id == locationContainer.Id && item.WholePercentages == locationContainer.WholePercentages)
|
||||||
|
continue;
|
||||||
|
results.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LocationContainer[] array = results.OrderBy(l => l.LengthPermyriad).ToArray();
|
||||||
|
return new(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ReadOnlyCollection<SortingContainer> SetFaceMappingSortingCollectionThenGetSortedSortingContainers(int maxDegreeOfParallelism, Configuration mapConfiguration, long ticks, MapLogic mapLogic, IDistanceLimits distanceLimits, ReadOnlyCollection<FaceDistance> faceDistanceEncodings, FaceDistanceContainer[] filteredFaceDistanceContainers)
|
||||||
{
|
{
|
||||||
List<SortingContainer> results = [];
|
List<SortingContainer> results = [];
|
||||||
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||||
@ -475,7 +611,7 @@ public partial class E_Distance : IDistance
|
|||||||
progressBar.Tick();
|
progressBar.Tick();
|
||||||
Face face = filteredFaceDistanceContainers[i].Face;
|
Face face = filteredFaceDistanceContainers[i].Face;
|
||||||
FaceDistance faceDistanceEncoding = filteredFaceDistanceContainers[i].FaceDistance;
|
FaceDistance faceDistanceEncoding = filteredFaceDistanceContainers[i].FaceDistance;
|
||||||
List<Sorting> sortingCollection = GetSortingCollection(mapLogic, distanceLimits, faceDistanceEncodings, i, face, faceDistanceEncoding);
|
List<Sorting> sortingCollection = GetSortingCollection(mapLogic, faceDistanceEncodings, i, face, faceDistanceEncoding);
|
||||||
if (sortingCollection.Count == 0)
|
if (sortingCollection.Count == 0)
|
||||||
return;
|
return;
|
||||||
List<SortingContainer> sortingContainers = GetSortingContainers(mapConfiguration, distanceLimits, face, faceDistanceEncoding, sortingCollection);
|
List<SortingContainer> sortingContainers = GetSortingContainers(mapConfiguration, distanceLimits, face, faceDistanceEncoding, sortingCollection);
|
||||||
@ -486,9 +622,9 @@ public partial class E_Distance : IDistance
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (distanceLimits is not null && distanceLimits.RangeDaysDeltaTargetLessThenUpper)
|
if (distanceLimits is not null && distanceLimits.RangeDaysDeltaTargetLessThenUpper)
|
||||||
results = Shared.Models.Stateless.Methods.ISortingContainer.Sort(results);
|
results = ISortingContainer.Sort(results);
|
||||||
else
|
else
|
||||||
results = Shared.Models.Stateless.Methods.ISortingContainer.SortUsingDaysDelta(results);
|
results = ISortingContainer.SortUsingDaysDelta(results);
|
||||||
return new(results);
|
return new(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ using System.Text.Json;
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using View_by_Distance.FaceRecognitionDotNet;
|
using View_by_Distance.FaceRecognitionDotNet;
|
||||||
using View_by_Distance.Metadata.Models;
|
using View_by_Distance.Metadata.Models;
|
||||||
|
using View_by_Distance.Metadata.Models.Stateless.Methods;
|
||||||
using View_by_Distance.Property.Models;
|
using View_by_Distance.Property.Models;
|
||||||
using View_by_Distance.Resize.Models;
|
using View_by_Distance.Resize.Models;
|
||||||
using View_by_Distance.Shared.Models;
|
using View_by_Distance.Shared.Models;
|
||||||
@ -149,7 +150,7 @@ public class D_Face : IFaceD
|
|||||||
|
|
||||||
#pragma warning disable CA1416
|
#pragma warning disable CA1416
|
||||||
|
|
||||||
private void SaveFaces(FileHolder resizedFileHolder, MetadataExtractor.GeoLocation? geoLocation, string? maker, string? model, List<(Shared.Models.Face, FileInfo?, string, bool)> collection)
|
private void SaveFaces(FileHolder resizedFileHolder, ExifDirectory exifDirectory, List<(Shared.Models.Face, FileHolder?, string, bool)> collection)
|
||||||
{
|
{
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
@ -162,17 +163,27 @@ public class D_Face : IFaceD
|
|||||||
string faceFileJson;
|
string faceFileJson;
|
||||||
string faceEncodingJson;
|
string faceEncodingJson;
|
||||||
PropertyItem? propertyItem;
|
PropertyItem? propertyItem;
|
||||||
|
string? maker = IMetadata.GetMaker(exifDirectory);
|
||||||
|
string? model = IMetadata.GetModel(exifDirectory);
|
||||||
using Bitmap source = new(resizedFileHolder.FullName);
|
using Bitmap source = new(resizedFileHolder.FullName);
|
||||||
int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist;
|
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
|
||||||
int userComment = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagUserComment;
|
const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist; // 315
|
||||||
foreach ((Shared.Models.Face face, FileInfo? fileInfo, string fileName, bool save) in collection)
|
const int userComment = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagUserComment;
|
||||||
|
foreach ((Shared.Models.Face face, FileHolder? fileHolder, string fileName, bool save) in collection)
|
||||||
{
|
{
|
||||||
if (!save)
|
if (!save)
|
||||||
continue;
|
continue;
|
||||||
if (fileInfo is null)
|
if (fileHolder is null)
|
||||||
continue;
|
continue;
|
||||||
if (face.FaceEncoding is null || face?.Location is null || face?.OutputResolution is null)
|
if (face.FaceEncoding is null || face?.Location is null || face?.OutputResolution is null)
|
||||||
continue;
|
continue;
|
||||||
|
if (_OverrideForFaceImages && fileHolder.Exists)
|
||||||
|
{
|
||||||
|
IFaceD dFace = this;
|
||||||
|
FilePath filePath = FilePath.Get(_PropertyConfiguration, fileHolder, index: null);
|
||||||
|
dFace.ReSaveFace(exifDirectory, filePath, face, mappedFile: false);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
location = Shared.Models.Stateless.Methods.ILocation.GetLocation(face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, source.Height, source.Width, collection.Count);
|
location = Shared.Models.Stateless.Methods.ILocation.GetLocation(face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, source.Height, source.Width, collection.Count);
|
||||||
if (location is null)
|
if (location is null)
|
||||||
continue;
|
continue;
|
||||||
@ -180,7 +191,15 @@ public class D_Face : IFaceD
|
|||||||
height = location.Bottom - location.Top;
|
height = location.Bottom - location.Top;
|
||||||
faceEncodingJson = JsonSerializer.Serialize(face.FaceEncoding);
|
faceEncodingJson = JsonSerializer.Serialize(face.FaceEncoding);
|
||||||
rectangle = new Rectangle(location.Left, location.Top, width, height);
|
rectangle = new Rectangle(location.Left, location.Top, width, height);
|
||||||
faceFile = new(face.DateTime, geoLocation?.ToDmsString(), face.FaceParts, face.Location, maker, model, face.OutputResolution);
|
faceFile = new(face.Mapping?.MappingFromLocation?.AreaPermyriad,
|
||||||
|
face.Mapping?.MappingFromLocation?.ConfidencePercent,
|
||||||
|
face.DateTime,
|
||||||
|
geoLocation?.ToDmsString(),
|
||||||
|
face.FaceParts,
|
||||||
|
face.Location,
|
||||||
|
maker,
|
||||||
|
model,
|
||||||
|
face.OutputResolution);
|
||||||
faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
|
faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
|
||||||
using (bitmap = new(width, height))
|
using (bitmap = new(width, height))
|
||||||
{
|
{
|
||||||
@ -190,7 +209,7 @@ public class D_Face : IFaceD
|
|||||||
bitmap.SetPropertyItem(propertyItem);
|
bitmap.SetPropertyItem(propertyItem);
|
||||||
propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(_ConstructorInfo, userComment, type, faceEncodingJson);
|
propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(_ConstructorInfo, userComment, type, faceEncodingJson);
|
||||||
bitmap.SetPropertyItem(propertyItem);
|
bitmap.SetPropertyItem(propertyItem);
|
||||||
bitmap.Save(fileInfo.FullName, _ImageCodecInfo, _EncoderParameters);
|
bitmap.Save(fileHolder.FullName, _ImageCodecInfo, _EncoderParameters);
|
||||||
}
|
}
|
||||||
if (File.Exists(fileName))
|
if (File.Exists(fileName))
|
||||||
File.Delete(fileName);
|
File.Delete(fileName);
|
||||||
@ -330,11 +349,12 @@ public class D_Face : IFaceD
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<(Shared.Models.Face, FileInfo?, string, bool)> SaveFaces(string f, string dResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces)
|
public List<(Shared.Models.Face, FileHolder?, string, bool)> SaveFaces(string f, string dResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces)
|
||||||
{
|
{
|
||||||
List<(Shared.Models.Face, FileInfo?, string, bool Save)> results = [];
|
List<(Shared.Models.Face, FileHolder?, string, bool Save)> results = [];
|
||||||
bool save;
|
bool save;
|
||||||
FileInfo fileInfo;
|
FileInfo fileInfo;
|
||||||
|
FileHolder fileHolder;
|
||||||
string deterministicHashCodeKey;
|
string deterministicHashCodeKey;
|
||||||
string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize)];
|
string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize)];
|
||||||
List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList();
|
List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList();
|
||||||
@ -351,42 +371,78 @@ public class D_Face : IFaceD
|
|||||||
}
|
}
|
||||||
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
|
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
|
||||||
fileInfo = new FileInfo(Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
|
fileInfo = new FileInfo(Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
|
||||||
|
fileHolder = FileHolder.Get(fileInfo);
|
||||||
if (!directoryExists)
|
if (!directoryExists)
|
||||||
save = true;
|
save = true;
|
||||||
else if (_OverrideForFaceImages)
|
else if (_OverrideForFaceImages)
|
||||||
save = true;
|
save = true;
|
||||||
else if (!fileInfo.Exists)
|
else if (!fileHolder.Exists)
|
||||||
save = true;
|
save = true;
|
||||||
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count > 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count > 0 && dateTimes.Max() > fileInfo.LastWriteTime)
|
||||||
save = true;
|
save = true;
|
||||||
results.Add(new(face, fileInfo, Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_HiddenFileNameExtension}"), save));
|
results.Add(new(face, fileHolder, Path.Combine(directory, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_HiddenFileNameExtension}"), save));
|
||||||
}
|
}
|
||||||
if (results.Any(l => l.Save))
|
if (results.Any(l => l.Save))
|
||||||
{
|
{
|
||||||
if (!directoryExists)
|
if (!directoryExists)
|
||||||
_ = Directory.CreateDirectory(directory);
|
_ = Directory.CreateDirectory(directory);
|
||||||
string? maker = Metadata.Models.Stateless.Methods.IMetadata.GetMaker(exifDirectory);
|
SaveFaces(mappingFromItem.ResizedFileHolder, exifDirectory, results);
|
||||||
string? model = Metadata.Models.Stateless.Methods.IMetadata.GetModel(exifDirectory);
|
|
||||||
MetadataExtractor.GeoLocation? geoLocation = Metadata.Models.Stateless.Methods.IMetadata.GeoLocation(exifDirectory);
|
|
||||||
SaveFaces(mappingFromItem.ResizedFileHolder, geoLocation, maker, model, results);
|
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CA1416
|
#pragma warning disable CA1416
|
||||||
|
|
||||||
void IFaceD.ReSaveFace(ExifDirectory exifDirectory, LocationContainer locationContainer, Shared.Models.Face face)
|
private static (string?, string?) Get(string? json)
|
||||||
{
|
{
|
||||||
FileInfo fileInfo = new(locationContainer.FilePath.FullName);
|
string? model;
|
||||||
|
string? maker;
|
||||||
|
FaceFile? faceFile = json is null ? null : JsonSerializer.Deserialize(json, FaceFileGenerationContext.Default.FaceFile);
|
||||||
|
if (faceFile is null || faceFile.Location is null)
|
||||||
|
(maker, model) = (null, null);
|
||||||
|
else
|
||||||
|
(maker, model) = (faceFile.Maker, faceFile.Model);
|
||||||
|
return (maker, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IFaceD.ReSaveFace(ExifDirectory exifDirectory, FilePath filePath, Shared.Models.Face face, bool mappedFile)
|
||||||
|
{
|
||||||
|
FileInfo fileInfo = new(filePath.FullName);
|
||||||
if (fileInfo.Exists)
|
if (fileInfo.Exists)
|
||||||
{
|
{
|
||||||
|
string? json;
|
||||||
short type = 2;
|
short type = 2;
|
||||||
string checkFile = $"{locationContainer.FilePath.FullName}.exif";
|
string? model;
|
||||||
int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist;
|
string? maker;
|
||||||
string? maker = Metadata.Models.Stateless.Methods.IMetadata.GetMaker(exifDirectory);
|
string checkFile = $"{filePath.FullName}.exif";
|
||||||
string? model = Metadata.Models.Stateless.Methods.IMetadata.GetModel(exifDirectory);
|
const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist;
|
||||||
MetadataExtractor.GeoLocation? geoLocation = Metadata.Models.Stateless.Methods.IMetadata.GeoLocation(exifDirectory);
|
// const int author = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagWinAuthor; // 40093
|
||||||
FaceFile faceFile = new(face.DateTime, geoLocation?.ToDmsString(), face.FaceParts, face.Location, maker, model, face.OutputResolution);
|
if (mappedFile)
|
||||||
|
{
|
||||||
|
json = IMetadata.GetOutputResolution(exifDirectory);
|
||||||
|
if (json is not null && json.Contains(nameof(DateTime)))
|
||||||
|
return;
|
||||||
|
(maker, model) = Get(json);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
maker = IMetadata.GetMaker(exifDirectory);
|
||||||
|
model = IMetadata.GetModel(exifDirectory);
|
||||||
|
ExifDirectory? faceExifDirectory = IMetadata.GetExifDirectory(filePath);
|
||||||
|
json = IMetadata.GetOutputResolution(faceExifDirectory);
|
||||||
|
if (json is not null && json.Contains(nameof(DateTime)))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
|
||||||
|
FaceFile faceFile = new(face.Mapping?.MappingFromLocation?.AreaPermyriad,
|
||||||
|
face.Mapping?.MappingFromLocation?.ConfidencePercent,
|
||||||
|
face.DateTime,
|
||||||
|
geoLocation?.ToDmsString(),
|
||||||
|
face.FaceParts,
|
||||||
|
face.Location,
|
||||||
|
maker,
|
||||||
|
model,
|
||||||
|
face.OutputResolution);
|
||||||
string faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
|
string faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
|
||||||
ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, [], null) ?? throw new Exception();
|
ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, [], null) ?? throw new Exception();
|
||||||
PropertyItem? propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(constructorInfo, artist, type, faceFileJson);
|
PropertyItem? propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(constructorInfo, artist, type, faceFileJson);
|
||||||
|
@ -302,12 +302,12 @@ public class D2_FaceParts
|
|||||||
|
|
||||||
#pragma warning disable CA1416
|
#pragma warning disable CA1416
|
||||||
|
|
||||||
private void SaveFaceLandmarkImage(MappingFromItem mappingFromItem, List<(Shared.Models.Face, FileInfo?, string, bool)> faceCollection, string fileName)
|
private void SaveFaceLandmarkImage(MappingFromItem mappingFromItem, List<(Shared.Models.Face, FileHolder?, string, bool)> faceCollection, string fileName)
|
||||||
{
|
{
|
||||||
Pen pen;
|
Pen pen;
|
||||||
using Image image = Image.FromFile(mappingFromItem.ResizedFileHolder.FullName);
|
using Image image = Image.FromFile(mappingFromItem.ResizedFileHolder.FullName);
|
||||||
using Graphics graphic = Graphics.FromImage(image);
|
using Graphics graphic = Graphics.FromImage(image);
|
||||||
foreach ((Shared.Models.Face face, FileInfo? fileInfo, string _, bool _) in faceCollection)
|
foreach ((Shared.Models.Face face, FileHolder? _, string _, bool _) in faceCollection)
|
||||||
{
|
{
|
||||||
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null || face.FaceParts is null || face.FaceParts.Count == 0)
|
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null || face.FaceParts is null || face.FaceParts.Count == 0)
|
||||||
continue;
|
continue;
|
||||||
@ -327,17 +327,17 @@ public class D2_FaceParts
|
|||||||
|
|
||||||
#pragma warning restore CA1416
|
#pragma warning restore CA1416
|
||||||
|
|
||||||
private static bool GetNotMapped(string facePartsCollectionDirectory, List<(Shared.Models.Face Face, FileInfo?, string, bool)> faceCollection)
|
private static bool GetNotMapped(string facePartsCollectionDirectory, List<(Shared.Models.Face Face, FileHolder?, string, bool)> faceCollection)
|
||||||
{
|
{
|
||||||
bool results = false;
|
bool results = false;
|
||||||
string checkFile;
|
string checkFile;
|
||||||
foreach ((Shared.Models.Face face, FileInfo? fileInfo, string _, bool _) in faceCollection)
|
foreach ((Shared.Models.Face face, FileHolder? fileHolder, string _, bool _) in faceCollection)
|
||||||
{
|
{
|
||||||
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null)
|
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null)
|
||||||
continue;
|
continue;
|
||||||
if (fileInfo is not null)
|
if (fileHolder is not null)
|
||||||
{
|
{
|
||||||
checkFile = Path.Combine(facePartsCollectionDirectory, fileInfo.Name);
|
checkFile = Path.Combine(facePartsCollectionDirectory, fileHolder.Name);
|
||||||
if (face.Mapping?.MappingFromPerson is not null)
|
if (face.Mapping?.MappingFromPerson is not null)
|
||||||
{
|
{
|
||||||
if (File.Exists(checkFile))
|
if (File.Exists(checkFile))
|
||||||
@ -353,14 +353,14 @@ public class D2_FaceParts
|
|||||||
if (!results)
|
if (!results)
|
||||||
results = true;
|
results = true;
|
||||||
if (!File.Exists(checkFile))
|
if (!File.Exists(checkFile))
|
||||||
File.Copy(fileInfo.FullName, checkFile);
|
File.Copy(fileHolder.FullName, checkFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyFacesAndSaveFaceLandmarkImage(string facePartsCollectionDirectory, MappingFromItem mappingFromItem, List<(Shared.Models.Face Face, FileInfo?, string, bool)> faceCollection)
|
public void CopyFacesAndSaveFaceLandmarkImage(string facePartsCollectionDirectory, MappingFromItem mappingFromItem, List<(Shared.Models.Face Face, FileHolder?, string, bool)> faceCollection)
|
||||||
{
|
{
|
||||||
bool hasNotMapped = GetNotMapped(facePartsCollectionDirectory, faceCollection);
|
bool hasNotMapped = GetNotMapped(facePartsCollectionDirectory, faceCollection);
|
||||||
string fileName = Path.Combine(facePartsCollectionDirectory, $"{mappingFromItem.FilePath.Name}{_FileNameExtension}");
|
string fileName = Path.Combine(facePartsCollectionDirectory, $"{mappingFromItem.FilePath.Name}{_FileNameExtension}");
|
||||||
|
@ -412,16 +412,42 @@ public class FaceRecognition : DisposableObject
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ReadOnlyCollection<LocationContainer> GetLocationContainers(int permyriad, ReadOnlyCollection<LocationContainer> readOnlyLocationContainers, LocationContainer locationContainer)
|
||||||
|
{
|
||||||
|
List<LocationContainer> results = [];
|
||||||
|
int lengthPermyriad;
|
||||||
|
if (readOnlyLocationContainers.Count != 0)
|
||||||
|
{
|
||||||
|
double length;
|
||||||
|
LocationContainer result;
|
||||||
|
if (locationContainer.Encoding is not FaceEncoding faceEncodingToCompare)
|
||||||
|
throw new NullReferenceException(nameof(locationContainer));
|
||||||
|
faceEncodingToCompare.ThrowIfDisposed();
|
||||||
|
foreach (LocationContainer item in readOnlyLocationContainers)
|
||||||
|
{
|
||||||
|
#pragma warning disable CA1513
|
||||||
|
if (item.Encoding is not FaceEncoding faceEncoding || faceEncoding.IsDisposed)
|
||||||
|
throw new ObjectDisposedException($"{nameof(item)} contains disposed object.");
|
||||||
|
#pragma warning restore CA1513
|
||||||
|
using (Matrix<double> diff = faceEncoding.Encoding - faceEncodingToCompare.Encoding)
|
||||||
|
length = DlibDotNet.Dlib.Length(diff);
|
||||||
|
lengthPermyriad = (int)(length * permyriad);
|
||||||
|
result = LocationContainer.Get(locationContainer, item, lengthPermyriad, keepExifDirectory: false, keepEncoding: false);
|
||||||
|
results.Add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LocationContainer[] array = results.OrderBy(l => l.LengthPermyriad).ToArray();
|
||||||
|
return new(array);
|
||||||
|
}
|
||||||
|
|
||||||
public static List<FaceDistance> FaceDistances(ReadOnlyCollection<FaceDistance> faceDistances, FaceDistance faceDistanceToCompare)
|
public static List<FaceDistance> FaceDistances(ReadOnlyCollection<FaceDistance> faceDistances, FaceDistance faceDistanceToCompare)
|
||||||
{
|
{
|
||||||
List<FaceDistance> results = [];
|
List<FaceDistance> results = [];
|
||||||
if (faceDistances is null)
|
|
||||||
throw new NullReferenceException(nameof(faceDistances));
|
|
||||||
if (faceDistances.Count != 0)
|
if (faceDistances.Count != 0)
|
||||||
{
|
{
|
||||||
double length;
|
double length;
|
||||||
FaceDistance result;
|
FaceDistance result;
|
||||||
if (faceDistanceToCompare is null || faceDistanceToCompare.Encoding is not FaceEncoding faceEncodingToCompare)
|
if (faceDistanceToCompare.Encoding is not FaceEncoding faceEncodingToCompare)
|
||||||
throw new NullReferenceException(nameof(faceDistanceToCompare));
|
throw new NullReferenceException(nameof(faceDistanceToCompare));
|
||||||
faceEncodingToCompare.ThrowIfDisposed();
|
faceEncodingToCompare.ThrowIfDisposed();
|
||||||
foreach (FaceDistance faceDistance in faceDistances)
|
foreach (FaceDistance faceDistance in faceDistances)
|
||||||
|
@ -286,6 +286,34 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void MapFaceFileLogic(long ticks, ReadOnlyCollection<PersonContainer> personContainers, MapLogic mapLogic, string? a2PeopleContentDirectory, string eDistanceContentDirectory, ProgressBarOptions options)
|
||||||
|
{
|
||||||
|
foreach (string outputResolution in _Configuration.OutputResolutions)
|
||||||
|
{
|
||||||
|
if (_Exceptions.Count != 0)
|
||||||
|
break;
|
||||||
|
if (!_Configuration.SaveResizedSubfiles)
|
||||||
|
continue;
|
||||||
|
if (!_ArgZeroIsConfigurationRootDirectory)
|
||||||
|
continue;
|
||||||
|
if (outputResolution != _Configuration.OutputResolutions[0])
|
||||||
|
continue;
|
||||||
|
if (_PropertyRootExistedBefore || a2PeopleContentDirectory is null)
|
||||||
|
break;
|
||||||
|
if (!_Configuration.SaveFaceDistancesForOutputResolutions.Contains(outputResolution))
|
||||||
|
continue;
|
||||||
|
if (!_Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution))
|
||||||
|
continue;
|
||||||
|
List<SaveContainer> saveContainers = GetSaveContainers(ticks, personContainers, a2PeopleContentDirectory, eDistanceContentDirectory, options, mapLogic, outputResolution);
|
||||||
|
if (saveContainers.Count > 0)
|
||||||
|
{
|
||||||
|
int updated = 0;
|
||||||
|
mapLogic.SaveContainers(updated, saveContainers);
|
||||||
|
throw new NotSupportedException("Done Restart! :)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void Search(long ticks, ReadOnlyCollection<PersonContainer> personContainers, string argZero, string propertyRoot)
|
private void Search(long ticks, ReadOnlyCollection<PersonContainer> personContainers, string argZero, string propertyRoot)
|
||||||
{
|
{
|
||||||
int t;
|
int t;
|
||||||
@ -381,6 +409,8 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
SaveDistinctIds(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, readOnlyContainers);
|
SaveDistinctIds(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, readOnlyContainers);
|
||||||
mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleContentDirectory, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleContentDirectory, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
||||||
DeleteContinueFiles(personContainers);
|
DeleteContinueFiles(personContainers);
|
||||||
|
if (!runToDoCollectionFirst)
|
||||||
|
MapFaceFileLogic(ticks, personContainers, mapLogic, a2PeopleContentDirectory, eDistanceContentDirectory, options);
|
||||||
FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, bResultsFullGroupDirectory, fPhotoPrismSingletonDirectory, t, readOnlyContainers, propertyLogic, mapLogic);
|
FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, bResultsFullGroupDirectory, fPhotoPrismSingletonDirectory, t, readOnlyContainers, propertyLogic, mapLogic);
|
||||||
ReadOnlyCollection<Item> distinctValidImageItems = Shared.Models.Stateless.Methods.IContainer.GetValidImageItems(_Configuration.PropertyConfiguration, readOnlyContainers, distinctItems: true, filterItems: true);
|
ReadOnlyCollection<Item> distinctValidImageItems = Shared.Models.Stateless.Methods.IContainer.GetValidImageItems(_Configuration.PropertyConfiguration, readOnlyContainers, distinctItems: true, filterItems: true);
|
||||||
if (_Configuration.LookForAbandoned)
|
if (_Configuration.LookForAbandoned)
|
||||||
@ -389,7 +419,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
string d2ResultsFullGroupDirectory;
|
string d2ResultsFullGroupDirectory;
|
||||||
foreach (string outputResolution in _Configuration.OutputResolutions)
|
foreach (string outputResolution in _Configuration.OutputResolutions)
|
||||||
{
|
{
|
||||||
_ProgressBar = new(5, nameof(mapLogic.LookForAbandoned), new ProgressBarOptions() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true });
|
_ProgressBar = new(5, nameof(mapLogic.LookForAbandoned), options);
|
||||||
(cResultsFullGroupDirectory, _, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution);
|
(cResultsFullGroupDirectory, _, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution);
|
||||||
mapLogic.LookForAbandoned(this, _Configuration.PropertyConfiguration, bResultsFullGroupDirectory, readOnlyContainers, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory);
|
mapLogic.LookForAbandoned(this, _Configuration.PropertyConfiguration, bResultsFullGroupDirectory, readOnlyContainers, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory);
|
||||||
_ProgressBar.Dispose();
|
_ProgressBar.Dispose();
|
||||||
@ -805,6 +835,57 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ReadOnlyCollection<FilePath> GetFilePath(long ticks, string dFacesContentDirectory)
|
||||||
|
{
|
||||||
|
List<FilePath> results = [];
|
||||||
|
FilePath filePath;
|
||||||
|
FileHolder fileHolder;
|
||||||
|
string[] files = Directory.GetFiles(dFacesContentDirectory, $"*{_Faces.FileNameExtension}", SearchOption.AllDirectories);
|
||||||
|
long? skipOlderThan = _Configuration.SkipOlderThanDays is null ? null : new DateTime(ticks).AddDays(-_Configuration.SkipOlderThanDays.Value).Ticks;
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
fileHolder = Shared.Models.Stateless.Methods.IFileHolder.Get(file);
|
||||||
|
filePath = FilePath.Get(_Configuration.PropertyConfiguration, fileHolder, index: null);
|
||||||
|
if (filePath.Id is null)
|
||||||
|
continue;
|
||||||
|
if (skipOlderThan is not null && (fileHolder.LastWriteTime is null || fileHolder.LastWriteTime.Value.Ticks < skipOlderThan.Value))
|
||||||
|
continue;
|
||||||
|
results.Add(filePath);
|
||||||
|
}
|
||||||
|
return new(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<SaveContainer> GetSaveContainers(long ticks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory, ProgressBarOptions options, MapLogic mapLogic, string outputResolution)
|
||||||
|
{
|
||||||
|
List<SaveContainer> results;
|
||||||
|
long[] jLinkResolvedPersonKeys = _JLinkResolvedDirectories.Select(l => l.PersonKey).ToArray();
|
||||||
|
(string cResultsFullGroupDirectory, string _, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution);
|
||||||
|
string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
|
||||||
|
ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mapped = Map.Models.Stateless.Methods.IMapLogic.GetMapped(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, ticks, personContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
||||||
|
if (mapped.Count == 0 && !_Configuration.SaveSortingWithoutPerson)
|
||||||
|
throw new NotSupportedException($"Switch {nameof(_Configuration.SaveSortingWithoutPerson)}!");
|
||||||
|
ReadOnlyCollection<FilePath> filePaths = GetFilePath(ticks, dFacesContentDirectory);
|
||||||
|
List<LocationContainer> available = Map.Models.Stateless.Methods.IMapLogic.GetAvailable(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Faces, ticks, dFacesContentDirectory, filePaths);
|
||||||
|
if (!string.IsNullOrEmpty(_Configuration.FocusDirectory) && _Configuration.FocusDirectory.Length != 2)
|
||||||
|
throw new NotSupportedException($"{nameof(_Configuration.FocusDirectory)} currently only works with output directory! Example 00.");
|
||||||
|
ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> mappedWithEncoding = E_Distance.GetMappedWithEncoding(mapped);
|
||||||
|
if (mappedWithEncoding.Count == 0 && !_Configuration.SaveSortingWithoutPerson)
|
||||||
|
throw new NotSupportedException($"Switch {nameof(_Configuration.SaveSortingWithoutPerson)}!");
|
||||||
|
List<LocationContainer> preFiltered = E_Distance.GetPreFilterLocationContainer(_AppSettings.MaxDegreeOfParallelism, _MapConfiguration, _Configuration.FocusDirectory, _Configuration.FocusModel, _Configuration.SkipPersonWithMoreThen, ticks, mapLogic, jLinkResolvedPersonKeys, mapped, available);
|
||||||
|
if (preFiltered.Count == 0)
|
||||||
|
throw new NotSupportedException("Done?");
|
||||||
|
DistanceLimits distanceLimits = new(_Configuration.FaceAreaPermyriad, _Configuration.FaceConfidencePercent, _Configuration.FaceDistancePermyriad, _Configuration.RangeDaysDeltaTolerance, _Configuration.RangeDistanceTolerance, _Configuration.RangeFaceAreaPermyriadTolerance, _Configuration.RangeFaceConfidence, _Configuration.SortingMaximumPerFaceShouldBeHigh);
|
||||||
|
List<LocationContainer> postFiltered = E_Distance.GetPostFilterLocationContainer(mapLogic, preFiltered, distanceLimits);
|
||||||
|
if (postFiltered.Count == 0)
|
||||||
|
throw new NotSupportedException("Done?");
|
||||||
|
string message = $") Building Matrix - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
||||||
|
_ProgressBar = new(postFiltered.Count, message, options);
|
||||||
|
ReadOnlyCollection<LocationContainer> matrix = E_Distance.GetMatrixLocationContainers(this, _MapConfiguration, ticks, mapLogic, mappedWithEncoding, preFiltered, distanceLimits, postFiltered);
|
||||||
|
_ProgressBar.Dispose();
|
||||||
|
results = mapLogic.GetSaveContainers(cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, distanceLimits, matrix);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
private void MapLogic(long ticks, ReadOnlyCollection<Container> containers, string fPhotoPrismContentDirectory, MapLogic mapLogic, string outputResolution, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Shared.Models.Face> distinctValidImageFaces, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
|
private void MapLogic(long ticks, ReadOnlyCollection<Container> containers, string fPhotoPrismContentDirectory, MapLogic mapLogic, string outputResolution, ReadOnlyDictionary<long, List<int>> personKeyToIds, ReadOnlyCollection<Shared.Models.Face> distinctValidImageFaces, ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
|
||||||
{
|
{
|
||||||
(_, _, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution);
|
(_, _, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution);
|
||||||
@ -1074,7 +1155,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
bool move = _Configuration.DistanceMoveUnableToMatch || _Configuration.DistanceRenameToMatch && _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution);
|
bool move = _Configuration.DistanceMoveUnableToMatch || _Configuration.DistanceRenameToMatch && _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution);
|
||||||
faces = _Faces.GetFaces(outputResolution, dResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, property, mappingFromItem, outputResolutionToResize, mappingFromPhotoPrismCollection);
|
faces = _Faces.GetFaces(outputResolution, dResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, property, mappingFromItem, outputResolutionToResize, mappingFromPhotoPrismCollection);
|
||||||
result = GetNotMappedCountAndUpdateMappingFromPersonThenSetMapping(mapLogic, item, isFocusRelativePath, mappingFromItem, mappingFromPhotoPrismCollection, faces);
|
result = GetNotMappedCountAndUpdateMappingFromPersonThenSetMapping(mapLogic, item, isFocusRelativePath, mappingFromItem, mappingFromPhotoPrismCollection, faces);
|
||||||
List<(Shared.Models.Face, FileInfo?, string, bool Saved)> faceCollection = _Faces.SaveFaces(_FaceParts.FileNameExtension, dResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, mappingFromItem, exifDirectory, faces);
|
List<(Shared.Models.Face, FileHolder?, string, bool Saved)> faceCollection = _Faces.SaveFaces(_FaceParts.FileNameExtension, dResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, mappingFromItem, exifDirectory, faces);
|
||||||
if (_Configuration.CopyFacesAndSaveFaceLandmarkForOutputResolutions.Contains(outputResolution))
|
if (_Configuration.CopyFacesAndSaveFaceLandmarkForOutputResolutions.Contains(outputResolution))
|
||||||
_FaceParts.CopyFacesAndSaveFaceLandmarkImage(facePartsCollectionDirectory, mappingFromItem, faceCollection);
|
_FaceParts.CopyFacesAndSaveFaceLandmarkImage(facePartsCollectionDirectory, mappingFromItem, faceCollection);
|
||||||
if (move && faceCollection.All(l => !l.Saved))
|
if (move && faceCollection.All(l => !l.Saved))
|
||||||
@ -1085,7 +1166,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
Map.Models.Stateless.Methods.IMapLogic.SetCreationTime(mappingFromItem, locationContainers);
|
Map.Models.Stateless.Methods.IMapLogic.SetCreationTime(mappingFromItem, locationContainers);
|
||||||
if (_Configuration.LocationContainerDistanceTolerance is null && _Configuration.MoveToDecade)
|
if (_Configuration.LocationContainerDistanceTolerance is null && _Configuration.MoveToDecade)
|
||||||
Map.Models.Stateless.Methods.IMapLogic.MoveToDecade(_Configuration.PropertyConfiguration, mappingFromItem, locationContainers);
|
Map.Models.Stateless.Methods.IMapLogic.MoveToDecade(_Configuration.PropertyConfiguration, mappingFromItem, locationContainers);
|
||||||
_Distance.LookForMatchFacesAndPossiblyRename(_DistanceLimits, _Faces, item.FilePath, mappingFromItem, exifDirectory, faces, locationContainers);
|
_Distance.LookForMatchFacesAndPossiblyRename(_Configuration.OverrideForFaceImages, _DistanceLimits, _Faces, item.FilePath, mappingFromItem, exifDirectory, faces, locationContainers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(bool review, int[] eyesCollection) = Shared.Models.Stateless.Methods.IFace.GetEyeCollection(_Configuration.EyeThreshold, faces);
|
(bool review, int[] eyesCollection) = Shared.Models.Stateless.Methods.IFace.GetEyeCollection(_Configuration.EyeThreshold, faces);
|
||||||
@ -1250,8 +1331,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
|||||||
if (filteredFaceDistanceContainers.Length > 0)
|
if (filteredFaceDistanceContainers.Length > 0)
|
||||||
{
|
{
|
||||||
int updated = sortingContainers.Count == 0 ? 0 : mapLogic.UpdateFromSortingContainers(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, idToWholePercentagesToMapping, sortingContainers);
|
int updated = sortingContainers.Count == 0 ? 0 : mapLogic.UpdateFromSortingContainers(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, idToWholePercentagesToMapping, sortingContainers);
|
||||||
List<SaveContainer> saveContainers;
|
List<SaveContainer> saveContainers = mapLogic.GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, idToWholePercentagesToMapping, distanceLimits, useFiltersCounter, sortingContainers);
|
||||||
saveContainers = mapLogic.GetSaveContainers(dFacesContentDirectory, d2FacePartsContentDirectory, d2FacePartsContentCollectionDirectory, idToWholePercentagesToMapping, distanceLimits, useFiltersCounter, sortingContainers);
|
|
||||||
if (saveContainers.Count > 0)
|
if (saveContainers.Count > 0)
|
||||||
mapLogic.SaveContainers(updated, saveContainers);
|
mapLogic.SaveContainers(updated, saveContainers);
|
||||||
}
|
}
|
||||||
|
1
Map/.vscode/format-report.json
vendored
Normal file
1
Map/.vscode/format-report.json
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
42
Map/.vscode/tasks.json
vendored
Normal file
42
Map/.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "Format",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"--report",
|
||||||
|
".vscode",
|
||||||
|
"--verbosity",
|
||||||
|
"detailed",
|
||||||
|
"--severity",
|
||||||
|
"warn"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Format-Whitespaces",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"whitespace"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "build",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/Map.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -460,6 +460,31 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private (long?, string?) GetDirectory(Configuration configuration, string by, string segmentB)
|
||||||
|
{
|
||||||
|
long? ticks = null;
|
||||||
|
const int zero = 0;
|
||||||
|
string? directory = null;
|
||||||
|
string personKeyFormatted;
|
||||||
|
PersonBirthday personBirthday;
|
||||||
|
PersonContainer personContainer;
|
||||||
|
for (int i = _NotMappedPersonContainers.Count - 1; i > 0; i--)
|
||||||
|
{
|
||||||
|
if (configuration.SaveIndividually)
|
||||||
|
break;
|
||||||
|
personContainer = _NotMappedPersonContainers[i];
|
||||||
|
if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Birthdays.Length == 0)
|
||||||
|
continue;
|
||||||
|
personBirthday = personContainer.Birthdays[zero];
|
||||||
|
ticks = personBirthday.Value.Ticks;
|
||||||
|
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personBirthday);
|
||||||
|
directory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, segmentB);
|
||||||
|
_NotMappedPersonContainers.RemoveAt(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (ticks, directory);
|
||||||
|
}
|
||||||
|
|
||||||
private (long?, string?) GetDirectory(Configuration configuration, bool saveIndividually, int padLeft, string? segmentC, string by, MappingFromItem mappingFromItem)
|
private (long?, string?) GetDirectory(Configuration configuration, bool saveIndividually, int padLeft, string? segmentC, string by, MappingFromItem mappingFromItem)
|
||||||
{
|
{
|
||||||
long? ticks = null;
|
long? ticks = null;
|
||||||
@ -512,7 +537,30 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Record Get(Configuration configuration, bool saveIndividually, string by, Mapping question, int padLeft)
|
private Record Get(Configuration configuration, string by, long? personKey, string? displayDirectoryName, string segmentB)
|
||||||
|
{
|
||||||
|
long? ticks;
|
||||||
|
string? directory;
|
||||||
|
string? debugDirectory;
|
||||||
|
string? personDirectory;
|
||||||
|
if (personKey is null || string.IsNullOrEmpty(displayDirectoryName))
|
||||||
|
{
|
||||||
|
debugDirectory = null;
|
||||||
|
(ticks, directory) = GetDirectory(configuration, by, segmentB);
|
||||||
|
personDirectory = directory is null ? null : Path.Combine(directory, $"X+{ticks}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ticks = null;
|
||||||
|
string personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey.Value);
|
||||||
|
debugDirectory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, displayDirectoryName);
|
||||||
|
directory = Path.Combine(_EDistanceContentTicksDirectory, by, personKeyFormatted, segmentB);
|
||||||
|
personDirectory = Path.Combine(directory, displayDirectoryName, "lnk");
|
||||||
|
}
|
||||||
|
return new(debugDirectory, directory, ticks, personDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Record Get(Configuration configuration, bool saveIndividually, int padLeft, string by, Mapping question)
|
||||||
{
|
{
|
||||||
long? ticks;
|
long? ticks;
|
||||||
string? directory;
|
string? directory;
|
||||||
@ -594,7 +642,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
if (!PreAndPostContinue(_Configuration, mapping, question))
|
if (!PreAndPostContinue(_Configuration, mapping, question))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
record = Get(_Configuration, saveIndividually, by, mapping, padLeft);
|
record = Get(_Configuration, saveIndividually, padLeft, by, mapping);
|
||||||
if (string.IsNullOrEmpty(record.Directory) || string.IsNullOrEmpty(record.PersonDirectory))
|
if (string.IsNullOrEmpty(record.Directory) || string.IsNullOrEmpty(record.PersonDirectory))
|
||||||
continue;
|
continue;
|
||||||
directory = record.Directory;
|
directory = record.Directory;
|
||||||
@ -673,7 +721,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
Stateless.MapLogic.SaveMappingShortcuts(mappingDirectory);
|
Stateless.MapLogic.SaveMappingShortcuts(mappingDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Sorting> GetSortingCollection(Shared.Models.Methods.IDistanceLimits distanceLimits, int i, Face face, FaceDistance faceDistanceEncoding, List<FaceDistance> faceDistanceLengths)
|
public List<Sorting> GetSortingCollection(int i, Face face, FaceDistance faceDistanceEncoding, List<FaceDistance> faceDistanceLengths)
|
||||||
{
|
{
|
||||||
if (_Configuration is null)
|
if (_Configuration is null)
|
||||||
throw new NullReferenceException(nameof(_Configuration));
|
throw new NullReferenceException(nameof(_Configuration));
|
||||||
@ -772,6 +820,94 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string? GetDisplayDirectoryName(string? displayDirectoryName, LocationContainer locationContainer)
|
||||||
|
{
|
||||||
|
string? result = displayDirectoryName;
|
||||||
|
ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers = GetWholePercentagesToPersonContainers(locationContainer.Id);
|
||||||
|
if (wholePercentagesToPersonContainers is not null)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<int, ReadOnlyCollection<PersonContainer>> keyValuePair in wholePercentagesToPersonContainers)
|
||||||
|
{
|
||||||
|
if (keyValuePair.Key != locationContainer.WholePercentages)
|
||||||
|
continue;
|
||||||
|
if (keyValuePair.Value.Count != 1)
|
||||||
|
continue;
|
||||||
|
result = keyValuePair.Value[0].DisplayDirectoryName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SaveContainer> GetSaveContainers(string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, Shared.Models.Methods.IDistanceLimits distanceLimits, ReadOnlyCollection<LocationContainer> matrix)
|
||||||
|
{
|
||||||
|
if (_Configuration is null)
|
||||||
|
throw new NullReferenceException(nameof(_Configuration));
|
||||||
|
List<SaveContainer> results = [];
|
||||||
|
string by;
|
||||||
|
Record record;
|
||||||
|
string segmentB;
|
||||||
|
bool isBySorting;
|
||||||
|
string checkFile;
|
||||||
|
string? directory;
|
||||||
|
string shortcutFile;
|
||||||
|
string facesDirectory;
|
||||||
|
List<string> added = [];
|
||||||
|
bool isCounterPersonYear;
|
||||||
|
string facePartsDirectory;
|
||||||
|
FileHolder? faceFileHolder;
|
||||||
|
SaveContainer? saveContainer;
|
||||||
|
string? displayDirectoryName;
|
||||||
|
FileHolder? resizedFileHolder;
|
||||||
|
int? useFiltersCounter = null;
|
||||||
|
string resizeContentDirectory;
|
||||||
|
FileHolder? facePartsFileHolder;
|
||||||
|
FileHolder? hiddenFaceFileHolder;
|
||||||
|
bool sortingContainersAny = matrix.Count > 0;
|
||||||
|
string cContentDirectory = Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
|
||||||
|
string forceSingleImageHumanized = nameof(Shared.Models.Stateless.IMapLogic.ForceSingleImage).Humanize(LetterCasing.Title);
|
||||||
|
string d2FacePartsContentDirectory = Path.Combine(d2ResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
|
||||||
|
foreach (LocationContainer locationContainer in matrix)
|
||||||
|
{
|
||||||
|
if (_Configuration.SaveIndividually)
|
||||||
|
break;
|
||||||
|
if (locationContainer.LengthPermyriad is null || locationContainer.LengthSource is null)
|
||||||
|
continue;
|
||||||
|
if (added.Contains(locationContainer.LengthSource.Name))
|
||||||
|
continue;
|
||||||
|
segmentB = locationContainer.LengthPermyriad.Value.ToString().PadLeft(2, '0')[..2];
|
||||||
|
isCounterPersonYear = locationContainer.PersonKey is not null && IPersonBirthday.IsCounterPersonYear(locationContainer.PersonKey.Value);
|
||||||
|
displayDirectoryName = isCounterPersonYear ? locationContainer.DisplayDirectoryName : GetDisplayDirectoryName(locationContainer.DisplayDirectoryName, locationContainer);
|
||||||
|
(by, _, isBySorting) = Stateless.MapLogic.Get(useFiltersCounter, _Configuration.SaveIndividually, sortingContainersAny, forceSingleImageHumanized, locationContainer.LengthPermyriad, locationContainer.PersonKey, displayDirectoryName);
|
||||||
|
record = Get(_Configuration, by, locationContainer.PersonKey, displayDirectoryName, segmentB);
|
||||||
|
if (string.IsNullOrEmpty(record.Directory) || string.IsNullOrEmpty(record.PersonDirectory))
|
||||||
|
continue;
|
||||||
|
directory = record.Directory;
|
||||||
|
if (!string.IsNullOrEmpty(record.DebugDirectory))
|
||||||
|
results.Add(new(record.DebugDirectory));
|
||||||
|
if (locationContainer.PersonKey is null)
|
||||||
|
{
|
||||||
|
if (!_Configuration.SaveSortingWithoutPerson)
|
||||||
|
throw new NotSupportedException();
|
||||||
|
if (record.Ticks is null)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
results.Add(new(record.PersonDirectory));
|
||||||
|
facesDirectory = locationContainer.LengthSource.DirectoryName;
|
||||||
|
faceFileHolder = IFileHolder.Get(locationContainer.LengthSource.FullName);
|
||||||
|
checkFile = Path.Combine(directory, $"{locationContainer.LengthSource.Name}");
|
||||||
|
shortcutFile = Path.Combine(record.PersonDirectory, $"{locationContainer.LengthSource.Name}.lnk");
|
||||||
|
resizeContentDirectory = Stateless.MapLogic.GetResizeContentDirectory(_PropertyConfiguration, cContentDirectory, locationContainer.LengthSource);
|
||||||
|
facePartsDirectory = Stateless.MapLogic.GetFacePartsDirectoryX(_PropertyConfiguration, d2FacePartsContentDirectory, locationContainer.LengthSource);
|
||||||
|
hiddenFaceFileHolder = IFileHolder.Get(Path.Combine(facesDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{_Configuration.FacesHiddenFileNameExtension}"));
|
||||||
|
facePartsFileHolder = IFileHolder.Get(Path.Combine(facePartsDirectory, $"{locationContainer.LengthSource.NameWithoutExtension}{_Configuration.FacePartsFileNameExtension}"));
|
||||||
|
resizedFileHolder = IFileHolder.Get(Path.Combine(resizeContentDirectory, $"{locationContainer.LengthSource.FileNameFirstSegment}{Path.GetExtension(locationContainer.LengthSource.NameWithoutExtension)}"));
|
||||||
|
saveContainer = new(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, facePartsFileHolder, resizedFileHolder, shortcutFile);
|
||||||
|
results.Add(saveContainer);
|
||||||
|
added.Add(locationContainer.LengthSource.Name);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
public List<SaveContainer> GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping, Shared.Models.Methods.IDistanceLimits distanceLimits, int? useFiltersCounter, ReadOnlyCollection<SortingContainer> sortingContainers)
|
public List<SaveContainer> GetSaveContainers(string dFacesContentDirectory, string d2FacePartsContentDirectory, string d2FacePartsContentCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> idToWholePercentagesToMapping, Shared.Models.Methods.IDistanceLimits distanceLimits, int? useFiltersCounter, ReadOnlyCollection<SortingContainer> sortingContainers)
|
||||||
{
|
{
|
||||||
if (_Configuration is null)
|
if (_Configuration is null)
|
||||||
@ -810,7 +946,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
if (question.MappingFromLocation is null)
|
if (question.MappingFromLocation is null)
|
||||||
continue;
|
continue;
|
||||||
record = Get(_Configuration, _Configuration.SaveIndividually, by, question, padLeft);
|
record = Get(_Configuration, _Configuration.SaveIndividually, padLeft, by, question);
|
||||||
if (string.IsNullOrEmpty(record.Directory) || string.IsNullOrEmpty(record.PersonDirectory))
|
if (string.IsNullOrEmpty(record.Directory) || string.IsNullOrEmpty(record.PersonDirectory))
|
||||||
continue;
|
continue;
|
||||||
directory = record.Directory;
|
directory = record.Directory;
|
||||||
@ -1320,10 +1456,13 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool InSkipCollection(int id, MappingFromLocation mappingFromLocation) =>
|
public bool InSkipCollection(int id, int wholePercentages) =>
|
||||||
_SkipCollection.TryGetValue(id, out List<int>? wholePercentagesCollection) && wholePercentagesCollection.Contains(mappingFromLocation.WholePercentages);
|
_SkipCollection.TryGetValue(id, out List<int>? wholePercentagesCollection) && wholePercentagesCollection.Contains(wholePercentages);
|
||||||
|
|
||||||
public bool? IsFocusPerson(int? skipPersonWithMoreThen, long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation)
|
public bool InSkipCollection(int id, MappingFromLocation mappingFromLocation) =>
|
||||||
|
InSkipCollection(id, mappingFromLocation.WholePercentages);
|
||||||
|
|
||||||
|
public bool? IsFocusPerson(int? skipPersonWithMoreThen, long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, int wholePercentages)
|
||||||
{
|
{
|
||||||
bool? result;
|
bool? result;
|
||||||
ReadOnlyCollection<PersonContainer>? personContainers;
|
ReadOnlyCollection<PersonContainer>? personContainers;
|
||||||
@ -1331,7 +1470,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
result = null;
|
result = null;
|
||||||
else if (wholePercentagesToPersonContainers is null)
|
else if (wholePercentagesToPersonContainers is null)
|
||||||
result = null;
|
result = null;
|
||||||
else if (!wholePercentagesToPersonContainers.TryGetValue(mappingFromLocation.WholePercentages, out personContainers))
|
else if (!wholePercentagesToPersonContainers.TryGetValue(wholePercentages, out personContainers))
|
||||||
result = null;
|
result = null;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1355,6 +1494,9 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool? IsFocusPerson(int? skipPersonWithMoreThen, long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
|
||||||
|
IsFocusPerson(skipPersonWithMoreThen, jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation.WholePercentages);
|
||||||
|
|
||||||
public void LookForAbandoned(IDlibDotNet dlibDotNet, Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection<Container> readOnlyContainers, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory)
|
public void LookForAbandoned(IDlibDotNet dlibDotNet, Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection<Container> readOnlyContainers, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory)
|
||||||
{
|
{
|
||||||
string[] directories;
|
string[] directories;
|
||||||
|
@ -387,7 +387,7 @@ internal abstract class DistanceLogic
|
|||||||
}
|
}
|
||||||
personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
if (personNameDirectories.Length > 1)
|
if (personNameDirectories.Length > 1)
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException("Try deleting *.lnk files!");
|
||||||
foreach (string personNameDirectory in personNameDirectories)
|
foreach (string personNameDirectory in personNameDirectories)
|
||||||
{
|
{
|
||||||
directoryNumber++;
|
directoryNumber++;
|
||||||
|
212
Map/Models/Stateless/FaceFileLogic.cs
Normal file
212
Map/Models/Stateless/FaceFileLogic.cs
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
using ShellProgressBar;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Text.Json;
|
||||||
|
using View_by_Distance.Shared.Models;
|
||||||
|
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
using static View_by_Distance.Map.Models.Stateless.MapLogic;
|
||||||
|
|
||||||
|
namespace View_by_Distance.Map.Models.Stateless;
|
||||||
|
|
||||||
|
internal abstract class FaceFileLogic
|
||||||
|
{
|
||||||
|
|
||||||
|
private static void MappedParallelFor(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, ReadOnlyDictionary<int, List<(string, int)>> skipCollection, List<LocationContainer> locationContainers, MappedFile mappedFile)
|
||||||
|
{
|
||||||
|
int? id;
|
||||||
|
string checkFile;
|
||||||
|
DateOnly dateOnly;
|
||||||
|
FilePath filePath;
|
||||||
|
string[] fileMatches;
|
||||||
|
FileHolder fileHolder;
|
||||||
|
int? wholePercentages;
|
||||||
|
const string lnk = ".lnk";
|
||||||
|
ExifDirectory? exifDirectory;
|
||||||
|
string personDisplayDirectoryName;
|
||||||
|
const bool fromDistanceContent = true;
|
||||||
|
List<(string File, int WholePercentages)>? wholePercentagesCollection;
|
||||||
|
if (!mappedFile.FilePath.Name.EndsWith(lnk))
|
||||||
|
{
|
||||||
|
if (mappedFile.FilePath.Id is null)
|
||||||
|
return;
|
||||||
|
id = mappedFile.FilePath.Id;
|
||||||
|
wholePercentages = IMapping.GetWholePercentages(configuration.FacesFileNameExtension, mappedFile.FilePath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileHolder = IFileHolder.Get(mappedFile.FilePath.FullName[..^4]);
|
||||||
|
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
||||||
|
if (filePath.Id is null)
|
||||||
|
return;
|
||||||
|
id = filePath.Id;
|
||||||
|
wholePercentages = IMapping.GetWholePercentages(configuration.FacesFileNameExtension, filePath);
|
||||||
|
}
|
||||||
|
if (wholePercentages is null)
|
||||||
|
return;
|
||||||
|
if (configuration.LinkedAlpha is null && string.IsNullOrEmpty(configuration.LocationContainerDebugDirectory) && skipCollection.TryGetValue(id.Value, out wholePercentagesCollection))
|
||||||
|
{
|
||||||
|
fileMatches = (from l in wholePercentagesCollection where l.WholePercentages == wholePercentages select l.File).ToArray();
|
||||||
|
foreach (string fileMatch in fileMatches)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(fileMatch) || !File.Exists(fileMatch))
|
||||||
|
continue;
|
||||||
|
checkFile = $"{fileMatch}.dup";
|
||||||
|
if (File.Exists(checkFile))
|
||||||
|
continue;
|
||||||
|
File.Move(fileMatch, checkFile);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dateOnly = DateOnly.FromDateTime(new DateTime(mappedFile.FilePath.CreationTicks));
|
||||||
|
if (mappedFile.FilePath.Name.EndsWith(lnk) || !File.Exists(mappedFile.FilePath.FullName))
|
||||||
|
exifDirectory = null;
|
||||||
|
else
|
||||||
|
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(mappedFile.FilePath);
|
||||||
|
RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value);
|
||||||
|
personDisplayDirectoryName = mappedFile.PersonDisplayDirectoryName is null ? configuration.MappingDefaultName : mappedFile.PersonDisplayDirectoryName;
|
||||||
|
lock (locationContainers)
|
||||||
|
locationContainers.Add(new(dateOnly,
|
||||||
|
exifDirectory,
|
||||||
|
mappedFile.DirectoryNumber,
|
||||||
|
personDisplayDirectoryName,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
mappedFile.FilePath,
|
||||||
|
fromDistanceContent,
|
||||||
|
id.Value,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
mappedFile.PersonKey,
|
||||||
|
rectangle,
|
||||||
|
wholePercentages.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> GetReadOnly(Dictionary<int, Dictionary<int, LocationContainer>> keyValuePairs)
|
||||||
|
{
|
||||||
|
Dictionary<int, ReadOnlyDictionary<int, LocationContainer>> results = [];
|
||||||
|
foreach (KeyValuePair<int, Dictionary<int, LocationContainer>> keyValuePair in keyValuePairs)
|
||||||
|
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
||||||
|
return new(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> GetMapped(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory)
|
||||||
|
{
|
||||||
|
Dictionary<int, Dictionary<int, LocationContainer>> results = [];
|
||||||
|
List<LocationContainer> locationContainers = [];
|
||||||
|
Dictionary<int, LocationContainer>? keyValuePairs;
|
||||||
|
Dictionary<int, List<(string, int)>> skipCollection = [];
|
||||||
|
Dictionary<int, List<(string, int)>> skipNotSkipCollection = [];
|
||||||
|
ReadOnlyCollection<string> readOnlyPersonKeyFormattedCollection;
|
||||||
|
ReadOnlyDictionary<string, string> readOnlyPersonKeyFormattedToNewestPersonKeyFormatted;
|
||||||
|
SetSkipCollections(configuration, personContainers, a2PeopleSingletonDirectory, skipCollection, skipNotSkipCollection);
|
||||||
|
{
|
||||||
|
List<string> personKeyFormattedCollection = [];
|
||||||
|
Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted = [];
|
||||||
|
SetPersonCollections(configuration, personContainers, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedCollection);
|
||||||
|
readOnlyPersonKeyFormattedCollection = new(personKeyFormattedCollection);
|
||||||
|
readOnlyPersonKeyFormattedToNewestPersonKeyFormatted = new(personKeyFormattedToNewestPersonKeyFormatted);
|
||||||
|
}
|
||||||
|
List<Record> records = DistanceLogic.DeleteEmptyDirectoriesAndGetCollection(propertyConfiguration, configuration, ticks, eDistanceContentDirectory, readOnlyPersonKeyFormattedToNewestPersonKeyFormatted, readOnlyPersonKeyFormattedCollection);
|
||||||
|
List<MappedFile> mappedFiles = GetMappedFiles(propertyConfiguration, configuration, personContainers, records);
|
||||||
|
if (mappedFiles.Count > 0)
|
||||||
|
{
|
||||||
|
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||||
|
string message = $") Building Mapped Face Files Collection - {totalSeconds} total second(s)";
|
||||||
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||||
|
ReadOnlyDictionary<int, List<(string, int)>> readOnlySkipNotSkipCollection = new(skipCollection);
|
||||||
|
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||||
|
using ProgressBar progressBar = new(mappedFiles.Count, message, options);
|
||||||
|
_ = Parallel.For(0, mappedFiles.Count, parallelOptions, (i, state) =>
|
||||||
|
{
|
||||||
|
progressBar.Tick();
|
||||||
|
MappedParallelFor(propertyConfiguration, configuration, readOnlySkipNotSkipCollection, locationContainers, mappedFiles[i]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
foreach (LocationContainer locationContainer in locationContainers)
|
||||||
|
{
|
||||||
|
if (!results.TryGetValue(locationContainer.Id, out keyValuePairs))
|
||||||
|
{
|
||||||
|
results.Add(locationContainer.Id, []);
|
||||||
|
if (!results.TryGetValue(locationContainer.Id, out keyValuePairs))
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
if (keyValuePairs.ContainsKey(locationContainer.WholePercentages))
|
||||||
|
continue;
|
||||||
|
keyValuePairs.Add(locationContainer.WholePercentages, locationContainer);
|
||||||
|
}
|
||||||
|
return GetReadOnly(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MoveUnableToMatch(FilePath filePath)
|
||||||
|
{
|
||||||
|
string checkFile = $"{filePath.FullName}.unk";
|
||||||
|
if (File.Exists(filePath.FullName) && !File.Exists(checkFile))
|
||||||
|
File.Move(filePath.FullName, checkFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AvailableParallelFor(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, IFaceD dFace, List<LocationContainer> locationContainers, FilePath filePath)
|
||||||
|
{
|
||||||
|
string? json;
|
||||||
|
const bool fromDistanceContent = false;
|
||||||
|
if (filePath.Id is null)
|
||||||
|
return;
|
||||||
|
DateOnly dateOnly = DateOnly.FromDateTime(new DateTime(filePath.CreationTicks));
|
||||||
|
int? wholePercentages = IMapping.GetWholePercentages(dFace.FileNameExtension, filePath);
|
||||||
|
if (wholePercentages is null)
|
||||||
|
{
|
||||||
|
if (configuration.DistanceMoveUnableToMatch)
|
||||||
|
MoveUnableToMatch(filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ExifDirectory exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(filePath);
|
||||||
|
json = Metadata.Models.Stateless.Methods.IMetadata.GetOutputResolution(exifDirectory);
|
||||||
|
if (json is null || !json.Contains(nameof(DateTime)))
|
||||||
|
{
|
||||||
|
if (configuration.DistanceMoveUnableToMatch)
|
||||||
|
MoveUnableToMatch(filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FaceFile? faceFile = JsonSerializer.Deserialize(json, FaceFileGenerationContext.Default.FaceFile);
|
||||||
|
if (faceFile is null || faceFile.Location is null)
|
||||||
|
{
|
||||||
|
if (configuration.DistanceMoveUnableToMatch)
|
||||||
|
MoveUnableToMatch(filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value);
|
||||||
|
if (rectangle is null)
|
||||||
|
return;
|
||||||
|
lock (locationContainers)
|
||||||
|
locationContainers.Add(new(dateOnly,
|
||||||
|
exifDirectory,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
faceFile,
|
||||||
|
filePath,
|
||||||
|
fromDistanceContent,
|
||||||
|
filePath.Id.Value,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
rectangle,
|
||||||
|
wholePercentages.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static List<LocationContainer> GetAvailable(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration configuration, IFaceD dFace, long ticks, string dFacesContentDirectory, ReadOnlyCollection<FilePath> filePaths)
|
||||||
|
{
|
||||||
|
List<LocationContainer> results = [];
|
||||||
|
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||||
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||||
|
string message = $") Building Available Face Files Collection - {totalSeconds} total second(s)";
|
||||||
|
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||||
|
using ProgressBar progressBar = new(filePaths.Count, message, options);
|
||||||
|
_ = Parallel.For(0, filePaths.Count, parallelOptions, (i, state) =>
|
||||||
|
{
|
||||||
|
progressBar.Tick();
|
||||||
|
AvailableParallelFor(propertyConfiguration, configuration, dFace, results, filePaths[i]);
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -438,7 +438,7 @@ internal abstract class MapLogic
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<MappedFile> GetMappedFiles(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, List<Record> records)
|
internal static List<MappedFile> GetMappedFiles(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, List<Record> records)
|
||||||
{
|
{
|
||||||
List<MappedFile> results = [];
|
List<MappedFile> results = [];
|
||||||
long personKey;
|
long personKey;
|
||||||
@ -540,10 +540,13 @@ internal abstract class MapLogic
|
|||||||
exifDirectory,
|
exifDirectory,
|
||||||
mappedFile.DirectoryNumber,
|
mappedFile.DirectoryNumber,
|
||||||
personDisplayDirectoryName,
|
personDisplayDirectoryName,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
mappedFile.FilePath,
|
mappedFile.FilePath,
|
||||||
fromDistanceContent,
|
fromDistanceContent,
|
||||||
id.Value,
|
id.Value,
|
||||||
null,
|
null,
|
||||||
|
null,
|
||||||
mappedFile.PersonKey,
|
mappedFile.PersonKey,
|
||||||
rectangle,
|
rectangle,
|
||||||
wholePercentages.Value));
|
wholePercentages.Value));
|
||||||
@ -561,6 +564,8 @@ internal abstract class MapLogic
|
|||||||
Dictionary<string, (FilePath, int)> distinct = [];
|
Dictionary<string, (FilePath, int)> distinct = [];
|
||||||
foreach (LocationContainer locationContainer in locationContainers)
|
foreach (LocationContainer locationContainer in locationContainers)
|
||||||
{
|
{
|
||||||
|
if (locationContainer.PersonKey is null)
|
||||||
|
continue;
|
||||||
key = string.Concat(locationContainer.PersonKey, locationContainer.Id);
|
key = string.Concat(locationContainer.PersonKey, locationContainer.Id);
|
||||||
if (distinct.TryGetValue(key, out item))
|
if (distinct.TryGetValue(key, out item))
|
||||||
{
|
{
|
||||||
@ -576,7 +581,7 @@ internal abstract class MapLogic
|
|||||||
}
|
}
|
||||||
delete.Add(item.FilePath);
|
delete.Add(item.FilePath);
|
||||||
delete.Add(locationContainer.FilePath);
|
delete.Add(locationContainer.FilePath);
|
||||||
duplicates.Add(new(locationContainer.PersonKey, locationContainer.Id, locationContainer.FilePath, percent));
|
duplicates.Add(new(locationContainer.PersonKey.Value, locationContainer.Id, locationContainer.FilePath, percent));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
distinct.Add(key, new(locationContainer.FilePath, locationContainer.WholePercentages));
|
distinct.Add(key, new(locationContainer.FilePath, locationContainer.WholePercentages));
|
||||||
@ -990,6 +995,22 @@ internal abstract class MapLogic
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static string GetFacePartsDirectoryX(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string d2FacePartsContentDirectory, FilePath filePath)
|
||||||
|
{
|
||||||
|
string result;
|
||||||
|
(string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath);
|
||||||
|
result = Path.Combine(d2FacePartsContentDirectory, directoryName, filePath.NameWithoutExtension);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string GetResizeContentDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string cContentDirectory, FilePath filePath)
|
||||||
|
{
|
||||||
|
string result;
|
||||||
|
(string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath);
|
||||||
|
result = Path.Combine(cContentDirectory, directoryName);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
internal static SaveContainer GetDebugSaveContainer(SortingContainer sortingContainer, string directory, Mapping keyMapping)
|
internal static SaveContainer GetDebugSaveContainer(SortingContainer sortingContainer, string directory, Mapping keyMapping)
|
||||||
{
|
{
|
||||||
SaveContainer result;
|
SaveContainer result;
|
||||||
@ -1171,29 +1192,29 @@ internal abstract class MapLogic
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static (string, bool, bool) Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, Mapping mapping)
|
internal static (string, bool, bool) Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, int? by, string? displayDirectoryName)
|
||||||
{
|
{
|
||||||
string by;
|
string byValue;
|
||||||
bool isByMapping;
|
bool isByMapping;
|
||||||
bool isBySorting;
|
bool isBySorting;
|
||||||
if (mapping.By is null)
|
if (by is null)
|
||||||
{
|
{
|
||||||
isByMapping = false;
|
isByMapping = false;
|
||||||
isBySorting = !sortingContainersAny;
|
isBySorting = !sortingContainersAny;
|
||||||
by = $"{nameof(Shared.Models.Stateless.IMapLogic.Mapping)}Null";
|
byValue = $"{nameof(Shared.Models.Stateless.IMapLogic.Mapping)}Null";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
isByMapping = mapping.By == Shared.Models.Stateless.IMapLogic.Mapping;
|
isByMapping = by == Shared.Models.Stateless.IMapLogic.Mapping;
|
||||||
isBySorting = mapping.By == Shared.Models.Stateless.IMapLogic.Sorting;
|
isBySorting = by == Shared.Models.Stateless.IMapLogic.Sorting;
|
||||||
bool isDefaultName = mapping.MappingFromPerson is not null && IPerson.IsDefaultName(mapping.MappingFromPerson.DisplayDirectoryName);
|
bool isDefaultName = displayDirectoryName is not null && IPerson.IsDefaultName(displayDirectoryName);
|
||||||
if (isBySorting && mapping.MappingFromPerson is null)
|
if (isBySorting && displayDirectoryName is null)
|
||||||
by = saveIndividually ? nameof(Shared.Models.Stateless.IMapLogic.Individually) : $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)} Without Person{(distancePermyriad < 2000 ? "-A" : "-Z")}";
|
byValue = saveIndividually ? nameof(Shared.Models.Stateless.IMapLogic.Individually) : $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)} Without Person{(distancePermyriad < 2000 ? "-A" : "-Z")}";
|
||||||
else if (isBySorting && useFiltersCounter.HasValue)
|
else if (isBySorting && useFiltersCounter.HasValue)
|
||||||
by = $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)}{(!isDefaultName ? "-A" : "-Z")} Modified Filters - {useFiltersCounter.Value}";
|
byValue = $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)}{(!isDefaultName ? "-A" : "-Z")} Modified Filters - {useFiltersCounter.Value}";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
by = $"{mapping.By.Value switch
|
byValue = $"{by.Value switch
|
||||||
{
|
{
|
||||||
Shared.Models.Stateless.IMapLogic.Mapping => nameof(Shared.Models.Stateless.IMapLogic.Mapping),
|
Shared.Models.Stateless.IMapLogic.Mapping => nameof(Shared.Models.Stateless.IMapLogic.Mapping),
|
||||||
Shared.Models.Stateless.IMapLogic.Sorting => saveIndividually ? nameof(Shared.Models.Stateless.IMapLogic.Individually) : nameof(Shared.Models.Stateless.IMapLogic.Sorting),
|
Shared.Models.Stateless.IMapLogic.Sorting => saveIndividually ? nameof(Shared.Models.Stateless.IMapLogic.Individually) : nameof(Shared.Models.Stateless.IMapLogic.Sorting),
|
||||||
@ -1202,9 +1223,15 @@ internal abstract class MapLogic
|
|||||||
}}{(!isDefaultName ? "-A" : "-Z")}";
|
}}{(!isDefaultName ? "-A" : "-Z")}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new(by, isByMapping, isBySorting);
|
return new(byValue, isByMapping, isBySorting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static (string, bool, bool) Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, long? personKey, string? displayDirectoryName) =>
|
||||||
|
Get(useFiltersCounter, saveIndividually, sortingContainersAny, forceSingleImageHumanized, distancePermyriad, personKey is null ? null : Shared.Models.Stateless.IMapLogic.Mapping, displayDirectoryName);
|
||||||
|
|
||||||
|
internal static (string, bool, bool) Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, Mapping mapping) =>
|
||||||
|
Get(useFiltersCounter, saveIndividually, sortingContainersAny, forceSingleImageHumanized, distancePermyriad, mapping.By, mapping.MappingFromPerson?.DisplayDirectoryName);
|
||||||
|
|
||||||
internal static void CheckCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string? rootDirectoryParent)
|
internal static void CheckCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string? rootDirectoryParent)
|
||||||
{
|
{
|
||||||
string json;
|
string json;
|
||||||
@ -1272,7 +1299,7 @@ internal abstract class MapLogic
|
|||||||
return new(results);
|
return new(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation)
|
internal static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, int wholePercentages)
|
||||||
{
|
{
|
||||||
bool? result;
|
bool? result;
|
||||||
ReadOnlyCollection<PersonContainer>? personContainers;
|
ReadOnlyCollection<PersonContainer>? personContainers;
|
||||||
@ -1280,7 +1307,7 @@ internal abstract class MapLogic
|
|||||||
result = null;
|
result = null;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!wholePercentagesToPersonContainers.TryGetValue(mappingFromLocation.WholePercentages, out personContainers))
|
if (!wholePercentagesToPersonContainers.TryGetValue(wholePercentages, out personContainers))
|
||||||
result = null;
|
result = null;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using View_by_Distance.Shared.Models;
|
using View_by_Distance.Shared.Models;
|
||||||
|
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
namespace View_by_Distance.Map.Models.Stateless.Methods;
|
namespace View_by_Distance.Map.Models.Stateless.Methods;
|
||||||
|
|
||||||
@ -49,11 +50,26 @@ public interface IMapLogic
|
|||||||
bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
|
bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
|
||||||
CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation);
|
CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation);
|
||||||
static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
|
static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
|
||||||
MapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation);
|
MapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation.WholePercentages);
|
||||||
|
|
||||||
|
bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, int wholePercentages) =>
|
||||||
|
CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, wholePercentages);
|
||||||
|
static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, int wholePercentages) =>
|
||||||
|
MapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, wholePercentages);
|
||||||
|
|
||||||
string TestStatic_GetDecade(MappingFromItem mappingFromItem) =>
|
string TestStatic_GetDecade(MappingFromItem mappingFromItem) =>
|
||||||
GetDecade(mappingFromItem);
|
GetDecade(mappingFromItem);
|
||||||
static string GetDecade(MappingFromItem mappingFromItem) =>
|
static string GetDecade(MappingFromItem mappingFromItem) =>
|
||||||
DecadeLogic.GetDecade(mappingFromItem, null);
|
DecadeLogic.GetDecade(mappingFromItem, null);
|
||||||
|
|
||||||
|
ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> TestStatic_GetMappedFiles(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory) =>
|
||||||
|
GetMapped(maxDegreeOfParallelism, propertyConfiguration, configuration, ticks, personContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
||||||
|
static ReadOnlyDictionary<int, ReadOnlyDictionary<int, LocationContainer>> GetMapped(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, string a2PeopleSingletonDirectory, string eDistanceContentDirectory) =>
|
||||||
|
FaceFileLogic.GetMapped(maxDegreeOfParallelism, propertyConfiguration, configuration, ticks, personContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
||||||
|
|
||||||
|
List<LocationContainer> TestStatic_GetAvailable(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration configuration, IFaceD dFace, long ticks, string dFacesContentDirectory, ReadOnlyCollection<FilePath> filePaths) =>
|
||||||
|
GetAvailable(maxDegreeOfParallelism, propertyConfiguration, configuration, dFace, ticks, dFacesContentDirectory, filePaths);
|
||||||
|
static List<LocationContainer> GetAvailable(int maxDegreeOfParallelism, Property.Models.Configuration propertyConfiguration, Configuration configuration, IFaceD dFace, long ticks, string dFacesContentDirectory, ReadOnlyCollection<FilePath> filePaths) =>
|
||||||
|
FaceFileLogic.GetAvailable(maxDegreeOfParallelism, propertyConfiguration, configuration, dFace, ticks, dFacesContentDirectory, filePaths);
|
||||||
|
|
||||||
}
|
}
|
@ -17,14 +17,16 @@ internal abstract class RelationLogic
|
|||||||
Dictionary<long, Dictionary<int, List<LocationContainer>>> personKeyTo = [];
|
Dictionary<long, Dictionary<int, List<LocationContainer>>> personKeyTo = [];
|
||||||
foreach (LocationContainer locationContainer in locationContainers)
|
foreach (LocationContainer locationContainer in locationContainers)
|
||||||
{
|
{
|
||||||
|
if (locationContainer.PersonKey is null)
|
||||||
|
continue;
|
||||||
if (!locationContainer.FromDistanceContent)
|
if (!locationContainer.FromDistanceContent)
|
||||||
continue;
|
continue;
|
||||||
if (!locationContainer.FilePath.FullName.Contains(configuration.LocationContainerDirectoryPattern))
|
if (!locationContainer.FilePath.FullName.Contains(configuration.LocationContainerDirectoryPattern))
|
||||||
continue;
|
continue;
|
||||||
if (!personKeyTo.TryGetValue(locationContainer.PersonKey, out yearTo))
|
if (!personKeyTo.TryGetValue(locationContainer.PersonKey.Value, out yearTo))
|
||||||
{
|
{
|
||||||
personKeyTo.Add(locationContainer.PersonKey, []);
|
personKeyTo.Add(locationContainer.PersonKey.Value, []);
|
||||||
if (!personKeyTo.TryGetValue(locationContainer.PersonKey, out yearTo))
|
if (!personKeyTo.TryGetValue(locationContainer.PersonKey.Value, out yearTo))
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
if (!yearTo.TryGetValue(locationContainer.CreationDateOnly.Year, out collection))
|
if (!yearTo.TryGetValue(locationContainer.CreationDateOnly.Year, out collection))
|
||||||
@ -45,6 +47,7 @@ internal abstract class RelationLogic
|
|||||||
int lastIndex;
|
int lastIndex;
|
||||||
List<int> years = [];
|
List<int> years = [];
|
||||||
List<int> indices = [];
|
List<int> indices = [];
|
||||||
|
LocationContainer locationContainer;
|
||||||
List<(int Index, int Year)> sort = [];
|
List<(int Index, int Year)> sort = [];
|
||||||
List<LocationContainer> collection = [];
|
List<LocationContainer> collection = [];
|
||||||
KeyValuePair<int, List<LocationContainer>> keyValue;
|
KeyValuePair<int, List<LocationContainer>> keyValue;
|
||||||
@ -76,7 +79,10 @@ internal abstract class RelationLogic
|
|||||||
key = $"{years.Min()}-{keyValue.Key}";
|
key = $"{years.Min()}-{keyValue.Key}";
|
||||||
if (collection.Count == 0)
|
if (collection.Count == 0)
|
||||||
continue;
|
continue;
|
||||||
results.Add(new(key, collection[0].PersonKey, new(collection)));
|
locationContainer = collection[0];
|
||||||
|
if (locationContainer.PersonKey is null)
|
||||||
|
continue;
|
||||||
|
results.Add(new(key, locationContainer.PersonKey.Value, new(collection)));
|
||||||
collection = [];
|
collection = [];
|
||||||
years.Clear();
|
years.Clear();
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,17 @@ internal static class Face
|
|||||||
result = pngDirectory.TextualData[artist.Length..];
|
result = pngDirectory.TextualData[artist.Length..];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (result is null)
|
||||||
|
{
|
||||||
|
const string author = "Author:";
|
||||||
|
foreach (PngDirectory pngDirectory in pngDirectories)
|
||||||
|
{
|
||||||
|
if (pngDirectory.TextualData is null || !pngDirectory.TextualData.StartsWith(author))
|
||||||
|
continue;
|
||||||
|
result = pngDirectory.TextualData[author.Length..];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ public class OffsetDateTimeOriginal
|
|||||||
string checkFile;
|
string checkFile;
|
||||||
PropertyItem? propertyItem;
|
PropertyItem? propertyItem;
|
||||||
string? ticksDirectory = null;
|
string? ticksDirectory = null;
|
||||||
int dateTimeOriginal = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal;
|
const int dateTimeOriginal = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal; // 36867
|
||||||
for (int i = 0; i < int.MaxValue; i++)
|
for (int i = 0; i < int.MaxValue; i++)
|
||||||
{
|
{
|
||||||
ticksDirectory = Path.Combine(sourceDirectory, ticks.ToString());
|
ticksDirectory = Path.Combine(sourceDirectory, ticks.ToString());
|
||||||
|
@ -2,7 +2,9 @@ using System.Text.Json.Serialization;
|
|||||||
|
|
||||||
namespace View_by_Distance.Shared.Models;
|
namespace View_by_Distance.Shared.Models;
|
||||||
|
|
||||||
public record FaceFile(DateTime DateTime,
|
public record FaceFile(int? AreaPermyriad,
|
||||||
|
int? ConfidencePercent,
|
||||||
|
DateTime DateTime,
|
||||||
string? DMS,
|
string? DMS,
|
||||||
Dictionary<Stateless.FacePart, FacePoint[]>? FaceParts,
|
Dictionary<Stateless.FacePart, FacePoint[]>? FaceParts,
|
||||||
Location? Location,
|
Location? Location,
|
||||||
|
@ -5,11 +5,57 @@ namespace View_by_Distance.Shared.Models;
|
|||||||
public record LocationContainer(DateOnly CreationDateOnly,
|
public record LocationContainer(DateOnly CreationDateOnly,
|
||||||
ExifDirectory? ExifDirectory,
|
ExifDirectory? ExifDirectory,
|
||||||
int? DirectoryNumber,
|
int? DirectoryNumber,
|
||||||
string DisplayDirectoryName,
|
string? DisplayDirectoryName,
|
||||||
|
object? Encoding,
|
||||||
|
FaceFile? FaceFile,
|
||||||
FilePath FilePath,
|
FilePath FilePath,
|
||||||
bool FromDistanceContent,
|
bool FromDistanceContent,
|
||||||
int Id,
|
int Id,
|
||||||
Location? Location,
|
int? LengthPermyriad,
|
||||||
long PersonKey,
|
FilePath? LengthSource,
|
||||||
|
long? PersonKey,
|
||||||
RectangleF? Rectangle,
|
RectangleF? Rectangle,
|
||||||
int WholePercentages);
|
int WholePercentages)
|
||||||
|
{
|
||||||
|
|
||||||
|
public static LocationContainer Get(LocationContainer locationContainer, object? encoding, bool keepExifDirectory)
|
||||||
|
{
|
||||||
|
LocationContainer result;
|
||||||
|
result = new(locationContainer.CreationDateOnly,
|
||||||
|
keepExifDirectory ? locationContainer.ExifDirectory : null,
|
||||||
|
locationContainer.DirectoryNumber,
|
||||||
|
locationContainer.DisplayDirectoryName,
|
||||||
|
encoding,
|
||||||
|
locationContainer.FaceFile,
|
||||||
|
locationContainer.FilePath,
|
||||||
|
locationContainer.FromDistanceContent,
|
||||||
|
locationContainer.Id,
|
||||||
|
locationContainer.LengthPermyriad,
|
||||||
|
locationContainer.LengthSource,
|
||||||
|
locationContainer.PersonKey,
|
||||||
|
locationContainer.Rectangle,
|
||||||
|
locationContainer.WholePercentages);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LocationContainer Get(LocationContainer source, LocationContainer locationContainer, int lengthPermyriad, bool keepExifDirectory, bool keepEncoding)
|
||||||
|
{
|
||||||
|
LocationContainer result;
|
||||||
|
result = new(locationContainer.CreationDateOnly,
|
||||||
|
keepExifDirectory ? locationContainer.ExifDirectory : null,
|
||||||
|
locationContainer.DirectoryNumber,
|
||||||
|
locationContainer.DisplayDirectoryName,
|
||||||
|
keepEncoding ? locationContainer.Encoding : null,
|
||||||
|
locationContainer.FaceFile,
|
||||||
|
locationContainer.FilePath,
|
||||||
|
locationContainer.FromDistanceContent,
|
||||||
|
locationContainer.Id,
|
||||||
|
lengthPermyriad,
|
||||||
|
source.FilePath,
|
||||||
|
locationContainer.PersonKey,
|
||||||
|
locationContainer.Rectangle,
|
||||||
|
locationContainer.WholePercentages);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -4,6 +4,6 @@ public interface IFaceD
|
|||||||
{
|
{
|
||||||
|
|
||||||
public string FileNameExtension { get; }
|
public string FileNameExtension { get; }
|
||||||
void ReSaveFace(ExifDirectory exifDirectory, LocationContainer locationContainer, Models.Face face);
|
void ReSaveFace(ExifDirectory exifDirectory, FilePath filePath, Models.Face face, bool mappedFile);
|
||||||
|
|
||||||
}
|
}
|
@ -10,9 +10,9 @@ public interface ILocation
|
|||||||
static Models.Location? GetLocation(int height, Rectangle rectangle, int width) =>
|
static Models.Location? GetLocation(int height, Rectangle rectangle, int width) =>
|
||||||
Location.GetLocation(height, rectangle, width);
|
Location.GetLocation(height, rectangle, width);
|
||||||
|
|
||||||
List<Models.Face> TestStatic_FilterByIntersect(Models.Face[] faces, float rectangleIntersectMinimum, int wholePercentages) =>
|
List<Models.Face> TestStatic_FilterByIntersect(List<Models.Face> faces, float rectangleIntersectMinimum, int wholePercentages) =>
|
||||||
FilterByIntersect(faces, rectangleIntersectMinimum, wholePercentages);
|
FilterByIntersect(faces, rectangleIntersectMinimum, wholePercentages);
|
||||||
static List<Models.Face> FilterByIntersect(Models.Face[] faces, float rectangleIntersectMinimum, int wholePercentages) =>
|
static List<Models.Face> FilterByIntersect(List<Models.Face> faces, float rectangleIntersectMinimum, int wholePercentages) =>
|
||||||
Location.FilterByIntersect(faces, rectangleIntersectMinimum, wholePercentages);
|
Location.FilterByIntersect(faces, rectangleIntersectMinimum, wholePercentages);
|
||||||
|
|
||||||
RectangleF? TestStatic_GetPercentagesRectangle(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution) =>
|
RectangleF? TestStatic_GetPercentagesRectangle(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution) =>
|
||||||
|
@ -310,7 +310,7 @@ internal abstract class Location
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static List<Models.Face> FilterByIntersect(Models.Face[] faces, float rectangleIntersectMinimum, int wholePercentages)
|
internal static List<Models.Face> FilterByIntersect(List<Models.Face> faces, float rectangleIntersectMinimum, int wholePercentages)
|
||||||
{
|
{
|
||||||
List<Models.Face> results = [];
|
List<Models.Face> results = [];
|
||||||
float? percent;
|
float? percent;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user