LocationContainer

This commit is contained in:
Mike Phares 2022-12-28 23:52:42 -07:00
parent 681b2fdf3c
commit 26edd826d5
14 changed files with 317 additions and 220 deletions

View File

@ -38,53 +38,14 @@ public partial class E_Distance
_DistanceMoveUnableToMatch = distanceMoveUnableToMatch; _DistanceMoveUnableToMatch = distanceMoveUnableToMatch;
} }
private void MoveUnableToMatch(string eDistanceContentDirectory, string file, string fileName) private static void MoveUnableToMatch(string file)
{ {
bool check; string checkFile = string.Concat(file, ".unk");
string? directoryName = Path.GetDirectoryName(file); if (File.Exists(file) && !File.Exists(checkFile))
if (fileName is null || directoryName is null) File.Move(file, checkFile);
check = false;
else
{
if (string.IsNullOrEmpty(directoryName) || string.IsNullOrEmpty(directoryName) || !directoryName.Contains(eDistanceContentDirectory))
check = false;
else
{
List<string> directoryNames = new();
string? checkDirectoryName = directoryName;
for (int i = 0; i < int.MaxValue; i++)
{
if (string.IsNullOrEmpty(checkDirectoryName))
continue;
directoryNames.Add(Path.GetFileName(checkDirectoryName));
checkDirectoryName = Path.GetDirectoryName(checkDirectoryName);
if (string.IsNullOrEmpty(checkDirectoryName))
continue;
if (checkDirectoryName == eDistanceContentDirectory)
break;
}
if (string.IsNullOrEmpty(checkDirectoryName) || !directoryNames.Any() || !long.TryParse(directoryNames[^1][1..^1], out long directoryTicks))
{
check = false;
File.Delete(file);
}
else
{
checkDirectoryName = Path.Combine(checkDirectoryName, $"({directoryTicks}_{string.Join('-', _RangeDistanceTolerance)})");
for (int i = directoryNames.Count - 1 - 1; i > -1; i--)
checkDirectoryName = Path.Combine(checkDirectoryName, directoryNames[i]);
if (!Directory.Exists(checkDirectoryName))
_ = Directory.CreateDirectory(checkDirectoryName);
File.Move(file, Path.Combine(checkDirectoryName, fileName));
check = true;
}
}
}
if (check)
_Moved.Add(file);
} }
private FaceDistanceContainer[] GetFaceDistanceContainers(MappingFromItem mappingFromItem, List<Face> filteredFaces) private FaceDistanceContainer[] GetFaceDistanceContainers(MappingFromItem mappingFromItem, List<Face> intersectFaces)
{ {
FaceDistanceContainer[] results; FaceDistanceContainer[] results;
int confidencePercent; int confidencePercent;
@ -92,7 +53,7 @@ public partial class E_Distance
FaceDistance faceDistance; FaceDistance faceDistance;
FaceDistanceContainer faceDistanceContainer; FaceDistanceContainer faceDistanceContainer;
List<FaceDistanceContainer> collection = new(); List<FaceDistanceContainer> collection = new();
foreach (Face face in filteredFaces) foreach (Face face in intersectFaces)
{ {
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)
throw new NotSupportedException(); throw new NotSupportedException();
@ -104,7 +65,7 @@ public partial class E_Distance
{ {
faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding);
faceDistance = new(confidencePercent, faceEncoding, mappingFromItem.Id, mappingFromItem.IsWrongYear, mappingFromItem.MinimumDateTime, normalizedRectangle); faceDistance = new(confidencePercent, faceEncoding, mappingFromItem.Id, mappingFromItem.IsWrongYear, mappingFromItem.MinimumDateTime, normalizedRectangle);
lock (filteredFaces) lock (intersectFaces)
face.SetFaceDistance(faceDistance); face.SetFaceDistance(faceDistance);
} }
faceDistanceContainer = new(face, faceDistance); faceDistanceContainer = new(face, faceDistance);
@ -126,42 +87,38 @@ public partial class E_Distance
return faceDistanceEncodings; return faceDistanceEncodings;
} }
private List<(Face Face, double? Length)> GetValues(MappingFromItem mappingFromItem, Face[] faces, Shared.Models.FaceEncoding modelsFaceEncoding, int normalizedRectangle) private List<(Face Face, double? Length)> GetValues(MappingFromItem mappingFromItem, List<Face> intersectFaces, Shared.Models.FaceEncoding modelsFaceEncoding)
{ {
List<(Face Face, double? Length)> results = new(); List<(Face Face, double? Length)> results = new();
Face face; Face face;
FaceDistance faceDistanceLength; FaceDistance faceDistanceLength;
List<Face> filteredFaces = FilterByIntersect(faces, normalizedRectangle); FaceRecognitionDotNet.FaceEncoding faceRecognitionDotNetFaceEncoding = FaceRecognition.LoadFaceEncoding(modelsFaceEncoding.RawEncoding);
if (filteredFaces.Any()) FaceDistance faceDistanceEncoding = new(faceRecognitionDotNetFaceEncoding);
FaceDistanceContainer[] faceDistanceContainers = GetFaceDistanceContainers(mappingFromItem, intersectFaces);
int faceDistanceContainersLength = faceDistanceContainers.Length;
if (faceDistanceContainersLength != intersectFaces.Count)
throw new NotSupportedException();
List<FaceDistance> faceDistanceEncodings = GetFaceDistanceEncodings(faceDistanceContainers);
if (faceDistanceEncodings.Count != intersectFaces.Count)
throw new NotSupportedException();
List<FaceDistance> faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncoding);
if (faceDistanceLengths.Count != faceDistanceContainersLength)
throw new NotSupportedException();
for (int i = 0; i < intersectFaces.Count; i++)
{ {
FaceRecognitionDotNet.FaceEncoding faceRecognitionDotNetFaceEncoding = FaceRecognition.LoadFaceEncoding(modelsFaceEncoding.RawEncoding); face = intersectFaces[i];
FaceDistance faceDistanceEncoding = new(faceRecognitionDotNetFaceEncoding); faceDistanceLength = faceDistanceLengths[i];
FaceDistanceContainer[] faceDistanceContainers = GetFaceDistanceContainers(mappingFromItem, filteredFaces); if (faceDistanceLength.Length is null)
int faceDistanceContainersLength = faceDistanceContainers.Length;
if (faceDistanceContainersLength != filteredFaces.Count)
throw new NotSupportedException(); throw new NotSupportedException();
List<FaceDistance> faceDistanceEncodings = GetFaceDistanceEncodings(faceDistanceContainers); results.Add(new(face, faceDistanceLength.Length.Value));
if (faceDistanceEncodings.Count != filteredFaces.Count)
throw new NotSupportedException();
List<FaceDistance> faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncoding);
if (faceDistanceLengths.Count != faceDistanceContainersLength)
throw new NotSupportedException();
for (int i = 0; i < filteredFaces.Count; i++)
{
face = filteredFaces[i];
faceDistanceLength = faceDistanceLengths[i];
if (faceDistanceLength.Length is null)
throw new NotSupportedException();
results.Add(new(face, faceDistanceLength.Length.Value));
}
} }
return results; return results;
} }
private (Face, double?)[] GetClosestFaceByDistanceIgnoringTolerance(MappingFromItem mappingFromItem, int normalizedRectangle, Face[] filteredFaces, Shared.Models.FaceEncoding modelsFaceEncoding) private (Face, double?)[] GetClosestFaceByDistanceIgnoringTolerance(MappingFromItem mappingFromItem, List<Face> intersectFaces, Shared.Models.FaceEncoding modelsFaceEncoding)
{ {
(Face, double?)[] results; (Face, double?)[] results;
List<(Face Face, double? Length)> collection = GetValues(mappingFromItem, filteredFaces, modelsFaceEncoding, normalizedRectangle); List<(Face Face, double? Length)> collection = GetValues(mappingFromItem, intersectFaces, modelsFaceEncoding);
results = (from l in collection orderby l.Length select l).Take(1).ToArray(); results = (from l in collection orderby l.Length select l).Take(1).ToArray();
if (results.Any()) if (results.Any())
{ {
@ -240,70 +197,41 @@ public partial class E_Distance
} }
} }
private static List<Face> FilterByIntersect(Face[] faces, int normalizedRectangle) public void LookForMatchFacesAndPossiblyRename(string facesFileNameExtension, string eDistanceContentDirectory, MappingFromItem mappingFromItem, List<Face> faces, List<LocationContainer<MetadataExtractor.Directory>> collection)
{
List<Face> results = new();
bool useOldWay;
double? percent;
System.Drawing.Rectangle checkRectangle;
System.Drawing.Rectangle sourceRectangle;
System.Drawing.Rectangle intersectRectangle;
foreach (Face face in faces)
{
if (face.Location is null || face.OutputResolution is null)
continue;
checkRectangle = new(face.Location.Left, face.Location.Top, face.Location.Right - face.Location.Left, face.Location.Bottom - face.Location.Top);
for (int i = 1; i < 3; i++)
{
useOldWay = i == 1;
sourceRectangle = Shared.Models.Stateless.Methods.ILocation.GetRectangle(checkRectangle, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, normalizedRectangle, face.OutputResolution, useOldWay);
intersectRectangle = System.Drawing.Rectangle.Intersect(checkRectangle, sourceRectangle);
if (intersectRectangle.Width == 0 || intersectRectangle.Height == 0)
continue;
percent = (double)intersectRectangle.Width * intersectRectangle.Height / (checkRectangle.Width * checkRectangle.Height);
if (percent < 0.000001)
continue;
results.Add(face);
}
}
return results;
}
public void LookForMatchFacesAndPossiblyRename(string facesFileNameExtension, string eDistanceContentDirectory, MappingFromItem mappingFromItem, List<Face> faces, List<(bool c, string File, int NormalizedRectangle, IReadOnlyList<MetadataExtractor.Directory>? Directories)> collection)
{ {
string? json; string? json;
string fileName; string fileName;
string[] matches; string[] matches;
FileInfo? fileInfo; FileInfo? fileInfo;
List<Face> intersectFaces;
List<(Face, double?)> checkFaces = new(); List<(Face, double?)> checkFaces = new();
Shared.Models.FaceEncoding? modelsFaceEncoding; Shared.Models.FaceEncoding? modelsFaceEncoding;
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(); 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) if (filteredFaces.Length != faces.Count)
checkFaces.Clear(); checkFaces.Clear();
foreach ((bool fromDistanceContent, string file, int normalizedRectangle, IReadOnlyList<MetadataExtractor.Directory>? directories) in collection) foreach (LocationContainer<MetadataExtractor.Directory>? locationContainer in collection)
{ {
if (!filteredFaces.Any()) if (_Renamed.Contains(locationContainer.File))
break;
if (_Renamed.Contains(file))
continue; continue;
fileName = Path.GetFileName(file); fileName = Path.GetFileName(locationContainer.File);
if (fromDistanceContent && _DuplicateMappedFaceFiles.Contains(fileName)) if (locationContainer.FromDistanceContent && _DuplicateMappedFaceFiles.Contains(fileName))
continue; continue;
checkFaces.Clear(); checkFaces.Clear();
if (directories is null) if (!locationContainer.Directories.Any())
{ {
if (fromDistanceContent) if (locationContainer.FromDistanceContent)
throw new NullReferenceException(nameof(directories)); throw new NullReferenceException(nameof(locationContainer.Directories));
continue; continue;
} }
json = Metadata.Models.Stateless.IMetadata.GetFaceEncoding(directories); json = Metadata.Models.Stateless.IMetadata.GetFaceEncoding(locationContainer.Directories);
if (json is null) if (json is null)
{ {
if (_DistanceMoveUnableToMatch) if (_DistanceMoveUnableToMatch)
MoveUnableToMatch(eDistanceContentDirectory, file, fileName); MoveUnableToMatch(locationContainer.File);
continue; continue;
} }
checkFaces.AddRange(GetMatchingFacesByFaceEncoding(filteredFaces, json)); if (filteredFaces.Any())
checkFaces.AddRange(GetMatchingFacesByFaceEncoding(filteredFaces, 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))
@ -312,44 +240,49 @@ public partial class E_Distance
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();
checkFaces.AddRange(GetClosestFaceByDistanceIgnoringTolerance(mappingFromItem, normalizedRectangle, filteredFaces, modelsFaceEncoding)); if (filteredFaces.Any())
{
intersectFaces = Shared.Models.Stateless.Methods.ILocation.FilterByIntersect(filteredFaces, locationContainer.NormalizedRectangle);
if (intersectFaces.Any())
checkFaces.AddRange(GetClosestFaceByDistanceIgnoringTolerance(mappingFromItem, intersectFaces, modelsFaceEncoding));
}
} }
if (!checkFaces.Any()) if (!checkFaces.Any())
{ {
if (_DistanceMoveUnableToMatch) if (_DistanceMoveUnableToMatch)
MoveUnableToMatch(eDistanceContentDirectory, file, fileName); MoveUnableToMatch(locationContainer.File);
continue; continue;
} }
if (checkFaces.Count != 1) if (checkFaces.Count != 1)
{ {
if (_DistanceMoveUnableToMatch) if (_DistanceMoveUnableToMatch)
MoveUnableToMatch(eDistanceContentDirectory, file, fileName); MoveUnableToMatch(locationContainer.File);
continue; continue;
} }
fileInfo = CheckFileThenGetFileInfo(facesFileNameExtension, mappingFromItem, file, checkFaces); fileInfo = CheckFileThenGetFileInfo(facesFileNameExtension, mappingFromItem, locationContainer.File, checkFaces);
if (fileInfo is not null) if (fileInfo is not null)
{ {
if (_DistanceRenameToMatch && fileInfo is not null) if (_DistanceRenameToMatch && fileInfo is not null)
{ {
if (fileInfo.Exists) if (fileInfo.Exists)
File.Delete(file); File.Delete(locationContainer.File);
else else
File.Move(file, fileInfo.FullName); File.Move(locationContainer.File, fileInfo.FullName);
_Renamed.Add(file); _Renamed.Add(locationContainer.File);
} }
continue; continue;
} }
if (_AllMappedFaceFileNames.Contains(fileName)) if (_AllMappedFaceFileNames.Contains(fileName))
{ {
lock (_AllMappedFaceFiles) lock (_AllMappedFaceFiles)
matches = (from l in _AllMappedFaceFiles where l != file && Path.GetFileName(l) == fileName select l).ToArray(); matches = (from l in _AllMappedFaceFiles where l != locationContainer.File && Path.GetFileName(l) == fileName select l).ToArray();
if (fromDistanceContent && matches.Any()) if (locationContainer.FromDistanceContent && matches.Any())
AppendMatchingDuplicates(file, matches); AppendMatchingDuplicates(locationContainer.File, matches);
} }
if (!fromDistanceContent) if (!locationContainer.FromDistanceContent)
continue; continue;
lock (_AllMappedFaceFiles) lock (_AllMappedFaceFiles)
_AllMappedFaceFiles.Add(file); _AllMappedFaceFiles.Add(locationContainer.File);
lock (_AllMappedFaceFileNames) lock (_AllMappedFaceFileNames)
_AllMappedFaceFileNames.Add(fileName); _AllMappedFaceFileNames.Add(fileName);
} }

View File

@ -140,6 +140,12 @@ public class D_Face
#pragma warning disable CA1416 #pragma warning disable CA1416
private static (int width, int height) Get(string file)
{
using Bitmap source = new(file);
return new(source.Width, source.Height);
}
private PropertyItem GetPropertyItem(int id, string value) private PropertyItem GetPropertyItem(int id, string value)
{ {
PropertyItem result = (PropertyItem)_ConstructorInfo.Invoke(null); PropertyItem result = (PropertyItem)_ConstructorInfo.Invoke(null);
@ -291,12 +297,60 @@ public class D_Face
#pragma warning restore CA1416 #pragma warning restore CA1416
public List<Shared.Models.Face> GetFaces(string dResultsFullGroupDirectory, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection) private static List<LocationContainer<MetadataExtractor.Directory>> GetCollection(int outputResolutionWidth, int outputResolutionHeight, List<LocationContainer<MetadataExtractor.Directory>> collection, List<Shared.Models.Face> faces)
{
List<LocationContainer<MetadataExtractor.Directory>> results = new();
string? json;
int width, height;
Location? location;
Rectangle? rectangle;
List<int> skip = new();
OutputResolution? outputResolution = null;
foreach (Shared.Models.Face face in faces)
{
if (face.Location is null || face.OutputResolution is null)
continue;
skip.Add(Shared.Models.Stateless.Methods.ILocation.GetNormalizedRectangle(face.Location, ILocation.Digits, face.OutputResolution));
}
foreach (LocationContainer<MetadataExtractor.Directory> locationContainer in collection)
{
if (locationContainer.Directories is null)
continue;
if (skip.Contains(locationContainer.NormalizedRectangle))
continue;
foreach (Shared.Models.Face face in faces)
{
if (face.Location is not null && face.OutputResolution is not null)
continue;
json = Metadata.Models.Stateless.IMetadata.GetOutputResolution(locationContainer.Directories);
if (json is not null)
{
outputResolution = JsonSerializer.Deserialize<OutputResolution>(json);
if (outputResolution is not null && (outputResolution.Width != outputResolutionWidth || outputResolution.Height != outputResolutionHeight))
continue;
}
(width, height) = Get(locationContainer.File);
rectangle = Shared.Models.Stateless.Methods.ILocation.GetRectangle(height, ILocation.Digits, ILocation.Factor, locationContainer.NormalizedRectangle, outputResolutionHeight, outputResolutionWidth, width);
if (rectangle is null)
continue;
location = Shared.Models.Stateless.Methods.ILocation.GetLocation(outputResolutionHeight, rectangle.Value, outputResolutionWidth);
if (location is null)
continue;
if (!results.Any(l => l.NormalizedRectangle == locationContainer.NormalizedRectangle))
results.Add(new(locationContainer.FromDistanceContent, locationContainer.File, locationContainer.NormalizedRectangle, locationContainer.Directories, rectangle.Value, location));
}
}
if (results.Any())
outputResolution = null;
return results;
}
public List<Shared.Models.Face> GetFaces(string dResultsFullGroupDirectory, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, List<LocationContainer<MetadataExtractor.Directory>>? collection, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection)
{ {
List<Shared.Models.Face>? results; List<Shared.Models.Face>? results;
if (string.IsNullOrEmpty(dResultsFullGroupDirectory)) if (string.IsNullOrEmpty(dResultsFullGroupDirectory))
throw new NullReferenceException(nameof(dResultsFullGroupDirectory)); throw new NullReferenceException(nameof(dResultsFullGroupDirectory));
string json; string? json;
List<Location>? locations; List<Location>? locations;
string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize) }; string[] changesFrom = new string[] { 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();
@ -334,10 +388,15 @@ public class D_Face
parseExceptions.Add(nameof(D_Face)); parseExceptions.Add(nameof(D_Face));
} }
} }
if (mappingFromPhotoPrismCollection is null || results is null) List<LocationContainer<MetadataExtractor.Directory>> containers;
locations = null; if (results is null || collection is null)
containers = new();
else else
locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(mappingFromPhotoPrismCollection, results); containers = GetCollection(outputResolutionWidth, outputResolutionHeight, collection, results);
if (mappingFromPhotoPrismCollection is null || results is null)
locations = (from l in containers where l is not null select l.Location).ToList();
else
locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(mappingFromPhotoPrismCollection, results, containers);
if (results is null || (locations is not null && locations.Any())) if (results is null || (locations is not null && locations.Any()))
{ {
results = GetFaces(property, mappingFromItem, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, locations); results = GetFaces(property, mappingFromItem, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, locations);

View File

@ -283,7 +283,7 @@ public partial class DlibDotNet
return result; return result;
} }
private void FullParallelForWork(A_Property propertyLogic, Dictionary<int, List<(bool, string, int, IReadOnlyList<MetadataExtractor.Directory>?)>> idToMappedFaceFilesWithCollection, string outputResolution, string bResultsFullGroupDirectory, string cResultsFullGroupDirectory, string dResultsDateGroupDirectory, string dResultsFullGroupDirectory, string eDistanceContentDirectory, List<Tuple<string, DateTime>> sourceDirectoryChanges, List<FileHolder?> propertyFileHolderCollection, List<Shared.Models.Property?> propertyCollection, List<List<KeyValuePair<string, string>>> metadataCollections, List<Dictionary<string, int[]>> resizeKeyValuePairs, List<List<Shared.Models.Face>> imageFaceCollections, Container container, int index, Item item, DateTime[] containerDateTimes) private void FullParallelForWork(A_Property propertyLogic, Dictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> idToMappedFaceFilesWithCollection, string outputResolution, string bResultsFullGroupDirectory, string cResultsFullGroupDirectory, string dResultsDateGroupDirectory, string dResultsFullGroupDirectory, string eDistanceContentDirectory, List<Tuple<string, DateTime>> sourceDirectoryChanges, List<FileHolder?> propertyFileHolderCollection, List<Shared.Models.Property?> propertyCollection, List<List<KeyValuePair<string, string>>> metadataCollections, List<Dictionary<string, int[]>> resizeKeyValuePairs, List<List<Shared.Models.Face>> imageFaceCollections, Container container, int index, Item item, DateTime[] containerDateTimes)
{ {
if (_Log is null) if (_Log is null)
throw new NullReferenceException(nameof(_Log)); throw new NullReferenceException(nameof(_Log));
@ -369,10 +369,14 @@ public partial class DlibDotNet
int outputResolutionHeight = outputResolutionCollection[1]; int outputResolutionHeight = outputResolutionCollection[1];
int outputResolutionOrientation = outputResolutionCollection[2]; int outputResolutionOrientation = outputResolutionCollection[2];
List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection; List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection;
List<(bool, string, int, IReadOnlyList<MetadataExtractor.Directory>?)>? collection; List<LocationContainer<MetadataExtractor.Directory>>? collection;
if (item.Property?.Id is null)
collection = null;
else
_ = idToMappedFaceFilesWithCollection.TryGetValue(item.Property.Id.Value, out collection);
if (!_FileNameToCollection.TryGetValue(mappingFromItem.RelativePath[1..], out mappingFromPhotoPrismCollection)) if (!_FileNameToCollection.TryGetValue(mappingFromItem.RelativePath[1..], out mappingFromPhotoPrismCollection))
mappingFromPhotoPrismCollection = null; mappingFromPhotoPrismCollection = null;
faces = _Faces.GetFaces(dResultsFullGroupDirectory, subFileTuples, parseExceptions, property, mappingFromItem, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, mappingFromPhotoPrismCollection); faces = _Faces.GetFaces(dResultsFullGroupDirectory, subFileTuples, parseExceptions, property, mappingFromItem, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, collection, mappingFromPhotoPrismCollection);
if (_AppSettings.MaxDegreeOfParallelism < 2) if (_AppSettings.MaxDegreeOfParallelism < 2)
ticks = LogDelta(ticks, nameof(D_Face.GetFaces)); ticks = LogDelta(ticks, nameof(D_Face.GetFaces));
bool anyFacesSaved = _Faces.SaveFaces(dResultsFullGroupDirectory, subFileTuples, parseExceptions, mappingFromItem, facesDirectory, faces); bool anyFacesSaved = _Faces.SaveFaces(dResultsFullGroupDirectory, subFileTuples, parseExceptions, mappingFromItem, facesDirectory, faces);
@ -380,8 +384,7 @@ public partial class DlibDotNet
ticks = LogDelta(ticks, nameof(D_Face.SaveFaces)); ticks = LogDelta(ticks, nameof(D_Face.SaveFaces));
if ((_Configuration.DistanceMoveUnableToMatch || _Configuration.DistanceRenameToMatch) if ((_Configuration.DistanceMoveUnableToMatch || _Configuration.DistanceRenameToMatch)
&& _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution) && _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution)
&& !anyFacesSaved && item.Property?.Id is not null && !anyFacesSaved && collection is not null)
&& idToMappedFaceFilesWithCollection.TryGetValue(item.Property.Id.Value, out collection))
_Distance.LookForMatchFacesAndPossiblyRename(_Faces.FileNameExtension, eDistanceContentDirectory, mappingFromItem, faces, collection); _Distance.LookForMatchFacesAndPossiblyRename(_Faces.FileNameExtension, eDistanceContentDirectory, mappingFromItem, faces, collection);
if (_Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) if (_Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution))
{ {
@ -405,7 +408,7 @@ public partial class DlibDotNet
private int FullParallelWork(int maxDegreeOfParallelism, private int FullParallelWork(int maxDegreeOfParallelism,
A_Property propertyLogic, A_Property propertyLogic,
Dictionary<int, List<(bool, string, int, IReadOnlyList<MetadataExtractor.Directory>?)>> idToMappedFaceFilesWithCollection, Dictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> idToMappedFaceFilesWithCollection,
string outputResolution, string outputResolution,
string bResultsFullGroupDirectory, string bResultsFullGroupDirectory,
string cResultsFullGroupDirectory, string cResultsFullGroupDirectory,
@ -658,7 +661,7 @@ public partial class DlibDotNet
int maxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism; int maxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism;
List<Shared.Models.Property?> nullablePropertyCollection = new(); List<Shared.Models.Property?> nullablePropertyCollection = new();
List<List<KeyValuePair<string, string>>> metadataCollection = new(); List<List<KeyValuePair<string, string>>> metadataCollection = new();
Dictionary<int, List<(bool, string, int, IReadOnlyList<MetadataExtractor.Directory>?)>> idToMappedFaceFilesWithCollection = GetDictionary(ticks, a2PeopleContentDirectory, eDistanceContentDirectory); Dictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> idToMappedFaceFilesWithCollection = GetDictionary(ticks, a2PeopleContentDirectory, eDistanceContentDirectory);
string dResultsDateGroupDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(D_Face)); string dResultsDateGroupDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(D_Face));
foreach (string outputResolution in _Configuration.OutputResolutions) foreach (string outputResolution in _Configuration.OutputResolutions)
{ {
@ -874,7 +877,7 @@ public partial class DlibDotNet
List<Item> filteredItems = GetItems(argZero, containers); List<Item> filteredItems = GetItems(argZero, containers);
mapLogic.SaveShortcutsForOutputResolutions(filteredItems, mappingCollection, personKeyToCount); mapLogic.SaveShortcutsForOutputResolutions(filteredItems, mappingCollection, personKeyToCount);
} }
if (_Configuration.PersonCharactersToCopyTo.Length == 1) if (_Configuration.PersonCharactersToCopyTo.Length == 1 && _Configuration.PersonCharacters.ToArray().Contains(_Configuration.PersonCharactersToCopyTo[0]))
mapLogic.CopyAtLeastOneMappedFiles(_Configuration.PersonCharactersToCopyTo[0], dFacesContentDirectory, a2PeopleSingletonDirectory, mappingCollection); mapLogic.CopyAtLeastOneMappedFiles(_Configuration.PersonCharactersToCopyTo[0], dFacesContentDirectory, a2PeopleSingletonDirectory, mappingCollection);
Dictionary<int, Dictionary<int, Mapping>> idToNormalizedRectangleToMapping = MapLogicSupport.GetIdToNormalizedRectangleToFace(mappingCollection); Dictionary<int, Dictionary<int, Mapping>> idToNormalizedRectangleToMapping = MapLogicSupport.GetIdToNormalizedRectangleToFace(mappingCollection);
mapLogic.CopyManualFiles(dFacesContentDirectory, idToNormalizedRectangleToMapping); mapLogic.CopyManualFiles(dFacesContentDirectory, idToNormalizedRectangleToMapping);
@ -1008,11 +1011,11 @@ public partial class DlibDotNet
return results; return results;
} }
private void ParallelFor(string eDistanceContentDirectory, List<(bool, string, int, int, IReadOnlyList<MetadataExtractor.Directory>?)> collection, string file) private void ParallelFor(string eDistanceContentDirectory, List<(bool, string, int, int, IReadOnlyList<MetadataExtractor.Directory>)> collection, string file)
{ {
const string lnk = ".lnk"; const string lnk = ".lnk";
int? id, normalizedRectangle; int? id, normalizedRectangle;
IReadOnlyList<MetadataExtractor.Directory>? directories; IReadOnlyList<MetadataExtractor.Directory> directories;
bool fromDistanceContent = !file.EndsWith(lnk) && file.Contains(eDistanceContentDirectory); bool fromDistanceContent = !file.EndsWith(lnk) && file.Contains(eDistanceContentDirectory);
if (!file.EndsWith(lnk)) if (!file.EndsWith(lnk))
(id, normalizedRectangle) = Shared.Models.Stateless.Methods.IMapping.GetConverted(_MapConfiguration.FacesFileNameExtension, file); (id, normalizedRectangle) = Shared.Models.Stateless.Methods.IMapping.GetConverted(_MapConfiguration.FacesFileNameExtension, file);
@ -1021,52 +1024,58 @@ public partial class DlibDotNet
if (id is null || normalizedRectangle is null) if (id is null || normalizedRectangle is null)
return; return;
if (file.EndsWith(lnk) || (!_Configuration.DistanceMoveUnableToMatch && !_Configuration.DistanceRenameToMatch)) if (file.EndsWith(lnk) || (!_Configuration.DistanceMoveUnableToMatch && !_Configuration.DistanceRenameToMatch))
directories = null; directories = new List<MetadataExtractor.Directory>();
else else
directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(file); directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(file);
lock (collection) lock (collection)
collection.Add(new(fromDistanceContent, file, id.Value, normalizedRectangle.Value, directories)); collection.Add(new(fromDistanceContent, file, id.Value, normalizedRectangle.Value, directories));
} }
private List<(bool, string, int, int, IReadOnlyList<MetadataExtractor.Directory>?)> GetCollection(long ticks, string? a2PeopleContentDirectory, string eDistanceContentDirectory) private List<(bool, string, int, int, IReadOnlyList<MetadataExtractor.Directory>)> GetCollection(long ticks, string? a2PeopleContentDirectory, string eDistanceContentDirectory)
{ {
string file;
List<string> files = new(); List<string> files = new();
List<(bool, string, int, int, IReadOnlyList<MetadataExtractor.Directory>?)> results = new(); List<(bool, string, int, int, IReadOnlyList<MetadataExtractor.Directory>)> results = new();
files.AddRange(Map.Models.Stateless.Methods.IMapLogic.GetDisplayDirectoryAllFiles(_PersonContainers)); files.AddRange(Map.Models.Stateless.Methods.IMapLogic.GetDisplayDirectoryAllFiles(_PersonContainers));
files.AddRange(Map.Models.Stateless.Methods.IMapLogic.DeleteEmptyDirectoriesAndGetMappedFaceFiles(_MapConfiguration, _PersonContainers, ticks, a2PeopleContentDirectory, eDistanceContentDirectory)); files.AddRange(Map.Models.Stateless.Methods.IMapLogic.DeleteEmptyDirectoriesAndGetMappedFaceFiles(_MapConfiguration, _PersonContainers, ticks, a2PeopleContentDirectory, eDistanceContentDirectory));
// foreach (string file in files) for (int i = 0; i < files.Count; i++)
// { {
// if (!file.EndsWith(".dup")) file = files[i];
// continue; if (!file.EndsWith(".dup") && !file.EndsWith(".unk"))
// if (!File.Exists(file)) continue;
// continue; if (!File.Exists(file))
// File.Move(file, file[..^4]); continue;
// } File.Move(file, file[..^4]);
if (files.Any() && (_Configuration.DistanceMoveUnableToMatch || _Configuration.DistanceRenameToMatch)) files[i] = file[..^4];
}
string[] distictFiles = files.Distinct().ToArray();
if (distictFiles.Any() && (_Configuration.DistanceMoveUnableToMatch || _Configuration.DistanceRenameToMatch))
{ {
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
string message = $") Building Mapped Face Files Collection - {totalSeconds} total second(s)"; string message = $") Building Mapped Face Files Collection - {totalSeconds} total second(s)";
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism }; ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism };
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
using ProgressBar progressBar = new(files.Count, message, options); using ProgressBar progressBar = new(distictFiles.Length, message, options);
_ = Parallel.For(0, files.Count, parallelOptions, (i, state) => _ = Parallel.For(0, distictFiles.Length, parallelOptions, (i, state) =>
{ {
progressBar.Tick(); progressBar.Tick();
ParallelFor(eDistanceContentDirectory, results, files[i]); ParallelFor(eDistanceContentDirectory, results, distictFiles[i]);
}); });
} }
return results; return results;
} }
private Dictionary<int, List<(bool, string, int, IReadOnlyList<MetadataExtractor.Directory>?)>> GetDictionary(long ticks, string? a2PeopleContentDirectory, string eDistanceContentDirectory) private Dictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> GetDictionary(long ticks, string? a2PeopleContentDirectory, string eDistanceContentDirectory)
{ {
Dictionary<int, List<(bool, string, int, IReadOnlyList<MetadataExtractor.Directory>?)>> results = new(); Dictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> results = new();
List<(bool, string, int, int, IReadOnlyList<MetadataExtractor.Directory>?)> collection = GetCollection(ticks, a2PeopleContentDirectory, eDistanceContentDirectory); LocationContainer<MetadataExtractor.Directory> noob;
foreach ((bool fromDistanceContent, string file, int id, int normalizedRectangle, IReadOnlyList<MetadataExtractor.Directory>? directories) in collection) List<(bool, string, int, int, IReadOnlyList<MetadataExtractor.Directory>)> collection = GetCollection(ticks, a2PeopleContentDirectory, eDistanceContentDirectory);
foreach ((bool fromDistanceContent, string file, int id, int normalizedRectangle, IReadOnlyList<MetadataExtractor.Directory> directories) in collection)
{ {
if (!results.ContainsKey(id)) if (!results.ContainsKey(id))
results.Add(id, new()); results.Add(id, new());
results[id].Add(new(fromDistanceContent, file, normalizedRectangle, directories)); noob = new LocationContainer<MetadataExtractor.Directory>(fromDistanceContent, file, normalizedRectangle, directories, null, null);
results[id].Add(noob);
} }
return results; return results;
} }

View File

@ -915,7 +915,7 @@ public class MapLogic : Shared.Models.Methods.IMapLogic
collection.Clear(); collection.Clear();
windowsShortcut = WindowsShortcut.Load(file); windowsShortcut = WindowsShortcut.Load(file);
fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file); fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file);
if (windowsShortcut.Path is null) if (string.IsNullOrEmpty(windowsShortcut.Path))
continue; continue;
if (!Directory.Exists(windowsShortcut.Path)) if (!Directory.Exists(windowsShortcut.Path))
{ {

View File

@ -233,7 +233,7 @@ internal abstract class MapLogic
if (!string.IsNullOrEmpty(a2PeopleContentDirectory)) if (!string.IsNullOrEmpty(a2PeopleContentDirectory))
File.WriteAllLines(Path.Combine(a2PeopleContentDirectory, "People - C.tsv"), from l in lines select l.Line); File.WriteAllLines(Path.Combine(a2PeopleContentDirectory, "People - C.tsv"), from l in lines select l.Line);
List<(string, string[], string)> collection = DeleteEmptyDirectoriesAndGetCollection(configuration, personKeyFormattedCollection, ticksDirectories, message); List<(string, string[], string)> collection = DeleteEmptyDirectoriesAndGetCollection(configuration, personKeyFormattedCollection, ticksDirectories, message);
foreach ((string personKeyFormatted, string[] personDisplayDirectoryNames, string mappedFaceFile) in collection) foreach ((_, _, string mappedFaceFile) in collection)
results.Add(mappedFaceFile); results.Add(mappedFaceFile);
return results; return results;
} }

View File

@ -8,9 +8,9 @@ public interface IMetadata
static string? GetFaceEncoding(IReadOnlyList<MetadataExtractor.Directory> directories) => static string? GetFaceEncoding(IReadOnlyList<MetadataExtractor.Directory> directories) =>
Metadata.GetFaceEncoding(directories); Metadata.GetFaceEncoding(directories);
string? TestStatic_GetFaceX(IReadOnlyList<MetadataExtractor.Directory> directories) => string? TestStatic_GetOutputResolution(IReadOnlyList<MetadataExtractor.Directory> directories) =>
GetFaceX(directories); GetOutputResolution(directories);
static string? GetFaceX(IReadOnlyList<MetadataExtractor.Directory> directories) => static string? GetOutputResolution(IReadOnlyList<MetadataExtractor.Directory> directories) =>
Metadata.GetFaceX(directories); Metadata.GetOutputResolution(directories);
} }

View File

@ -25,7 +25,7 @@ internal class Metadata
return result; return result;
} }
internal static string? GetFaceX(IReadOnlyList<MetadataExtractor.Directory> directories) internal static string? GetOutputResolution(IReadOnlyList<MetadataExtractor.Directory> directories)
{ {
string? result; string? result;
List<string> results = new(); List<string> results = new();

View File

@ -64,6 +64,32 @@ public class A_Property
#pragma warning disable CA1416 #pragma warning disable CA1416
private static List<DateTime> GetMetadataDateTimesByPattern(string dateTimeFormat, FileHolder fileHolder)
{
List<DateTime> results = new();
try
{
DateTime checkDateTime;
DateTime kristy = new(1976, 3, 8);
IReadOnlyList<MetadataExtractor.Directory> directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(fileHolder.FullName);
foreach (MetadataExtractor.Directory directory in directories)
{
foreach (MetadataExtractor.Tag tag in directory.Tags)
{
if (string.IsNullOrEmpty(tag.Description) || tag.Description.Length != dateTimeFormat.Length)
continue;
if (!DateTime.TryParseExact(tag.Description, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime))
continue;
if (checkDateTime < kristy)
continue;
results.Add(checkDateTime);
}
}
}
catch (Exception) { }
return results;
}
private Shared.Models.Property GetImageProperty(FileHolder fileHolder, Shared.Models.Property? property, bool populateId, bool isIgnoreExtension, bool isValidImageFormatExtension, bool isValidMetadataExtensions, int? id) private Shared.Models.Property GetImageProperty(FileHolder fileHolder, Shared.Models.Property? property, bool populateId, bool isIgnoreExtension, bool isValidImageFormatExtension, bool isValidMetadataExtensions, int? id)
{ {
Shared.Models.Property result; Shared.Models.Property result;
@ -90,7 +116,7 @@ public class A_Property
if (!isValidImageFormatExtension && isValidMetadataExtensions && fileHolder.Exists) if (!isValidImageFormatExtension && isValidMetadataExtensions && fileHolder.Exists)
{ {
dateTimeFormat = "ddd MMM dd HH:mm:ss yyyy"; dateTimeFormat = "ddd MMM dd HH:mm:ss yyyy";
List<DateTime> dateTimes = Shared.Models.Stateless.Methods.IProperty.GetMetadataDateTimesByPattern(dateTimeFormat, fileHolder); List<DateTime> dateTimes = GetMetadataDateTimesByPattern(dateTimeFormat, fileHolder);
if (dateTimes.Any()) if (dateTimes.Any())
dateTimeOriginal = dateTimes.Min(); dateTimeOriginal = dateTimes.Min();
} }

View File

@ -0,0 +1,6 @@
using System.Drawing;
namespace View_by_Distance.Shared.Models;
public record LocationContainer<T>(bool FromDistanceContent, string File, int NormalizedRectangle, IReadOnlyList<T> Directories, Rectangle? Rectangle, Location? Location)
{ }

View File

@ -5,6 +5,16 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods;
public interface ILocation public interface ILocation
{ // ... { // ...
Models.Location? TestStatic_GetLocation(int height, Rectangle rectangle, int width) =>
GetLocation(height, rectangle, width);
static Models.Location? GetLocation(int height, Rectangle rectangle, int width) =>
Location.GetLocation(height, rectangle, width);
List<Models.Face> TestStatic_FilterByIntersect(Models.Face[] faces, int normalizedRectangle) =>
FilterByIntersect(faces, normalizedRectangle);
static List<Models.Face> FilterByIntersect(Models.Face[] faces, int normalizedRectangle) =>
Location.FilterByIntersect(faces, normalizedRectangle);
Rectangle? TestStatic_GetRectangle(Models.OutputResolution outputResolution, DatabaseFile databaseFile, Marker marker) => Rectangle? TestStatic_GetRectangle(Models.OutputResolution outputResolution, DatabaseFile databaseFile, Marker marker) =>
GetRectangle(outputResolution, databaseFile, marker); GetRectangle(outputResolution, databaseFile, marker);
static Rectangle? GetRectangle(Models.OutputResolution outputResolution, DatabaseFile databaseFile, Marker marker) => static Rectangle? GetRectangle(Models.OutputResolution outputResolution, DatabaseFile databaseFile, Marker marker) =>
@ -15,15 +25,20 @@ public interface ILocation
static Models.Location? GetLocation(Models.OutputResolution outputResolution, DatabaseFile databaseFile, Marker marker) => static Models.Location? GetLocation(Models.OutputResolution outputResolution, DatabaseFile databaseFile, Marker marker) =>
Location.GetLocation(outputResolution, databaseFile, marker); Location.GetLocation(outputResolution, databaseFile, marker);
List<Models.Location> TestStatic_GetLocations(List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, List<Models.Face> faces) => List<Models.Location> TestStatic_GetLocations<T>(List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, List<Models.Face> faces, List<LocationContainer<T>> containers) =>
GetLocations(mappingFromPhotoPrismCollection, faces); GetLocations(mappingFromPhotoPrismCollection, faces, containers);
static List<Models.Location> GetLocations(List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, List<Models.Face> faces) => static List<Models.Location> GetLocations<T>(List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, List<Models.Face> faces, List<LocationContainer<T>> containers) =>
Location.GetLocations(mappingFromPhotoPrismCollection, faces); Location.GetLocations(mappingFromPhotoPrismCollection, faces, containers);
Rectangle TestStatic_GetRectangle(Rectangle checkRectangle, int locationDigits, int locationFactor, int normalizedRectangle, Models.OutputResolution outputResolution, bool useOldWay) => Rectangle? TestStatic_GetRectangle(Rectangle checkRectangle, int locationDigits, int locationFactor, int normalizedRectangle, Models.OutputResolution outputResolution, bool useOldWay) =>
GetRectangle(checkRectangle, locationDigits, locationFactor, normalizedRectangle, outputResolution, useOldWay); GetRectangle(checkRectangle, locationDigits, locationFactor, normalizedRectangle, outputResolution, useOldWay);
static Rectangle GetRectangle(Rectangle checkRectangle, int locationDigits, int locationFactor, int normalizedRectangle, Models.OutputResolution outputResolution, bool useOldWay) => static Rectangle? GetRectangle(Rectangle checkRectangle, int locationDigits, int locationFactor, int normalizedRectangle, Models.OutputResolution outputResolution, bool useOldWay) =>
Location.GetRectangle(checkRectangle, locationDigits, locationFactor, normalizedRectangle, OutputResolution.Get(outputResolution).Height, OutputResolution.Get(outputResolution).Width, useOldWay); Location.GetRectangle(checkRectangle, OutputResolution.Get(outputResolution).Height, locationDigits, locationFactor, normalizedRectangle.ToString(), OutputResolution.Get(outputResolution).Width, useOldWay);
Rectangle? TestStatic_GetRectangle(int height, int locationDigits, int locationFactor, int normalizedRectangle, int outputResolutionHeight, int outputResolutionWidth, int width) =>
GetRectangle(height, locationDigits, locationFactor, normalizedRectangle, outputResolutionHeight, outputResolutionWidth, width);
static Rectangle? GetRectangle(int height, int locationDigits, int locationFactor, int normalizedRectangle, int outputResolutionHeight, int outputResolutionWidth, int width) =>
Location.GetRectangle(height, locationDigits, locationFactor, normalizedRectangle.ToString(), outputResolutionHeight, outputResolutionWidth, width);
string TestStatic_GetLeftPadded(int locationDigits, string value) => string TestStatic_GetLeftPadded(int locationDigits, string value) =>
GetLeftPadded(locationDigits, value); GetLeftPadded(locationDigits, value);

View File

@ -11,11 +11,6 @@ public interface IProperty
static int GetDeterministicHashCode(byte[] value) => static int GetDeterministicHashCode(byte[] value) =>
Property.GetDeterministicHashCode(value); Property.GetDeterministicHashCode(value);
List<DateTime> TestStatic_GetMetadataDateTimesByPattern(string dateTimeFormat, Models.FileHolder fileHolder) =>
GetMetadataDateTimesByPattern(dateTimeFormat, fileHolder);
static List<DateTime> GetMetadataDateTimesByPattern(string dateTimeFormat, Models.FileHolder fileHolder) =>
Property.GetMetadataDateTimesByPattern(dateTimeFormat, fileHolder.FullName);
int TestStatic_GetDeterministicHashCode(string value) => int TestStatic_GetDeterministicHashCode(string value) =>
GetDeterministicHashCode(value); GetDeterministicHashCode(value);
static int GetDeterministicHashCode(string value) => static int GetDeterministicHashCode(string value) =>

View File

@ -167,26 +167,43 @@ internal abstract class Location
return result; return result;
} }
internal static Rectangle GetRectangle(Rectangle checkRectangle, int locationDigits, int locationFactor, int normalizedRectangleValue, int height, int width, bool useOldWay) internal static Rectangle? GetRectangle(Rectangle checkRectangle, int height, int locationDigits, int locationFactor, string normalizedRectangle, int width, bool useOldWay)
{ {
Rectangle? result; Rectangle? result;
string normalizedRectangle = normalizedRectangleValue.ToString(); if (useOldWay)
if (normalizedRectangle.Length != locationDigits)
throw new NotImplementedException();
if (!useOldWay)
{
result = GetRectangle(locationDigits, height, normalizedRectangle, width);
if (result is null)
throw new NullReferenceException(nameof(result));
}
else
{ {
(int? x, int? y) = GetXY(locationDigits, locationFactor, width, height, normalizedRectangle); (int? x, int? y) = GetXY(locationDigits, locationFactor, width, height, normalizedRectangle);
if (x is null || y is null) if (x is null || y is null)
throw new Exception(); throw new Exception();
result = new(x.Value - (checkRectangle.Width / 2), y.Value - (checkRectangle.Height / 2), checkRectangle.Width, checkRectangle.Height); result = new(x.Value - (checkRectangle.Width / 2), y.Value - (checkRectangle.Height / 2), checkRectangle.Width, checkRectangle.Height);
} }
return result.Value; else
{
if (normalizedRectangle.Length != locationDigits)
result = null;
else
{
result = GetRectangle(locationDigits, height, normalizedRectangle, width);
if (result is null)
throw new NullReferenceException(nameof(result));
}
}
return result;
}
internal static Rectangle? GetRectangle(int height, int locationDigits, int locationFactor, string normalizedRectangle, int outputResolutionHeight, int outputResolutionWidth, int width)
{
Rectangle? result;
if (normalizedRectangle.Length == locationDigits && normalizedRectangle[0] is '4' or '8')
result = GetRectangle(locationDigits, outputResolutionHeight, normalizedRectangle, outputResolutionWidth);
else
{
(int? x, int? y) = GetXY(locationDigits, locationFactor, outputResolutionWidth, outputResolutionHeight, normalizedRectangle);
if (x is null || y is null)
throw new Exception();
result = new(x.Value - (width / 2), y.Value - (height / 2), width, height);
}
return result;
} }
private static bool Matches(Models.OutputResolution outputResolution, DatabaseFile databaseFile) private static bool Matches(Models.OutputResolution outputResolution, DatabaseFile databaseFile)
@ -217,6 +234,18 @@ internal abstract class Location
return result; return result;
} }
internal static Models.Location? GetLocation(int height, Rectangle rectangle, int width)
{
Models.Location? result;
double confidence = 0;
bool verified = Check(rectangle.Bottom, height, rectangle.Left, rectangle.Right, rectangle.Top, width, zCount: 1, throwException: false);
if (!verified)
result = null;
else
result = new(rectangle.Bottom, confidence, rectangle.Left, rectangle.Right, rectangle.Top);
return result;
}
internal static Models.Location? GetLocation(Models.OutputResolution outputResolution, DatabaseFile databaseFile, Marker marker) internal static Models.Location? GetLocation(Models.OutputResolution outputResolution, DatabaseFile databaseFile, Marker marker)
{ {
Models.Location? result; Models.Location? result;
@ -228,7 +257,7 @@ internal abstract class Location
return result; return result;
} }
internal static List<Models.Location> GetLocations(List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, List<Models.Face> faces) internal static List<Models.Location> GetLocations<T>(List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, List<Models.Face> faces, List<LocationContainer<T>> containers)
{ {
List<Models.Location> results = new(); List<Models.Location> results = new();
bool any; bool any;
@ -246,6 +275,12 @@ internal abstract class Location
outputResolution ??= face.OutputResolution; outputResolution ??= face.OutputResolution;
} }
int before = results.Count; int before = results.Count;
foreach (LocationContainer<T> locationContainer in containers)
{
if (locationContainer.Location is null)
continue;
results.Add(locationContainer.Location);
}
foreach (MappingFromPhotoPrism mappingFromPhotoPrism in mappingFromPhotoPrismCollection) foreach (MappingFromPhotoPrism mappingFromPhotoPrism in mappingFromPhotoPrismCollection)
{ {
if (outputResolution is null) if (outputResolution is null)
@ -262,12 +297,27 @@ internal abstract class Location
location = GetLocation(mappingFromPhotoPrism.DatabaseFile, marker, prismRectangle.Value); location = GetLocation(mappingFromPhotoPrism.DatabaseFile, marker, prismRectangle.Value);
if (location is null) if (location is null)
break; break;
foreach (LocationContainer<T> locationContainer in containers)
{
if (any)
continue;
if (locationContainer.Location is null)
continue;
dlibRectangle = new(locationContainer.Location.Left, locationContainer.Location.Top, locationContainer.Location.Right - locationContainer.Location.Left, locationContainer.Location.Bottom - locationContainer.Location.Top);
intersectRectangle = Rectangle.Intersect(prismRectangle.Value, dlibRectangle);
if (intersectRectangle.Width == 0 && intersectRectangle.Height == 0)
continue;
any = true;
break;
}
foreach (Models.Face face in faces) foreach (Models.Face face in faces)
{ {
if (any)
continue;
if (face.Location is null || face.OutputResolution is null) if (face.Location is null || face.OutputResolution is null)
continue; continue;
dlibRectangle = new(face.Location.Left, face.Location.Top, face.Location.Right - face.Location.Left, face.Location.Bottom - face.Location.Top); dlibRectangle = new(face.Location.Left, face.Location.Top, face.Location.Right - face.Location.Left, face.Location.Bottom - face.Location.Top);
intersectRectangle = Rectangle.Intersect(dlibRectangle, prismRectangle.Value); intersectRectangle = Rectangle.Intersect(prismRectangle.Value, dlibRectangle);
if (intersectRectangle.Width == 0 && intersectRectangle.Height == 0) if (intersectRectangle.Width == 0 && intersectRectangle.Height == 0)
continue; continue;
any = true; any = true;
@ -282,4 +332,35 @@ internal abstract class Location
return results; return results;
} }
internal static List<Models.Face> FilterByIntersect(Models.Face[] faces, int normalizedRectangle)
{
List<Models.Face> results = new();
bool useOldWay;
double? percent;
Rectangle checkRectangle;
Rectangle? sourceRectangle;
Rectangle intersectRectangle;
foreach (Models.Face face in faces)
{
if (face.Location is null || face.OutputResolution is null)
continue;
checkRectangle = new(face.Location.Left, face.Location.Top, face.Location.Right - face.Location.Left, face.Location.Bottom - face.Location.Top);
for (int i = 1; i < 3; i++)
{
useOldWay = i == 1;
sourceRectangle = ILocation.GetRectangle(checkRectangle, Stateless.ILocation.Digits, Stateless.ILocation.Factor, normalizedRectangle, face.OutputResolution, useOldWay);
if (sourceRectangle is null)
continue;
intersectRectangle = Rectangle.Intersect(checkRectangle, sourceRectangle.Value);
if (intersectRectangle.Width == 0 || intersectRectangle.Height == 0)
continue;
percent = (double)intersectRectangle.Width * intersectRectangle.Height / (checkRectangle.Width * checkRectangle.Height);
if (percent < 0.000001)
continue;
results.Add(face);
}
}
return results;
}
} }

View File

@ -343,32 +343,6 @@ internal abstract class Property
return result; return result;
} }
internal static List<DateTime> GetMetadataDateTimesByPattern(string dateTimeFormat, string sourceDirectoryFile)
{
List<DateTime> results = new();
try
{
DateTime checkDateTime;
DateTime kristy = new(1976, 3, 8);
IReadOnlyList<MetadataExtractor.Directory> directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(sourceDirectoryFile);
foreach (MetadataExtractor.Directory directory in directories)
{
foreach (MetadataExtractor.Tag tag in directory.Tags)
{
if (string.IsNullOrEmpty(tag.Description) || tag.Description.Length != dateTimeFormat.Length)
continue;
if (!DateTime.TryParseExact(tag.Description, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime))
continue;
if (checkDateTime < kristy)
continue;
results.Add(checkDateTime);
}
}
}
catch (Exception) { }
return results;
}
#pragma warning disable CA1416 #pragma warning disable CA1416
internal static (DateTime?, int?, string?) Get(Models.FileHolder fileHolder) internal static (DateTime?, int?, string?) Get(Models.FileHolder fileHolder)

View File

@ -35,6 +35,5 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="7.0.0" /> <PackageReference Include="System.Drawing.Common" Version="7.0.0" />
<PackageReference Include="System.Text.Json" Version="7.0.1" /> <PackageReference Include="System.Text.Json" Version="7.0.1" />
<PackageReference Include="MetadataExtractor" Version="2.7.2" />
</ItemGroup> </ItemGroup>
</Project> </Project>