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;
}
private void MoveUnableToMatch(string eDistanceContentDirectory, string file, string fileName)
private static void MoveUnableToMatch(string file)
{
bool check;
string? directoryName = Path.GetDirectoryName(file);
if (fileName is null || directoryName is null)
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);
string checkFile = string.Concat(file, ".unk");
if (File.Exists(file) && !File.Exists(checkFile))
File.Move(file, checkFile);
}
private FaceDistanceContainer[] GetFaceDistanceContainers(MappingFromItem mappingFromItem, List<Face> filteredFaces)
private FaceDistanceContainer[] GetFaceDistanceContainers(MappingFromItem mappingFromItem, List<Face> intersectFaces)
{
FaceDistanceContainer[] results;
int confidencePercent;
@ -92,7 +53,7 @@ public partial class E_Distance
FaceDistance faceDistance;
FaceDistanceContainer faceDistanceContainer;
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)
throw new NotSupportedException();
@ -104,7 +65,7 @@ public partial class E_Distance
{
faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding);
faceDistance = new(confidencePercent, faceEncoding, mappingFromItem.Id, mappingFromItem.IsWrongYear, mappingFromItem.MinimumDateTime, normalizedRectangle);
lock (filteredFaces)
lock (intersectFaces)
face.SetFaceDistance(faceDistance);
}
faceDistanceContainer = new(face, faceDistance);
@ -126,42 +87,38 @@ public partial class E_Distance
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();
Face face;
FaceDistance faceDistanceLength;
List<Face> filteredFaces = FilterByIntersect(faces, normalizedRectangle);
if (filteredFaces.Any())
{
FaceRecognitionDotNet.FaceEncoding faceRecognitionDotNetFaceEncoding = FaceRecognition.LoadFaceEncoding(modelsFaceEncoding.RawEncoding);
FaceDistance faceDistanceEncoding = new(faceRecognitionDotNetFaceEncoding);
FaceDistanceContainer[] faceDistanceContainers = GetFaceDistanceContainers(mappingFromItem, filteredFaces);
FaceDistanceContainer[] faceDistanceContainers = GetFaceDistanceContainers(mappingFromItem, intersectFaces);
int faceDistanceContainersLength = faceDistanceContainers.Length;
if (faceDistanceContainersLength != filteredFaces.Count)
if (faceDistanceContainersLength != intersectFaces.Count)
throw new NotSupportedException();
List<FaceDistance> faceDistanceEncodings = GetFaceDistanceEncodings(faceDistanceContainers);
if (faceDistanceEncodings.Count != filteredFaces.Count)
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 < filteredFaces.Count; i++)
for (int i = 0; i < intersectFaces.Count; i++)
{
face = filteredFaces[i];
face = intersectFaces[i];
faceDistanceLength = faceDistanceLengths[i];
if (faceDistanceLength.Length is null)
throw new NotSupportedException();
results.Add(new(face, faceDistanceLength.Length.Value));
}
}
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;
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();
if (results.Any())
{
@ -240,69 +197,40 @@ public partial class E_Distance
}
}
private static List<Face> FilterByIntersect(Face[] faces, int normalizedRectangle)
{
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)
public void LookForMatchFacesAndPossiblyRename(string facesFileNameExtension, string eDistanceContentDirectory, MappingFromItem mappingFromItem, List<Face> faces, List<LocationContainer<MetadataExtractor.Directory>> collection)
{
string? json;
string fileName;
string[] matches;
FileInfo? fileInfo;
List<Face> intersectFaces;
List<(Face, double?)> checkFaces = new();
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();
if (filteredFaces.Length != faces.Count)
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())
break;
if (_Renamed.Contains(file))
if (_Renamed.Contains(locationContainer.File))
continue;
fileName = Path.GetFileName(file);
if (fromDistanceContent && _DuplicateMappedFaceFiles.Contains(fileName))
fileName = Path.GetFileName(locationContainer.File);
if (locationContainer.FromDistanceContent && _DuplicateMappedFaceFiles.Contains(fileName))
continue;
checkFaces.Clear();
if (directories is null)
if (!locationContainer.Directories.Any())
{
if (fromDistanceContent)
throw new NullReferenceException(nameof(directories));
if (locationContainer.FromDistanceContent)
throw new NullReferenceException(nameof(locationContainer.Directories));
continue;
}
json = Metadata.Models.Stateless.IMetadata.GetFaceEncoding(directories);
json = Metadata.Models.Stateless.IMetadata.GetFaceEncoding(locationContainer.Directories);
if (json is null)
{
if (_DistanceMoveUnableToMatch)
MoveUnableToMatch(eDistanceContentDirectory, file, fileName);
MoveUnableToMatch(locationContainer.File);
continue;
}
if (filteredFaces.Any())
checkFaces.AddRange(GetMatchingFacesByFaceEncoding(filteredFaces, json));
if (checkFaces.Count == 1)
_Debug.Add(0);
@ -312,44 +240,49 @@ public partial class E_Distance
modelsFaceEncoding = JsonSerializer.Deserialize<Shared.Models.FaceEncoding>(json);
if (modelsFaceEncoding is null)
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 (_DistanceMoveUnableToMatch)
MoveUnableToMatch(eDistanceContentDirectory, file, fileName);
MoveUnableToMatch(locationContainer.File);
continue;
}
if (checkFaces.Count != 1)
{
if (_DistanceMoveUnableToMatch)
MoveUnableToMatch(eDistanceContentDirectory, file, fileName);
MoveUnableToMatch(locationContainer.File);
continue;
}
fileInfo = CheckFileThenGetFileInfo(facesFileNameExtension, mappingFromItem, file, checkFaces);
fileInfo = CheckFileThenGetFileInfo(facesFileNameExtension, mappingFromItem, locationContainer.File, checkFaces);
if (fileInfo is not null)
{
if (_DistanceRenameToMatch && fileInfo is not null)
{
if (fileInfo.Exists)
File.Delete(file);
File.Delete(locationContainer.File);
else
File.Move(file, fileInfo.FullName);
_Renamed.Add(file);
File.Move(locationContainer.File, fileInfo.FullName);
_Renamed.Add(locationContainer.File);
}
continue;
}
if (_AllMappedFaceFileNames.Contains(fileName))
{
lock (_AllMappedFaceFiles)
matches = (from l in _AllMappedFaceFiles where l != file && Path.GetFileName(l) == fileName select l).ToArray();
if (fromDistanceContent && matches.Any())
AppendMatchingDuplicates(file, matches);
matches = (from l in _AllMappedFaceFiles where l != locationContainer.File && Path.GetFileName(l) == fileName select l).ToArray();
if (locationContainer.FromDistanceContent && matches.Any())
AppendMatchingDuplicates(locationContainer.File, matches);
}
if (!fromDistanceContent)
if (!locationContainer.FromDistanceContent)
continue;
lock (_AllMappedFaceFiles)
_AllMappedFaceFiles.Add(file);
_AllMappedFaceFiles.Add(locationContainer.File);
lock (_AllMappedFaceFileNames)
_AllMappedFaceFileNames.Add(fileName);
}

View File

@ -140,6 +140,12 @@ public class D_Face
#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)
{
PropertyItem result = (PropertyItem)_ConstructorInfo.Invoke(null);
@ -291,12 +297,60 @@ public class D_Face
#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;
if (string.IsNullOrEmpty(dResultsFullGroupDirectory))
throw new NullReferenceException(nameof(dResultsFullGroupDirectory));
string json;
string? json;
List<Location>? locations;
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();
@ -334,10 +388,15 @@ public class D_Face
parseExceptions.Add(nameof(D_Face));
}
}
if (mappingFromPhotoPrismCollection is null || results is null)
locations = null;
List<LocationContainer<MetadataExtractor.Directory>> containers;
if (results is null || collection is null)
containers = new();
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()))
{
results = GetFaces(property, mappingFromItem, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, locations);

View File

@ -283,7 +283,7 @@ public partial class DlibDotNet
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)
throw new NullReferenceException(nameof(_Log));
@ -369,10 +369,14 @@ public partial class DlibDotNet
int outputResolutionHeight = outputResolutionCollection[1];
int outputResolutionOrientation = outputResolutionCollection[2];
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))
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)
ticks = LogDelta(ticks, nameof(D_Face.GetFaces));
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));
if ((_Configuration.DistanceMoveUnableToMatch || _Configuration.DistanceRenameToMatch)
&& _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution)
&& !anyFacesSaved && item.Property?.Id is not null
&& idToMappedFaceFilesWithCollection.TryGetValue(item.Property.Id.Value, out collection))
&& !anyFacesSaved && collection is not null)
_Distance.LookForMatchFacesAndPossiblyRename(_Faces.FileNameExtension, eDistanceContentDirectory, mappingFromItem, faces, collection);
if (_Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution))
{
@ -405,7 +408,7 @@ public partial class DlibDotNet
private int FullParallelWork(int maxDegreeOfParallelism,
A_Property propertyLogic,
Dictionary<int, List<(bool, string, int, IReadOnlyList<MetadataExtractor.Directory>?)>> idToMappedFaceFilesWithCollection,
Dictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> idToMappedFaceFilesWithCollection,
string outputResolution,
string bResultsFullGroupDirectory,
string cResultsFullGroupDirectory,
@ -658,7 +661,7 @@ public partial class DlibDotNet
int maxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism;
List<Shared.Models.Property?> nullablePropertyCollection = 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));
foreach (string outputResolution in _Configuration.OutputResolutions)
{
@ -874,7 +877,7 @@ public partial class DlibDotNet
List<Item> filteredItems = GetItems(argZero, containers);
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);
Dictionary<int, Dictionary<int, Mapping>> idToNormalizedRectangleToMapping = MapLogicSupport.GetIdToNormalizedRectangleToFace(mappingCollection);
mapLogic.CopyManualFiles(dFacesContentDirectory, idToNormalizedRectangleToMapping);
@ -1008,11 +1011,11 @@ public partial class DlibDotNet
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";
int? id, normalizedRectangle;
IReadOnlyList<MetadataExtractor.Directory>? directories;
IReadOnlyList<MetadataExtractor.Directory> directories;
bool fromDistanceContent = !file.EndsWith(lnk) && file.Contains(eDistanceContentDirectory);
if (!file.EndsWith(lnk))
(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)
return;
if (file.EndsWith(lnk) || (!_Configuration.DistanceMoveUnableToMatch && !_Configuration.DistanceRenameToMatch))
directories = null;
directories = new List<MetadataExtractor.Directory>();
else
directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(file);
lock (collection)
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<(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.DeleteEmptyDirectoriesAndGetMappedFaceFiles(_MapConfiguration, _PersonContainers, ticks, a2PeopleContentDirectory, eDistanceContentDirectory));
// foreach (string file in files)
// {
// if (!file.EndsWith(".dup"))
// continue;
// if (!File.Exists(file))
// continue;
// File.Move(file, file[..^4]);
// }
if (files.Any() && (_Configuration.DistanceMoveUnableToMatch || _Configuration.DistanceRenameToMatch))
for (int i = 0; i < files.Count; i++)
{
file = files[i];
if (!file.EndsWith(".dup") && !file.EndsWith(".unk"))
continue;
if (!File.Exists(file))
continue;
File.Move(file, file[..^4]);
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);
string message = $") Building Mapped Face Files Collection - {totalSeconds} total second(s)";
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism };
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
using ProgressBar progressBar = new(files.Count, message, options);
_ = Parallel.For(0, files.Count, parallelOptions, (i, state) =>
using ProgressBar progressBar = new(distictFiles.Length, message, options);
_ = Parallel.For(0, distictFiles.Length, parallelOptions, (i, state) =>
{
progressBar.Tick();
ParallelFor(eDistanceContentDirectory, results, files[i]);
ParallelFor(eDistanceContentDirectory, results, distictFiles[i]);
});
}
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();
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)
Dictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> results = new();
LocationContainer<MetadataExtractor.Directory> noob;
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))
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;
}

View File

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

View File

@ -233,7 +233,7 @@ internal abstract class MapLogic
if (!string.IsNullOrEmpty(a2PeopleContentDirectory))
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);
foreach ((string personKeyFormatted, string[] personDisplayDirectoryNames, string mappedFaceFile) in collection)
foreach ((_, _, string mappedFaceFile) in collection)
results.Add(mappedFaceFile);
return results;
}

View File

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

View File

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

View File

@ -64,6 +64,32 @@ public class A_Property
#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)
{
Shared.Models.Property result;
@ -90,7 +116,7 @@ public class A_Property
if (!isValidImageFormatExtension && isValidMetadataExtensions && fileHolder.Exists)
{
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())
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
{ // ...
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) =>
GetRectangle(outputResolution, databaseFile, 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) =>
Location.GetLocation(outputResolution, databaseFile, marker);
List<Models.Location> TestStatic_GetLocations(List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, List<Models.Face> faces) =>
GetLocations(mappingFromPhotoPrismCollection, faces);
static List<Models.Location> GetLocations(List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, List<Models.Face> faces) =>
Location.GetLocations(mappingFromPhotoPrismCollection, faces);
List<Models.Location> TestStatic_GetLocations<T>(List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, List<Models.Face> faces, List<LocationContainer<T>> containers) =>
GetLocations(mappingFromPhotoPrismCollection, faces, containers);
static List<Models.Location> GetLocations<T>(List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, List<Models.Face> faces, List<LocationContainer<T>> containers) =>
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);
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);
static Rectangle? GetRectangle(Rectangle checkRectangle, int locationDigits, int locationFactor, int normalizedRectangle, Models.OutputResolution outputResolution, bool 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) =>
GetLeftPadded(locationDigits, value);

View File

@ -11,11 +11,6 @@ public interface IProperty
static int GetDeterministicHashCode(byte[] 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) =>
GetDeterministicHashCode(value);
static int GetDeterministicHashCode(string value) =>

View File

@ -167,26 +167,43 @@ internal abstract class Location
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;
string normalizedRectangle = normalizedRectangleValue.ToString();
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
if (useOldWay)
{
(int? x, int? y) = GetXY(locationDigits, locationFactor, width, height, normalizedRectangle);
if (x is null || y is null)
throw new Exception();
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)
@ -217,6 +234,18 @@ internal abstract class Location
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)
{
Models.Location? result;
@ -228,7 +257,7 @@ internal abstract class Location
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();
bool any;
@ -246,6 +275,12 @@ internal abstract class Location
outputResolution ??= face.OutputResolution;
}
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)
{
if (outputResolution is null)
@ -262,12 +297,27 @@ internal abstract class Location
location = GetLocation(mappingFromPhotoPrism.DatabaseFile, marker, prismRectangle.Value);
if (location is null)
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)
{
if (any)
continue;
if (face.Location is null || face.OutputResolution is null)
continue;
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)
continue;
any = true;
@ -282,4 +332,35 @@ internal abstract class Location
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;
}
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
internal static (DateTime?, int?, string?) Get(Models.FileHolder fileHolder)

View File

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