ReSaveFace
Removed GetLocationContainers Split SetCreationTime and MoveToDecade GetFilteredDistinctFileNameFirstSegments instead of GetFilteredDistinctIds for some void Tick(); FaceFile
This commit is contained in:
parent
9a772f8dcc
commit
7f8b09e66c
10
.vscode/tasks.json
vendored
10
.vscode/tasks.json
vendored
@ -42,6 +42,16 @@
|
|||||||
],
|
],
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label": "Format-Whitespaces",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"format",
|
||||||
|
"whitespace"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "build",
|
"label": "build",
|
||||||
"command": "dotnet",
|
"command": "dotnet",
|
||||||
|
@ -205,14 +205,14 @@ public partial class E_Distance : IDistance
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LookForMatchFacesAndPossiblyRename(IDistanceLimits distanceLimits, string facesFileNameExtension, FilePath filePath, MappingFromItem mappingFromItem, List<Face> faces, ReadOnlyCollection<LocationContainer> locationContainers)
|
public void LookForMatchFacesAndPossiblyRename(IDistanceLimits distanceLimits, Shared.Models.Stateless.Methods.IFaceD dFace, FilePath filePath, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Face> faces, ReadOnlyCollection<LocationContainer> locationContainers)
|
||||||
{
|
{
|
||||||
string? json;
|
string? json;
|
||||||
string[] matches;
|
string[] matches;
|
||||||
FileInfo? fileInfo;
|
FileInfo? fileInfo;
|
||||||
List<Face> intersectFaces;
|
List<Face> intersectFaces;
|
||||||
List<(Face, double?)> checkFaces = [];
|
|
||||||
Shared.Models.FaceEncoding? modelsFaceEncoding;
|
Shared.Models.FaceEncoding? modelsFaceEncoding;
|
||||||
|
List<(Face Face, double? Distance)> checkFaces = [];
|
||||||
Face[] filteredFaces = (from l in faces where l.FaceEncoding is not null && l.Location is not null && l.OutputResolution is not null select l).ToArray();
|
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();
|
||||||
@ -265,7 +265,7 @@ public partial class E_Distance : IDistance
|
|||||||
MoveUnableToMatch(locationContainer.FilePath);
|
MoveUnableToMatch(locationContainer.FilePath);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
fileInfo = CheckFileThenGetFileInfo(facesFileNameExtension, filePath, mappingFromItem, locationContainer.FilePath.FullName, checkFaces);
|
fileInfo = CheckFileThenGetFileInfo(dFace.FileNameExtension, filePath, mappingFromItem, locationContainer.FilePath.FullName, checkFaces);
|
||||||
if (fileInfo is not null)
|
if (fileInfo is not null)
|
||||||
{
|
{
|
||||||
if (_DistanceRenameToMatch && fileInfo is not null)
|
if (_DistanceRenameToMatch && fileInfo is not null)
|
||||||
@ -279,6 +279,12 @@ public partial class E_Distance : IDistance
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (checkFaces.Count == 1)
|
||||||
|
{
|
||||||
|
json = Metadata.Models.Stateless.Methods.IMetadata.GetOutputResolution(locationContainer.ExifDirectory);
|
||||||
|
if (json is null || json.Contains(nameof(DateTime)))
|
||||||
|
dFace.ReSaveFace(exifDirectory, locationContainer, checkFaces[0].Face);
|
||||||
|
}
|
||||||
if (_AllMappedFaceFileNames.Contains(locationContainer.FilePath.Name))
|
if (_AllMappedFaceFileNames.Contains(locationContainer.FilePath.Name))
|
||||||
{
|
{
|
||||||
lock (_AllMappedFaceFiles)
|
lock (_AllMappedFaceFiles)
|
||||||
|
@ -7,18 +7,18 @@ using System.Text.Json.Serialization;
|
|||||||
using View_by_Distance.FaceRecognitionDotNet;
|
using View_by_Distance.FaceRecognitionDotNet;
|
||||||
using View_by_Distance.Metadata.Models;
|
using View_by_Distance.Metadata.Models;
|
||||||
using View_by_Distance.Property.Models;
|
using View_by_Distance.Property.Models;
|
||||||
using View_by_Distance.Property.Models.Stateless;
|
|
||||||
using View_by_Distance.Resize.Models;
|
using View_by_Distance.Resize.Models;
|
||||||
using View_by_Distance.Shared.Models;
|
using View_by_Distance.Shared.Models;
|
||||||
using View_by_Distance.Shared.Models.Properties;
|
using View_by_Distance.Shared.Models.Properties;
|
||||||
using View_by_Distance.Shared.Models.Stateless;
|
using View_by_Distance.Shared.Models.Stateless;
|
||||||
|
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
namespace View_by_Distance.Face.Models;
|
namespace View_by_Distance.Face.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
// List<D_Faces>
|
// List<D_Faces>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class D_Face
|
public class D_Face : IFaceD
|
||||||
{
|
{
|
||||||
|
|
||||||
protected readonly string _FileNameExtension;
|
protected readonly string _FileNameExtension;
|
||||||
@ -149,22 +149,21 @@ public class D_Face
|
|||||||
|
|
||||||
#pragma warning disable CA1416
|
#pragma warning disable CA1416
|
||||||
|
|
||||||
private void SaveFaces(FileHolder resizedFileHolder, List<(Shared.Models.Face, FileInfo?, string, bool)> collection)
|
private void SaveFaces(FileHolder resizedFileHolder, MetadataExtractor.GeoLocation? geoLocation, string? maker, string? model, List<(Shared.Models.Face, FileInfo?, string, bool)> collection)
|
||||||
{
|
{
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
Bitmap bitmap;
|
Bitmap bitmap;
|
||||||
short type = 2;
|
short type = 2;
|
||||||
|
FaceFile faceFile;
|
||||||
Graphics graphics;
|
Graphics graphics;
|
||||||
Location? location;
|
Location? location;
|
||||||
Rectangle rectangle;
|
Rectangle rectangle;
|
||||||
string locationJson;
|
string faceFileJson;
|
||||||
string faceEncodingJson;
|
string faceEncodingJson;
|
||||||
PropertyItem? propertyItem;
|
PropertyItem? propertyItem;
|
||||||
string outputResolutionJson;
|
|
||||||
using Bitmap source = new(resizedFileHolder.FullName);
|
using Bitmap source = new(resizedFileHolder.FullName);
|
||||||
int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist;
|
int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist;
|
||||||
int fileSource = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagFileSource;
|
|
||||||
int userComment = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagUserComment;
|
int userComment = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagUserComment;
|
||||||
foreach ((Shared.Models.Face face, FileInfo? fileInfo, string fileName, bool save) in collection)
|
foreach ((Shared.Models.Face face, FileInfo? fileInfo, string fileName, bool save) in collection)
|
||||||
{
|
{
|
||||||
@ -179,19 +178,17 @@ public class D_Face
|
|||||||
continue;
|
continue;
|
||||||
width = location.Right - location.Left;
|
width = location.Right - location.Left;
|
||||||
height = location.Bottom - location.Top;
|
height = location.Bottom - location.Top;
|
||||||
locationJson = JsonSerializer.Serialize(face.Location);
|
|
||||||
faceEncodingJson = JsonSerializer.Serialize(face.FaceEncoding);
|
faceEncodingJson = JsonSerializer.Serialize(face.FaceEncoding);
|
||||||
outputResolutionJson = JsonSerializer.Serialize(face.OutputResolution);
|
|
||||||
rectangle = new Rectangle(location.Left, location.Top, width, height);
|
rectangle = new Rectangle(location.Left, location.Top, width, height);
|
||||||
|
faceFile = new(face.DateTime, geoLocation?.ToDmsString(), face.FaceParts, face.Location, maker, model, face.OutputResolution);
|
||||||
|
faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
|
||||||
using (bitmap = new(width, height))
|
using (bitmap = new(width, height))
|
||||||
{
|
{
|
||||||
using (graphics = Graphics.FromImage(bitmap))
|
using (graphics = Graphics.FromImage(bitmap))
|
||||||
graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel);
|
graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel);
|
||||||
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, fileSource, type, locationJson);
|
propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(_ConstructorInfo, artist, type, faceFileJson);
|
||||||
bitmap.SetPropertyItem(propertyItem);
|
bitmap.SetPropertyItem(propertyItem);
|
||||||
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, artist, type, outputResolutionJson);
|
propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(_ConstructorInfo, userComment, type, faceEncodingJson);
|
||||||
bitmap.SetPropertyItem(propertyItem);
|
|
||||||
propertyItem = IProperty.GetPropertyItem(_ConstructorInfo, userComment, type, faceEncodingJson);
|
|
||||||
bitmap.SetPropertyItem(propertyItem);
|
bitmap.SetPropertyItem(propertyItem);
|
||||||
bitmap.Save(fileInfo.FullName, _ImageCodecInfo, _EncoderParameters);
|
bitmap.Save(fileInfo.FullName, _ImageCodecInfo, _EncoderParameters);
|
||||||
}
|
}
|
||||||
@ -213,7 +210,7 @@ public class D_Face
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Shared.Models.Face> GetFaces(string outputResolution, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<Location>? locations)
|
private List<Shared.Models.Face> GetFaces(string outputResolution, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<Location> locations)
|
||||||
{
|
{
|
||||||
if (_PropertyConfiguration.NumberOfJitters is null)
|
if (_PropertyConfiguration.NumberOfJitters is null)
|
||||||
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfJitters));
|
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfJitters));
|
||||||
@ -260,69 +257,13 @@ public class D_Face
|
|||||||
|
|
||||||
#pragma warning restore CA1416
|
#pragma warning restore CA1416
|
||||||
|
|
||||||
private static List<LocationContainer> GetLocationContainers(string outputResolution, ReadOnlyCollection<LocationContainer> locationContainers, Dictionary<string, int[]> outputResolutionToResize, List<Shared.Models.Face> faces)
|
public List<Shared.Models.Face> GetFaces(string outputResolution, string dResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection)
|
||||||
{
|
|
||||||
List<LocationContainer> results = [];
|
|
||||||
string? json;
|
|
||||||
Location? location;
|
|
||||||
List<int> skip = [];
|
|
||||||
Rectangle? rectangle;
|
|
||||||
OutputResolution? outputResolutionCheck = null;
|
|
||||||
(int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) = Resize.Models.Stateless.Methods.IResize.Get(outputResolution, outputResolutionToResize);
|
|
||||||
foreach (Shared.Models.Face face in faces)
|
|
||||||
{
|
|
||||||
if (face.Location is null || face.OutputResolution is null)
|
|
||||||
continue;
|
|
||||||
skip.Add(Shared.Models.Stateless.Methods.ILocation.GetWholePercentages(face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution));
|
|
||||||
}
|
|
||||||
foreach (LocationContainer locationContainer in locationContainers)
|
|
||||||
{
|
|
||||||
if (locationContainer.ExifDirectory is null)
|
|
||||||
continue;
|
|
||||||
if (skip.Contains(locationContainer.WholePercentages))
|
|
||||||
continue;
|
|
||||||
foreach (Shared.Models.Face face in faces)
|
|
||||||
{
|
|
||||||
if (face.Location is not null && face.OutputResolution is not null)
|
|
||||||
continue;
|
|
||||||
json = Metadata.Models.Stateless.Methods.IMetadata.GetOutputResolution(locationContainer.ExifDirectory);
|
|
||||||
if (json is null)
|
|
||||||
continue;
|
|
||||||
outputResolutionCheck = JsonSerializer.Deserialize<OutputResolution>(json);
|
|
||||||
if (outputResolutionCheck is null || outputResolutionCheck.Width != outputResolutionWidth || outputResolutionCheck.Height != outputResolutionHeight)
|
|
||||||
continue;
|
|
||||||
rectangle = Shared.Models.Stateless.Methods.ILocation.GetRectangle(Shared.Models.Stateless.ILocation.Digits, outputResolutionCheck, locationContainer.WholePercentages);
|
|
||||||
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.WholePercentages == locationContainer.WholePercentages))
|
|
||||||
results.Add(new(locationContainer.CreationDateOnly,
|
|
||||||
locationContainer.ExifDirectory,
|
|
||||||
locationContainer.DirectoryNumber,
|
|
||||||
locationContainer.DisplayDirectoryName,
|
|
||||||
locationContainer.FilePath,
|
|
||||||
locationContainer.FromDistanceContent,
|
|
||||||
locationContainer.Id,
|
|
||||||
location,
|
|
||||||
locationContainer.PersonKey,
|
|
||||||
rectangle.Value,
|
|
||||||
locationContainer.WholePercentages));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (results.Count > 0)
|
|
||||||
outputResolutionCheck = null;
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Shared.Models.Face> GetFaces(string outputResolution, string dResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, ReadOnlyCollection<LocationContainer>? locationContainers, 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 = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize)];
|
string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize)];
|
||||||
List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList();
|
List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList();
|
||||||
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath);
|
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath);
|
||||||
@ -359,16 +300,11 @@ public class D_Face
|
|||||||
parseExceptions.Add(nameof(D_Face));
|
parseExceptions.Add(nameof(D_Face));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
List<LocationContainer> collection;
|
|
||||||
if (results is null || locationContainers is null)
|
|
||||||
collection = [];
|
|
||||||
else
|
|
||||||
collection = GetLocationContainers(outputResolution, locationContainers, outputResolutionToResize, results);
|
|
||||||
if (!_LoadPhotoPrismLocations || mappingFromPhotoPrismCollection is null || results is null)
|
if (!_LoadPhotoPrismLocations || mappingFromPhotoPrismCollection is null || results is null)
|
||||||
locations = (from l in collection where l is not null select l.Location).ToList();
|
locations = [];
|
||||||
else
|
else
|
||||||
locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(collection, results, mappingFromPhotoPrismCollection, _RectangleIntersectMinimum);
|
locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(results, mappingFromPhotoPrismCollection, _RectangleIntersectMinimum);
|
||||||
if (results is null || (locations is not null && locations.Count > 0))
|
if (results is null || locations.Count > 0)
|
||||||
{
|
{
|
||||||
results = GetFaces(outputResolution, property, mappingFromItem, outputResolutionToResize, locations);
|
results = GetFaces(outputResolution, property, mappingFromItem, outputResolutionToResize, locations);
|
||||||
if (results.Count == 0)
|
if (results.Count == 0)
|
||||||
@ -394,7 +330,7 @@ public class D_Face
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<(Shared.Models.Face, FileInfo?, string, bool)> SaveFaces(string f, string dResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, List<Shared.Models.Face> faces)
|
public List<(Shared.Models.Face, FileInfo?, string, bool)> SaveFaces(string f, string dResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces)
|
||||||
{
|
{
|
||||||
List<(Shared.Models.Face, FileInfo?, string, bool Save)> results = [];
|
List<(Shared.Models.Face, FileInfo?, string, bool Save)> results = [];
|
||||||
bool save;
|
bool save;
|
||||||
@ -429,9 +365,41 @@ public class D_Face
|
|||||||
{
|
{
|
||||||
if (!directoryExists)
|
if (!directoryExists)
|
||||||
_ = Directory.CreateDirectory(directory);
|
_ = Directory.CreateDirectory(directory);
|
||||||
SaveFaces(mappingFromItem.ResizedFileHolder, results);
|
string? maker = Metadata.Models.Stateless.Methods.IMetadata.GetMaker(exifDirectory);
|
||||||
|
string? model = Metadata.Models.Stateless.Methods.IMetadata.GetModel(exifDirectory);
|
||||||
|
MetadataExtractor.GeoLocation? geoLocation = Metadata.Models.Stateless.Methods.IMetadata.GeoLocation(exifDirectory);
|
||||||
|
SaveFaces(mappingFromItem.ResizedFileHolder, geoLocation, maker, model, results);
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CA1416
|
||||||
|
|
||||||
|
void IFaceD.ReSaveFace(ExifDirectory exifDirectory, LocationContainer locationContainer, Shared.Models.Face face)
|
||||||
|
{
|
||||||
|
FileInfo fileInfo = new(locationContainer.FilePath.FullName);
|
||||||
|
if (fileInfo.Exists)
|
||||||
|
{
|
||||||
|
short type = 2;
|
||||||
|
string checkFile = $"{locationContainer.FilePath.FullName}.exif";
|
||||||
|
int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist;
|
||||||
|
string? maker = Metadata.Models.Stateless.Methods.IMetadata.GetMaker(exifDirectory);
|
||||||
|
string? model = Metadata.Models.Stateless.Methods.IMetadata.GetModel(exifDirectory);
|
||||||
|
MetadataExtractor.GeoLocation? geoLocation = Metadata.Models.Stateless.Methods.IMetadata.GeoLocation(exifDirectory);
|
||||||
|
FaceFile faceFile = new(face.DateTime, geoLocation?.ToDmsString(), face.FaceParts, face.Location, maker, model, face.OutputResolution);
|
||||||
|
string faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
|
||||||
|
ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, [], null) ?? throw new Exception();
|
||||||
|
PropertyItem? propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(constructorInfo, artist, type, faceFileJson);
|
||||||
|
Bitmap bitmap = new(fileInfo.FullName);
|
||||||
|
bitmap.SetPropertyItem(propertyItem);
|
||||||
|
bitmap.Save(checkFile);
|
||||||
|
bitmap.Dispose();
|
||||||
|
File.SetLastWriteTime(checkFile, fileInfo.LastWriteTime);
|
||||||
|
File.Delete(fileInfo.FullName);
|
||||||
|
File.Move(checkFile, fileInfo.FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning restore CA1416
|
||||||
|
|
||||||
}
|
}
|
@ -203,7 +203,7 @@ public class FaceRecognition : DisposableObject
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<(Location, FaceEncoding?, Dictionary<FacePart, FacePoint[]>?)> GetCollection(Image image, List<Location>? locations, bool includeFaceEncoding, bool includeFaceParts)
|
public List<(Location, FaceEncoding?, Dictionary<FacePart, FacePoint[]>?)> GetCollection(Image image, List<Location> locations, bool includeFaceEncoding, bool includeFaceParts)
|
||||||
{
|
{
|
||||||
List<(Location, FaceEncoding?, Dictionary<FacePart, FacePoint[]>?)> results = [];
|
List<(Location, FaceEncoding?, Dictionary<FacePart, FacePoint[]>?)> results = [];
|
||||||
if (image is null)
|
if (image is null)
|
||||||
@ -212,9 +212,7 @@ public class FaceRecognition : DisposableObject
|
|||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
if (_PredictorModel == PredictorModel.Custom)
|
if (_PredictorModel == PredictorModel.Custom)
|
||||||
throw new NotSupportedException("FaceRecognition.PredictorModel.Custom is not supported.");
|
throw new NotSupportedException("FaceRecognition.PredictorModel.Custom is not supported.");
|
||||||
if (locations is null)
|
if (locations.Count == 0)
|
||||||
locations = GetLocations(image);
|
|
||||||
else if (locations.Count == 0)
|
|
||||||
locations.AddRange(GetLocations(image));
|
locations.AddRange(GetLocations(image));
|
||||||
List<FullObjectDetection> fullObjectDetections = GetFullObjectDetections(image, locations);
|
List<FullObjectDetection> fullObjectDetections = GetFullObjectDetections(image, locations);
|
||||||
if (fullObjectDetections.Count != locations.Count)
|
if (fullObjectDetections.Count != locations.Count)
|
||||||
|
@ -22,19 +22,20 @@ using WindowsShortcutFactory;
|
|||||||
|
|
||||||
namespace View_by_Distance.Instance;
|
namespace View_by_Distance.Instance;
|
||||||
|
|
||||||
public partial class DlibDotNet
|
public partial class DlibDotNet : IDlibDotNet, IDisposable
|
||||||
{
|
{
|
||||||
|
|
||||||
[GeneratedRegex(@"[\\,\/,\:,\*,\?,\"",\<,\>,\|]")]
|
[GeneratedRegex(@"[\\,\/,\:,\*,\?,\"",\<,\>,\|]")]
|
||||||
private static partial Regex CameraRegex();
|
private static partial Regex CameraRegex();
|
||||||
|
|
||||||
private readonly D_Face _Faces;
|
private readonly D_Face _Faces;
|
||||||
|
private ProgressBar? _ProgressBar;
|
||||||
private readonly C_Resize _Resize;
|
private readonly C_Resize _Resize;
|
||||||
private readonly F_Random _Random;
|
private readonly F_Random _Random;
|
||||||
private readonly IConsole _Console;
|
private readonly IConsole _Console;
|
||||||
private readonly E_Distance _Distance;
|
private readonly E_Distance _Distance;
|
||||||
private readonly IBlurHasher _BlurHasher;
|
|
||||||
private readonly D2_FaceParts _FaceParts;
|
private readonly D2_FaceParts _FaceParts;
|
||||||
|
private readonly IBlurHasher _BlurHasher;
|
||||||
private readonly AppSettings _AppSettings;
|
private readonly AppSettings _AppSettings;
|
||||||
private readonly List<string> _Exceptions;
|
private readonly List<string> _Exceptions;
|
||||||
private readonly ILogger<Program>? _Logger;
|
private readonly ILogger<Program>? _Logger;
|
||||||
@ -167,6 +168,15 @@ public partial class DlibDotNet
|
|||||||
_Logger?.LogInformation("First run completed. Run again if wanted");
|
_Logger?.LogInformation("First run completed. Run again if wanted");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IDlibDotNet.Tick() =>
|
||||||
|
_ProgressBar?.Tick();
|
||||||
|
|
||||||
|
void IDisposable.Dispose()
|
||||||
|
{
|
||||||
|
_ProgressBar?.Dispose();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
private static void Verify(Models.Configuration configuration)
|
private static void Verify(Models.Configuration configuration)
|
||||||
{
|
{
|
||||||
if (configuration.RangeDaysDeltaTolerance.Length != 3)
|
if (configuration.RangeDaysDeltaTolerance.Length != 3)
|
||||||
@ -361,15 +371,12 @@ public partial class DlibDotNet
|
|||||||
if (filesCollectionRootDirectory is null || filesCollection is null)
|
if (filesCollectionRootDirectory is null || filesCollection is null)
|
||||||
throw new NullReferenceException(nameof(filesCollection));
|
throw new NullReferenceException(nameof(filesCollection));
|
||||||
message = $") Building Container(s) - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
message = $") Building Container(s) - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
||||||
using (ProgressBar progressBar = new(2, message, options))
|
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton);
|
||||||
{
|
if (!Directory.Exists(aPropertySingletonDirectory))
|
||||||
progressBar.Tick();
|
_ = Directory.CreateDirectory(aPropertySingletonDirectory);
|
||||||
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultSingleton);
|
_ProgressBar = new(short.MaxValue, message, options);
|
||||||
if (!Directory.Exists(aPropertySingletonDirectory))
|
(t, containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(this, _Configuration.PropertyConfiguration, aPropertySingletonDirectory, filesCollectionRootDirectory, filesCollection);
|
||||||
_ = Directory.CreateDirectory(aPropertySingletonDirectory);
|
_ProgressBar.Dispose();
|
||||||
(t, containers) = Shared.Models.Stateless.Methods.IContainer.GetContainers(_Configuration.PropertyConfiguration, aPropertySingletonDirectory, filesCollectionRootDirectory, filesCollection);
|
|
||||||
progressBar.Tick();
|
|
||||||
}
|
|
||||||
ReadOnlyCollection<Container> readOnlyContainers = new(containers);
|
ReadOnlyCollection<Container> readOnlyContainers = new(containers);
|
||||||
SaveDistinctIds(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, readOnlyContainers);
|
SaveDistinctIds(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, readOnlyContainers);
|
||||||
mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleContentDirectory, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleContentDirectory, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
||||||
@ -382,8 +389,10 @@ public partial class DlibDotNet
|
|||||||
string d2ResultsFullGroupDirectory;
|
string d2ResultsFullGroupDirectory;
|
||||||
foreach (string outputResolution in _Configuration.OutputResolutions)
|
foreach (string outputResolution in _Configuration.OutputResolutions)
|
||||||
{
|
{
|
||||||
|
_ProgressBar = new(5, nameof(mapLogic.LookForAbandoned), new ProgressBarOptions() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true });
|
||||||
(cResultsFullGroupDirectory, _, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution);
|
(cResultsFullGroupDirectory, _, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution);
|
||||||
mapLogic.LookForAbandoned(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, readOnlyContainers, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory);
|
mapLogic.LookForAbandoned(this, _Configuration.PropertyConfiguration, bResultsFullGroupDirectory, readOnlyContainers, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory);
|
||||||
|
_ProgressBar.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_Distance.Clear();
|
_Distance.Clear();
|
||||||
@ -843,7 +852,7 @@ public partial class DlibDotNet
|
|||||||
_Logger?.LogInformation(string.Concat("Moved <", item.FilePath.FullName, '>'));
|
_Logger?.LogInformation(string.Concat("Moved <", item.FilePath.FullName, '>'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetNotMappedCountAndUpdateMappingFromPersonThenSetMapping(MapLogic mapLogic, Item item, bool? isFocusRelativePath, ReadOnlyCollection<LocationContainer> locationContainers, MappingFromItem mappingFromItem, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection, List<Shared.Models.Face> faces)
|
private int GetNotMappedCountAndUpdateMappingFromPersonThenSetMapping(MapLogic mapLogic, Item item, bool? isFocusRelativePath, MappingFromItem mappingFromItem, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection, List<Shared.Models.Face> faces)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
double? α;
|
double? α;
|
||||||
@ -864,7 +873,6 @@ public partial class DlibDotNet
|
|||||||
bool? isFocusModel = GetIsFocusModel(item.Property);
|
bool? isFocusModel = GetIsFocusModel(item.Property);
|
||||||
long[] jLinkResolvedPersonKeys = _JLinkResolvedDirectories.Select(l => l.PersonKey).ToArray();
|
long[] jLinkResolvedPersonKeys = _JLinkResolvedDirectories.Select(l => l.PersonKey).ToArray();
|
||||||
ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers;
|
ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers;
|
||||||
ReadOnlyCollection<string> locationContainersFiles = new((from l in locationContainers select l.FilePath.FullName).ToArray());
|
|
||||||
foreach (Shared.Models.Face face in faces)
|
foreach (Shared.Models.Face face in faces)
|
||||||
{
|
{
|
||||||
wholePercentagesToPersonContainers = mapLogic.GetWholePercentagesToPersonContainers(item.Property?.Id);
|
wholePercentagesToPersonContainers = mapLogic.GetWholePercentagesToPersonContainers(item.Property?.Id);
|
||||||
@ -987,7 +995,6 @@ public partial class DlibDotNet
|
|||||||
List<string> parseExceptions = [];
|
List<string> parseExceptions = [];
|
||||||
string[] changesFrom = [nameof(A_Property)];
|
string[] changesFrom = [nameof(A_Property)];
|
||||||
List<Tuple<string, DateTime>> subFileTuples = [];
|
List<Tuple<string, DateTime>> subFileTuples = [];
|
||||||
ReadOnlyCollection<LocationContainer> locationContainers = mapLogic.GetLocationContainers(item);
|
|
||||||
FileHolder resizedFileHolder = _Resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber);
|
FileHolder resizedFileHolder = _Resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber);
|
||||||
if (item.Property is null || item.Property.Id is null || !item.SourceDirectoryFileHolder.Exists || item.SourceDirectoryFileHolder.CreationTime is null || item.SourceDirectoryFileHolder.LastWriteTime is null || item.Any())
|
if (item.Property is null || item.Property.Id is null || !item.SourceDirectoryFileHolder.Exists || item.SourceDirectoryFileHolder.CreationTime is null || item.SourceDirectoryFileHolder.LastWriteTime is null || item.Any())
|
||||||
{
|
{
|
||||||
@ -1030,7 +1037,6 @@ public partial class DlibDotNet
|
|||||||
item.SetResizedFileHolder(_Resize.FileNameExtension, resizedFileHolder);
|
item.SetResizedFileHolder(_Resize.FileNameExtension, resizedFileHolder);
|
||||||
MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder);
|
MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder);
|
||||||
ExifDirectory exifDirectory = metadata.GetMetadataCollection(item.FilePath, subFileTuples, parseExceptions, changesFrom, mappingFromItem);
|
ExifDirectory exifDirectory = metadata.GetMetadataCollection(item.FilePath, subFileTuples, parseExceptions, changesFrom, mappingFromItem);
|
||||||
Map.Models.Stateless.Methods.IMapLogic.SetCreationTimeMaybeMoveToDecade(_Configuration.PropertyConfiguration, _Configuration.MoveToDecade && _Configuration.LocationContainerDistanceTolerance is null, mappingFromItem, locationContainers);
|
|
||||||
if (_AppSettings.Places.Count > 0)
|
if (_AppSettings.Places.Count > 0)
|
||||||
{
|
{
|
||||||
float latitude;
|
float latitude;
|
||||||
@ -1065,15 +1071,23 @@ public partial class DlibDotNet
|
|||||||
List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection;
|
List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection;
|
||||||
if (!fileNameToCollection.TryGetValue(mappingFromItem.Id, out mappingFromPhotoPrismCollection))
|
if (!fileNameToCollection.TryGetValue(mappingFromItem.Id, out mappingFromPhotoPrismCollection))
|
||||||
mappingFromPhotoPrismCollection = null;
|
mappingFromPhotoPrismCollection = null;
|
||||||
faces = _Faces.GetFaces(outputResolution, dResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, property, mappingFromItem, outputResolutionToResize, locationContainers, mappingFromPhotoPrismCollection);
|
bool move = _Configuration.DistanceMoveUnableToMatch || _Configuration.DistanceRenameToMatch && _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution);
|
||||||
result = GetNotMappedCountAndUpdateMappingFromPersonThenSetMapping(mapLogic, item, isFocusRelativePath, locationContainers, mappingFromItem, mappingFromPhotoPrismCollection, faces);
|
faces = _Faces.GetFaces(outputResolution, dResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, property, mappingFromItem, outputResolutionToResize, mappingFromPhotoPrismCollection);
|
||||||
List<(Shared.Models.Face, FileInfo?, string, bool Saved)> faceCollection = _Faces.SaveFaces(_FaceParts.FileNameExtension, dResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, mappingFromItem, faces);
|
result = GetNotMappedCountAndUpdateMappingFromPersonThenSetMapping(mapLogic, item, isFocusRelativePath, mappingFromItem, mappingFromPhotoPrismCollection, faces);
|
||||||
|
List<(Shared.Models.Face, FileInfo?, string, bool Saved)> faceCollection = _Faces.SaveFaces(_FaceParts.FileNameExtension, dResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, mappingFromItem, exifDirectory, faces);
|
||||||
if (_Configuration.CopyFacesAndSaveFaceLandmarkForOutputResolutions.Contains(outputResolution))
|
if (_Configuration.CopyFacesAndSaveFaceLandmarkForOutputResolutions.Contains(outputResolution))
|
||||||
_FaceParts.CopyFacesAndSaveFaceLandmarkImage(facePartsCollectionDirectory, mappingFromItem, faceCollection);
|
_FaceParts.CopyFacesAndSaveFaceLandmarkImage(facePartsCollectionDirectory, mappingFromItem, faceCollection);
|
||||||
if ((_Configuration.DistanceMoveUnableToMatch || _Configuration.DistanceRenameToMatch)
|
if (move && faceCollection.All(l => !l.Saved))
|
||||||
&& _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution)
|
{
|
||||||
&& locationContainers is not null && faceCollection.All(l => !l.Saved))
|
ReadOnlyCollection<LocationContainer> locationContainers = mapLogic.GetLocationContainers(item);
|
||||||
_Distance.LookForMatchFacesAndPossiblyRename(_DistanceLimits, _Faces.FileNameExtension, item.FilePath, mappingFromItem, faces, locationContainers);
|
if (locationContainers.Count > 0)
|
||||||
|
{
|
||||||
|
Map.Models.Stateless.Methods.IMapLogic.SetCreationTime(mappingFromItem, locationContainers);
|
||||||
|
if (_Configuration.LocationContainerDistanceTolerance is null && _Configuration.MoveToDecade)
|
||||||
|
Map.Models.Stateless.Methods.IMapLogic.MoveToDecade(_Configuration.PropertyConfiguration, mappingFromItem, locationContainers);
|
||||||
|
_Distance.LookForMatchFacesAndPossiblyRename(_DistanceLimits, _Faces, item.FilePath, mappingFromItem, exifDirectory, faces, locationContainers);
|
||||||
|
}
|
||||||
|
}
|
||||||
(bool review, int[] eyesCollection) = Shared.Models.Stateless.Methods.IFace.GetEyeCollection(_Configuration.EyeThreshold, faces);
|
(bool review, int[] eyesCollection) = Shared.Models.Stateless.Methods.IFace.GetEyeCollection(_Configuration.EyeThreshold, faces);
|
||||||
if (review || _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution))
|
if (review || _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution))
|
||||||
{
|
{
|
||||||
|
@ -1355,37 +1355,43 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LookForAbandoned(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection<Container> readOnlyContainers, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory)
|
public void LookForAbandoned(IDlibDotNet dlibDotNet, Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, ReadOnlyCollection<Container> readOnlyContainers, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory)
|
||||||
{
|
{
|
||||||
string[] directories;
|
string[] directories;
|
||||||
string? directoryName;
|
string? directoryName;
|
||||||
List<int> distinctFilteredIds = IContainer.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
List<int> distinctFilteredIds = IContainer.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
||||||
LookForAbandoned(propertyConfiguration, distinctFilteredIds);
|
LookForAbandoned(propertyConfiguration, distinctFilteredIds);
|
||||||
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, bResultsFullGroupDirectory, distinctFilteredIds);
|
dlibDotNet.Tick();
|
||||||
|
List<string> distinctFilteredFileNameFirstSegments = IContainer.GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
|
||||||
|
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, bResultsFullGroupDirectory, distinctFilteredFileNameFirstSegments);
|
||||||
|
dlibDotNet.Tick();
|
||||||
directories = Directory.GetDirectories(cResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
directories = Directory.GetDirectories(cResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
foreach (string directory in directories)
|
foreach (string directory in directories)
|
||||||
{
|
{
|
||||||
directoryName = Path.GetFileName(directory);
|
directoryName = Path.GetFileName(directory);
|
||||||
if (string.IsNullOrEmpty(directoryName) || directoryName.Length != 2 && directoryName.Length != 4)
|
if (string.IsNullOrEmpty(directoryName) || directoryName.Length != 2 && directoryName.Length != 4)
|
||||||
continue;
|
continue;
|
||||||
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredIds, directory, directoryName);
|
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
|
||||||
}
|
}
|
||||||
|
dlibDotNet.Tick();
|
||||||
directories = Directory.GetDirectories(dResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
directories = Directory.GetDirectories(dResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
foreach (string directory in directories)
|
foreach (string directory in directories)
|
||||||
{
|
{
|
||||||
directoryName = Path.GetFileName(directory);
|
directoryName = Path.GetFileName(directory);
|
||||||
if (string.IsNullOrEmpty(directoryName) || directoryName.Length != 2 && directoryName.Length != 4)
|
if (string.IsNullOrEmpty(directoryName) || directoryName.Length != 2 && directoryName.Length != 4)
|
||||||
continue;
|
continue;
|
||||||
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredIds, directory, directoryName);
|
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
|
||||||
}
|
}
|
||||||
|
dlibDotNet.Tick();
|
||||||
directories = Directory.GetDirectories(d2ResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
directories = Directory.GetDirectories(d2ResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
foreach (string directory in directories)
|
foreach (string directory in directories)
|
||||||
{
|
{
|
||||||
directoryName = Path.GetFileName(directory);
|
directoryName = Path.GetFileName(directory);
|
||||||
if (string.IsNullOrEmpty(directoryName) || directoryName.Length != 2 && directoryName.Length != 4)
|
if (string.IsNullOrEmpty(directoryName) || directoryName.Length != 2 && directoryName.Length != 4)
|
||||||
continue;
|
continue;
|
||||||
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredIds, directory, directoryName);
|
Stateless.LookForAbandonedLogic.LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
|
||||||
}
|
}
|
||||||
|
dlibDotNet.Tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -32,9 +32,23 @@ internal abstract class DecadeLogic
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void SetCreationTimeMaybeMoveToDecade(Property.Models.Configuration propertyConfiguration, bool moveToDecade, MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers)
|
internal static void SetCreationTime(MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers)
|
||||||
{
|
{
|
||||||
DateTime dateTime;
|
DateTime dateTime;
|
||||||
|
foreach (LocationContainer locationContainer in locationContainers)
|
||||||
|
{
|
||||||
|
dateTime = mappingFromItem.DateTimeOriginal is null ? mappingFromItem.MinimumDateTime : mappingFromItem.DateTimeOriginal.Value;
|
||||||
|
if (locationContainer.CreationDateOnly.Year != dateTime.Year || locationContainer.CreationDateOnly.Month != dateTime.Month || locationContainer.CreationDateOnly.Day != dateTime.Day)
|
||||||
|
{
|
||||||
|
if (!File.Exists(locationContainer.FilePath.FullName))
|
||||||
|
continue;
|
||||||
|
File.SetCreationTime(locationContainer.FilePath.FullName, dateTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void MoveToDecade(Property.Models.Configuration propertyConfiguration, MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers)
|
||||||
|
{
|
||||||
string halfDecade;
|
string halfDecade;
|
||||||
string checkDirectory;
|
string checkDirectory;
|
||||||
string? yearDirectory;
|
string? yearDirectory;
|
||||||
@ -44,13 +58,6 @@ internal abstract class DecadeLogic
|
|||||||
string? personKeyFormattedDirectoryName;
|
string? personKeyFormattedDirectoryName;
|
||||||
foreach (LocationContainer locationContainer in locationContainers)
|
foreach (LocationContainer locationContainer in locationContainers)
|
||||||
{
|
{
|
||||||
if (!File.Exists(locationContainer.FilePath.FullName))
|
|
||||||
continue;
|
|
||||||
dateTime = mappingFromItem.DateTimeOriginal is null ? mappingFromItem.MinimumDateTime : mappingFromItem.DateTimeOriginal.Value;
|
|
||||||
if (locationContainer.CreationDateOnly.Year != dateTime.Year || locationContainer.CreationDateOnly.Month != dateTime.Month || locationContainer.CreationDateOnly.Day != dateTime.Day)
|
|
||||||
File.SetCreationTime(locationContainer.FilePath.FullName, dateTime);
|
|
||||||
if (!moveToDecade)
|
|
||||||
continue;
|
|
||||||
if (string.IsNullOrEmpty(locationContainer.FilePath.DirectoryName))
|
if (string.IsNullOrEmpty(locationContainer.FilePath.DirectoryName))
|
||||||
continue;
|
continue;
|
||||||
personNameDirectoryName = Path.GetFileName(locationContainer.FilePath.DirectoryName);
|
personNameDirectoryName = Path.GetFileName(locationContainer.FilePath.DirectoryName);
|
||||||
@ -68,6 +75,8 @@ internal abstract class DecadeLogic
|
|||||||
if (halfDecade == yearDirectoryName)
|
if (halfDecade == yearDirectoryName)
|
||||||
continue;
|
continue;
|
||||||
checkDirectory = Path.Combine(personKeyFormattedDirectory, halfDecade, personNameDirectoryName);
|
checkDirectory = Path.Combine(personKeyFormattedDirectory, halfDecade, personNameDirectoryName);
|
||||||
|
if (!File.Exists(locationContainer.FilePath.FullName))
|
||||||
|
continue;
|
||||||
if (!Directory.Exists(checkDirectory))
|
if (!Directory.Exists(checkDirectory))
|
||||||
_ = Directory.CreateDirectory(checkDirectory);
|
_ = Directory.CreateDirectory(checkDirectory);
|
||||||
File.Move(locationContainer.FilePath.FullName, Path.Combine(checkDirectory, locationContainer.FilePath.Name));
|
File.Move(locationContainer.FilePath.FullName, Path.Combine(checkDirectory, locationContainer.FilePath.Name));
|
||||||
|
@ -6,13 +6,12 @@ namespace View_by_Distance.Map.Models.Stateless;
|
|||||||
internal abstract class LookForAbandonedLogic
|
internal abstract class LookForAbandonedLogic
|
||||||
{
|
{
|
||||||
|
|
||||||
internal static void LookForAbandoned(Property.Models.Configuration propertyConfiguration, List<int> distinctFilteredIds, string directory, string directoryName)
|
internal static void LookForAbandoned(Property.Models.Configuration propertyConfiguration, List<string> distinctFilteredFileNameFirstSegments, string directory, string directoryName)
|
||||||
{
|
{
|
||||||
FilePath filePath;
|
FilePath filePath;
|
||||||
FileHolder fileHolder;
|
FileHolder fileHolder;
|
||||||
string fileNameFirstSegment;
|
string fileNameFirstSegment;
|
||||||
List<string> renameCollection = [];
|
List<string> renameCollection = [];
|
||||||
string[] distinctFilteredIdsValues = distinctFilteredIds.Select(l => l.ToString()).ToArray();
|
|
||||||
string[] files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
|
string[] files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
|
||||||
foreach (string file in files)
|
foreach (string file in files)
|
||||||
{
|
{
|
||||||
@ -21,7 +20,7 @@ internal abstract class LookForAbandonedLogic
|
|||||||
fileNameFirstSegment = fileHolder.NameWithoutExtension.Split('.')[0];
|
fileNameFirstSegment = fileHolder.NameWithoutExtension.Split('.')[0];
|
||||||
if (!filePath.IsIntelligentIdFormat && filePath.SortOrder is null)
|
if (!filePath.IsIntelligentIdFormat && filePath.SortOrder is null)
|
||||||
continue;
|
continue;
|
||||||
if (distinctFilteredIdsValues.Contains(fileNameFirstSegment))
|
if (distinctFilteredFileNameFirstSegments.Contains(fileNameFirstSegment))
|
||||||
continue;
|
continue;
|
||||||
renameCollection.Add(file);
|
renameCollection.Add(file);
|
||||||
}
|
}
|
||||||
@ -36,7 +35,7 @@ internal abstract class LookForAbandonedLogic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void LookForAbandoned(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, List<int> distinctFilteredIds)
|
internal static void LookForAbandoned(Property.Models.Configuration propertyConfiguration, string bResultsFullGroupDirectory, List<string> distinctFilteredFileNameFirstSegments)
|
||||||
{
|
{
|
||||||
string[] directories = Directory.GetDirectories(bResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
string[] directories = Directory.GetDirectories(bResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||||
foreach (string directory in directories)
|
foreach (string directory in directories)
|
||||||
@ -44,7 +43,7 @@ internal abstract class LookForAbandonedLogic
|
|||||||
string? directoryName = Path.GetFileName(directory);
|
string? directoryName = Path.GetFileName(directory);
|
||||||
if (string.IsNullOrEmpty(directoryName) || (directoryName.Length != 2 && directoryName.Length != 4))
|
if (string.IsNullOrEmpty(directoryName) || (directoryName.Length != 2 && directoryName.Length != 4))
|
||||||
continue;
|
continue;
|
||||||
LookForAbandoned(propertyConfiguration, distinctFilteredIds, directory, directoryName);
|
LookForAbandoned(propertyConfiguration, distinctFilteredFileNameFirstSegments, directory, directoryName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using View_by_Distance.Shared.Models;
|
||||||
|
|
||||||
namespace View_by_Distance.Map.Models.Stateless.Methods;
|
namespace View_by_Distance.Map.Models.Stateless.Methods;
|
||||||
|
|
||||||
@ -10,24 +11,24 @@ public interface IMapLogic
|
|||||||
static ReadOnlyDictionary<int, List<long>> GetIdToPersonKeys(ReadOnlyDictionary<long, List<int>> personKeyToIds) =>
|
static ReadOnlyDictionary<int, List<long>> GetIdToPersonKeys(ReadOnlyDictionary<long, List<int>> personKeyToIds) =>
|
||||||
MapLogic.GetIdToPersonKeys(personKeyToIds);
|
MapLogic.GetIdToPersonKeys(personKeyToIds);
|
||||||
|
|
||||||
ReadOnlyCollection<Shared.Models.Face> TestStatic_GetFaces(ReadOnlyCollection<Shared.Models.Item> items) =>
|
ReadOnlyCollection<Face> TestStatic_GetFaces(ReadOnlyCollection<Item> items) =>
|
||||||
GetFaces(items);
|
GetFaces(items);
|
||||||
static ReadOnlyCollection<Shared.Models.Face> GetFaces(ReadOnlyCollection<Shared.Models.Item> items) =>
|
static ReadOnlyCollection<Face> GetFaces(ReadOnlyCollection<Item> items) =>
|
||||||
MapLogic.GetFaces(items);
|
MapLogic.GetFaces(items);
|
||||||
|
|
||||||
Shared.Models.Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Shared.Models.Item> items) =>
|
Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Item> items) =>
|
||||||
GetSelectedMappingCollection(items);
|
GetSelectedMappingCollection(items);
|
||||||
static Shared.Models.Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Shared.Models.Item> items) =>
|
static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Item> items) =>
|
||||||
MapLogic.GetSelectedMappingCollection(items);
|
MapLogic.GetSelectedMappingCollection(items);
|
||||||
|
|
||||||
Shared.Models.Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Shared.Models.Face> faces) =>
|
Mapping[] TestStatic_GetSelectedMappingCollection(ReadOnlyCollection<Face> faces) =>
|
||||||
GetSelectedMappingCollection(faces);
|
GetSelectedMappingCollection(faces);
|
||||||
static Shared.Models.Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Shared.Models.Face> faces) =>
|
static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Face> faces) =>
|
||||||
MapLogic.GetSelectedMappingCollection(faces);
|
MapLogic.GetSelectedMappingCollection(faces);
|
||||||
|
|
||||||
ReadOnlyDictionary<int, ReadOnlyDictionary<int, Shared.Models.Mapping>> TestStatic_GetIdToWholePercentagesToFace(ReadOnlyCollection<Shared.Models.Mapping> distinctValidImageMappingCollection) =>
|
ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> TestStatic_GetIdToWholePercentagesToFace(ReadOnlyCollection<Mapping> distinctValidImageMappingCollection) =>
|
||||||
GetIdToWholePercentagesToFace(distinctValidImageMappingCollection);
|
GetIdToWholePercentagesToFace(distinctValidImageMappingCollection);
|
||||||
static ReadOnlyDictionary<int, ReadOnlyDictionary<int, Shared.Models.Mapping>> GetIdToWholePercentagesToFace(ReadOnlyCollection<Shared.Models.Mapping> distinctValidImageMappingCollection) =>
|
static ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> GetIdToWholePercentagesToFace(ReadOnlyCollection<Mapping> distinctValidImageMappingCollection) =>
|
||||||
MapLogic.GetIdToWholePercentagesToFace(distinctValidImageMappingCollection);
|
MapLogic.GetIdToWholePercentagesToFace(distinctValidImageMappingCollection);
|
||||||
|
|
||||||
List<(string, long)> TestStatic_GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) =>
|
List<(string, long)> TestStatic_GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) =>
|
||||||
@ -35,19 +36,24 @@ public interface IMapLogic
|
|||||||
static List<(string, long)> GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) =>
|
static List<(string, long)> GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) =>
|
||||||
MapLogic.GetJLinkDirectories(genealogicalDataCommunicationFile, jLinks, personBirthdayFormat, personCharacters, a2PeopleSingletonDirectory, a2PeopleContentDirectory);
|
MapLogic.GetJLinkDirectories(genealogicalDataCommunicationFile, jLinks, personBirthdayFormat, personCharacters, a2PeopleSingletonDirectory, a2PeopleContentDirectory);
|
||||||
|
|
||||||
void TestStatic_SetCreationTimeMaybeMoveToDecade(Property.Models.Configuration propertyConfiguration, bool moveToDecade, Shared.Models.MappingFromItem mappingFromItem, ReadOnlyCollection<Shared.Models.LocationContainer> locationContainers) =>
|
void TestStatic_SetCreationTime(MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||||
SetCreationTimeMaybeMoveToDecade(propertyConfiguration, moveToDecade, mappingFromItem, locationContainers);
|
SetCreationTime(mappingFromItem, locationContainers);
|
||||||
static void SetCreationTimeMaybeMoveToDecade(Property.Models.Configuration propertyConfiguration, bool moveToDecade, Shared.Models.MappingFromItem mappingFromItem, ReadOnlyCollection<Shared.Models.LocationContainer> locationContainers) =>
|
static void SetCreationTime(MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||||
DecadeLogic.SetCreationTimeMaybeMoveToDecade(propertyConfiguration, moveToDecade, mappingFromItem, locationContainers);
|
DecadeLogic.SetCreationTime(mappingFromItem, locationContainers);
|
||||||
|
|
||||||
bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<Shared.Models.PersonContainer>>? wholePercentagesToPersonContainers, Shared.Models.MappingFromLocation mappingFromLocation) =>
|
void TestStatic_MoveToDecade(Property.Models.Configuration propertyConfiguration, MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||||
|
MoveToDecade(propertyConfiguration, mappingFromItem, locationContainers);
|
||||||
|
static void MoveToDecade(Property.Models.Configuration propertyConfiguration, MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers) =>
|
||||||
|
DecadeLogic.MoveToDecade(propertyConfiguration, mappingFromItem, locationContainers);
|
||||||
|
|
||||||
|
bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
|
||||||
CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation);
|
CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation);
|
||||||
static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<Shared.Models.PersonContainer>>? wholePercentagesToPersonContainers, Shared.Models.MappingFromLocation mappingFromLocation) =>
|
static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) =>
|
||||||
MapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation);
|
MapLogic.CanReMap(jLinkResolvedPersonKeys, wholePercentagesToPersonContainers, mappingFromLocation);
|
||||||
|
|
||||||
string TestStatic_GetDecade(Shared.Models.MappingFromItem mappingFromItem) =>
|
string TestStatic_GetDecade(MappingFromItem mappingFromItem) =>
|
||||||
GetDecade(mappingFromItem);
|
GetDecade(mappingFromItem);
|
||||||
static string GetDecade(Shared.Models.MappingFromItem mappingFromItem) =>
|
static string GetDecade(MappingFromItem mappingFromItem) =>
|
||||||
DecadeLogic.GetDecade(mappingFromItem, null);
|
DecadeLogic.GetDecade(mappingFromItem, null);
|
||||||
|
|
||||||
}
|
}
|
@ -519,8 +519,12 @@ internal abstract class Exif
|
|||||||
|
|
||||||
internal static Shared.Models.ExifDirectory GetExifDirectory(Shared.Models.FilePath filePath)
|
internal static Shared.Models.ExifDirectory GetExifDirectory(Shared.Models.FilePath filePath)
|
||||||
{
|
{
|
||||||
Shared.Models.ExifDirectory? result;
|
Shared.Models.ExifDirectory result;
|
||||||
System.Drawing.Size? size = Dimensions.GetDimensions(filePath.FullName);
|
System.Drawing.Size? size;
|
||||||
|
try
|
||||||
|
{ size = Dimensions.GetDimensions(filePath.FullName); }
|
||||||
|
catch (Exception)
|
||||||
|
{ size = null; }
|
||||||
IReadOnlyList<MetadataExtractor.Directory> directories = ImageMetadataReader.ReadMetadata(filePath.FullName);
|
IReadOnlyList<MetadataExtractor.Directory> directories = ImageMetadataReader.ReadMetadata(filePath.FullName);
|
||||||
result = Covert(filePath, size, directories);
|
result = Covert(filePath, size, directories);
|
||||||
return result;
|
return result;
|
||||||
|
17
Shared/Models/FaceFile.cs
Normal file
17
Shared/Models/FaceFile.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace View_by_Distance.Shared.Models;
|
||||||
|
|
||||||
|
public record FaceFile(DateTime DateTime,
|
||||||
|
string? DMS,
|
||||||
|
Dictionary<Stateless.FacePart, FacePoint[]>? FaceParts,
|
||||||
|
Location? Location,
|
||||||
|
string? Maker,
|
||||||
|
string? Model,
|
||||||
|
OutputResolution? OutputResolution);
|
||||||
|
|
||||||
|
[JsonSourceGenerationOptions(WriteIndented = false)]
|
||||||
|
[JsonSerializable(typeof(FaceFile))]
|
||||||
|
public partial class FaceFileGenerationContext : JsonSerializerContext
|
||||||
|
{
|
||||||
|
}
|
@ -29,7 +29,7 @@ internal abstract class Container
|
|||||||
return container.Items.Count == results.Count ? container.Items : new(results);
|
return container.Items.Count == results.Count ? container.Items : new(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static List<Models.FilePair> GetFilePairs(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string aPropertySingletonDirectory, ReadOnlyCollection<string[]> filesCollection)
|
internal static List<Models.FilePair> GetFilePairs(IDlibDotNet? dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string aPropertySingletonDirectory, ReadOnlyCollection<string[]> filesCollection)
|
||||||
{
|
{
|
||||||
int renamed;
|
int renamed;
|
||||||
const bool useCeilingAverage = true;
|
const bool useCeilingAverage = true;
|
||||||
@ -37,16 +37,19 @@ internal abstract class Container
|
|||||||
ReadOnlyCollection<string[]>? jsonFilesCollection = null;
|
ReadOnlyCollection<string[]>? jsonFilesCollection = null;
|
||||||
IReadOnlyDictionary<string, List<string>>? compareFileNamesToFiles = null;
|
IReadOnlyDictionary<string, List<string>>? compareFileNamesToFiles = null;
|
||||||
IReadOnlyDictionary<string, List<string>> fileNamesToFiles = XDirectory.GetFilesKeyValuePairs(filesCollection);
|
IReadOnlyDictionary<string, List<string>> fileNamesToFiles = XDirectory.GetFilesKeyValuePairs(filesCollection);
|
||||||
for (int i = 0; i < int.MaxValue; i++)
|
for (int i = 0; i < short.MaxValue; i++)
|
||||||
{
|
{
|
||||||
renamed = 0;
|
renamed = 0;
|
||||||
|
dlibDotNet?.Tick();
|
||||||
jsonFilesCollection = IDirectory.GetFilesCollection(aPropertySingletonDirectory, directorySearchFilter, extension, useCeilingAverage);
|
jsonFilesCollection = IDirectory.GetFilesCollection(aPropertySingletonDirectory, directorySearchFilter, extension, useCeilingAverage);
|
||||||
compareFileNamesToFiles = XDirectory.GetFilesKeyValuePairs(jsonFilesCollection);
|
compareFileNamesToFiles = XDirectory.GetFilesKeyValuePairs(jsonFilesCollection);
|
||||||
renamed += XDirectory.LookForAbandoned(jsonFilesCollection, fileNamesToFiles, extension);
|
renamed += XDirectory.LookForAbandoned(jsonFilesCollection, fileNamesToFiles, extension);
|
||||||
filePairs = XDirectory.GetFiles(filesCollection, fileNamesToFiles, extension, compareFileNamesToFiles);
|
filePairs = XDirectory.GetFiles(propertyConfiguration, filesCollection, fileNamesToFiles, extension, compareFileNamesToFiles);
|
||||||
renamed += XDirectory.MaybeMove(propertyConfiguration, filePairs, aPropertySingletonDirectory, extension);
|
renamed += XDirectory.MaybeMove(propertyConfiguration, filePairs, aPropertySingletonDirectory, extension);
|
||||||
if (renamed == 0)
|
if (renamed == 0)
|
||||||
break;
|
break;
|
||||||
|
if (i > 10)
|
||||||
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
if (filePairs is null || jsonFilesCollection is null || compareFileNamesToFiles is null)
|
if (filePairs is null || jsonFilesCollection is null || compareFileNamesToFiles is null)
|
||||||
throw new NullReferenceException(nameof(filePairs));
|
throw new NullReferenceException(nameof(filePairs));
|
||||||
@ -119,19 +122,19 @@ internal abstract class Container
|
|||||||
results.Add(new(filePair.IsUnique, filePair.Collection, filePath, item));
|
results.Add(new(filePair.IsUnique, filePair.Collection, filePath, item));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<FilePair> GetFilePairs(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyCollection<string[]> filesCollection, string directorySearchFilter)
|
private static List<FilePair> GetFilePairs(IDlibDotNet? dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyCollection<string[]> filesCollection, string directorySearchFilter)
|
||||||
{
|
{
|
||||||
List<FilePair> results = [];
|
List<FilePair> results = [];
|
||||||
const string extension = ".json";
|
const string extension = ".json";
|
||||||
int maxDegreeOfParallelism = Environment.ProcessorCount;
|
int maxDegreeOfParallelism = Environment.ProcessorCount;
|
||||||
int filesCollectionDirectoryLength = filesCollectionDirectory.Length;
|
int filesCollectionDirectoryLength = filesCollectionDirectory.Length;
|
||||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||||
List<Models.FilePair> filePairs = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, aPropertySingletonDirectory, filesCollection);
|
List<Models.FilePair> filePairs = GetFilePairs(dlibDotNet, propertyConfiguration, directorySearchFilter, extension, aPropertySingletonDirectory, filesCollection);
|
||||||
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(propertyConfiguration, aPropertySingletonDirectory, extension, filesCollectionDirectoryLength, filePairs[i], results));
|
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(propertyConfiguration, aPropertySingletonDirectory, extension, filesCollectionDirectoryLength, filePairs[i], results));
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyCollection<string[]> filesCollection, string directorySearchFilter)
|
private static (int, Models.Container[]) GetContainers(IDlibDotNet? dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyCollection<string[]> filesCollection, string directorySearchFilter)
|
||||||
{
|
{
|
||||||
List<Models.Container> results = [];
|
List<Models.Container> results = [];
|
||||||
string? directory;
|
string? directory;
|
||||||
@ -155,7 +158,7 @@ internal abstract class Container
|
|||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
List<FilePair> filePairs = GetFilePairs(propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, filesCollection, directorySearchFilter);
|
List<FilePair> filePairs = GetFilePairs(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, filesCollection, directorySearchFilter);
|
||||||
foreach (FilePair filePair in filePairs)
|
foreach (FilePair filePair in filePairs)
|
||||||
{
|
{
|
||||||
if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryName, out items))
|
if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryName, out items))
|
||||||
@ -176,12 +179,12 @@ internal abstract class Container
|
|||||||
return (filePairs.Count, results.ToArray());
|
return (filePairs.Count, results.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyCollection<string[]> filesCollection)
|
internal static (int, Models.Container[]) GetContainers(IDlibDotNet dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyCollection<string[]> filesCollection)
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
Models.Container[] results;
|
Models.Container[] results;
|
||||||
const string directorySearchFilter = "*";
|
const string directorySearchFilter = "*";
|
||||||
(count, results) = GetContainers(propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, filesCollection, directorySearchFilter);
|
(count, results) = GetContainers(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, filesCollection, directorySearchFilter);
|
||||||
return (count, results);
|
return (count, results);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,11 +192,12 @@ internal abstract class Container
|
|||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
Models.Container[] results;
|
Models.Container[] results;
|
||||||
|
IDlibDotNet? dlibDotNet = null;
|
||||||
const bool useCeilingAverage = true;
|
const bool useCeilingAverage = true;
|
||||||
const string fileSearchFilter = "*";
|
const string fileSearchFilter = "*";
|
||||||
const string directorySearchFilter = "*";
|
const string directorySearchFilter = "*";
|
||||||
ReadOnlyCollection<string[]> filesCollection = IDirectory.GetFilesCollection(propertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
ReadOnlyCollection<string[]> filesCollection = IDirectory.GetFilesCollection(propertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
|
||||||
(count, results) = GetContainers(propertyConfiguration, aPropertySingletonDirectory, propertyConfiguration.RootDirectory, filesCollection, directorySearchFilter);
|
(count, results) = GetContainers(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, propertyConfiguration.RootDirectory, filesCollection, directorySearchFilter);
|
||||||
return (count, results);
|
return (count, results);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,6 +224,29 @@ internal abstract class Container
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static List<string> GetFilteredDistinctFileNameFirstSegments(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers)
|
||||||
|
{
|
||||||
|
List<string> results = [];
|
||||||
|
ReadOnlyCollection<Models.Item> filteredItems;
|
||||||
|
foreach (Models.Container container in readOnlyContainers)
|
||||||
|
{
|
||||||
|
if (container.Items.Count == 0)
|
||||||
|
continue;
|
||||||
|
filteredItems = GetValidImageItems(propertyConfiguration, container);
|
||||||
|
if (filteredItems.Count == 0)
|
||||||
|
continue;
|
||||||
|
foreach (Models.Item item in filteredItems)
|
||||||
|
{
|
||||||
|
if (item.Property?.Id is null || item.ResizedFileHolder is null)
|
||||||
|
continue;
|
||||||
|
if (results.Contains(item.FilePath.FileNameFirstSegment))
|
||||||
|
continue;
|
||||||
|
results.Add(item.FilePath.FileNameFirstSegment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
internal static ReadOnlyCollection<Models.Item> GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems)
|
internal static ReadOnlyCollection<Models.Item> GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems)
|
||||||
{
|
{
|
||||||
List<Models.Item> results = [];
|
List<Models.Item> results = [];
|
||||||
|
@ -20,16 +20,21 @@ public interface IContainer
|
|||||||
static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) =>
|
static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) =>
|
||||||
Container.GetContainers(propertyConfiguration, aPropertySingletonDirectory);
|
Container.GetContainers(propertyConfiguration, aPropertySingletonDirectory);
|
||||||
|
|
||||||
(int, Models.Container[]) TestStatic_GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyCollection<string[]> filesCollection) =>
|
(int, Models.Container[]) TestStatic_GetContainers(IDlibDotNet dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyCollection<string[]> filesCollection) =>
|
||||||
GetContainers(propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, filesCollection);
|
GetContainers(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, filesCollection);
|
||||||
static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyCollection<string[]> filesCollection) =>
|
static (int, Models.Container[]) GetContainers(IDlibDotNet dlibDotNet, Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyCollection<string[]> filesCollection) =>
|
||||||
Container.GetContainers(propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, filesCollection);
|
Container.GetContainers(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, filesCollection);
|
||||||
|
|
||||||
List<int> TestStatic_GetFilteredDistinctIds(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
List<int> TestStatic_GetFilteredDistinctIds(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||||
GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
||||||
static List<int> GetFilteredDistinctIds(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
static List<int> GetFilteredDistinctIds(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||||
Container.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
Container.GetFilteredDistinctIds(propertyConfiguration, readOnlyContainers);
|
||||||
|
|
||||||
|
List<string> TestStatic_GetFilteredDistinctFileNameFirstSegments(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||||
|
GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
|
||||||
|
static List<string> GetFilteredDistinctFileNameFirstSegments(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> readOnlyContainers) =>
|
||||||
|
Container.GetFilteredDistinctFileNameFirstSegments(propertyConfiguration, readOnlyContainers);
|
||||||
|
|
||||||
ReadOnlyCollection<Models.Item> TestStatic_GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
|
ReadOnlyCollection<Models.Item> TestStatic_GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
|
||||||
GetValidImageItems(propertyConfiguration, containers, distinctItems, filterItems);
|
GetValidImageItems(propertyConfiguration, containers, distinctItems, filterItems);
|
||||||
static ReadOnlyCollection<Models.Item> GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
|
static ReadOnlyCollection<Models.Item> GetValidImageItems(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<Models.Container> containers, bool distinctItems, bool filterItems) =>
|
||||||
|
8
Shared/Models/Stateless/Methods/IDlibDotNet.cs
Normal file
8
Shared/Models/Stateless/Methods/IDlibDotNet.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
|
public interface IDlibDotNet
|
||||||
|
{
|
||||||
|
|
||||||
|
void Tick();
|
||||||
|
|
||||||
|
}
|
9
Shared/Models/Stateless/Methods/IFaceD.cs
Normal file
9
Shared/Models/Stateless/Methods/IFaceD.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||||
|
|
||||||
|
public interface IFaceD
|
||||||
|
{
|
||||||
|
|
||||||
|
public string FileNameExtension { get; }
|
||||||
|
void ReSaveFace(ExifDirectory exifDirectory, LocationContainer locationContainer, Models.Face face);
|
||||||
|
|
||||||
|
}
|
@ -25,10 +25,10 @@ public interface ILocation
|
|||||||
static Models.Location? GetLocation(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution) =>
|
static Models.Location? GetLocation(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution) =>
|
||||||
Location.GetLocation(databaseFile, marker, outputResolution);
|
Location.GetLocation(databaseFile, marker, outputResolution);
|
||||||
|
|
||||||
List<Models.Location> TestStatic_GetLocations(List<LocationContainer> locationContainers, List<Models.Face> faces, List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, float rectangleIntersectMinimum) =>
|
List<Models.Location> TestStatic_GetLocations(List<Models.Face> faces, List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, float rectangleIntersectMinimum) =>
|
||||||
GetLocations(locationContainers, faces, mappingFromPhotoPrismCollection, rectangleIntersectMinimum);
|
GetLocations(faces, mappingFromPhotoPrismCollection, rectangleIntersectMinimum);
|
||||||
static List<Models.Location> GetLocations(List<LocationContainer> locationContainers, List<Models.Face> faces, List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, float rectangleIntersectMinimum) =>
|
static List<Models.Location> GetLocations(List<Models.Face> faces, List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, float rectangleIntersectMinimum) =>
|
||||||
Location.GetLocations(locationContainers, faces, mappingFromPhotoPrismCollection, rectangleIntersectMinimum);
|
Location.GetLocations(faces, mappingFromPhotoPrismCollection, rectangleIntersectMinimum);
|
||||||
|
|
||||||
RectangleF? TestStatic_GetPercentagesRectangle(int locationDigits, int wholePercentages) =>
|
RectangleF? TestStatic_GetPercentagesRectangle(int locationDigits, int wholePercentages) =>
|
||||||
GetPercentagesRectangle(locationDigits, wholePercentages);
|
GetPercentagesRectangle(locationDigits, wholePercentages);
|
||||||
|
@ -245,7 +245,7 @@ internal abstract class Location
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static List<Models.Location> GetLocations(List<LocationContainer> locationContainers, List<Models.Face> faces, List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, float rectangleIntersectMinimum)
|
internal static List<Models.Location> GetLocations(List<Models.Face> faces, List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, float rectangleIntersectMinimum)
|
||||||
{
|
{
|
||||||
List<Models.Location> results = [];
|
List<Models.Location> results = [];
|
||||||
bool any;
|
bool any;
|
||||||
@ -266,12 +266,6 @@ internal abstract class Location
|
|||||||
outputResolution ??= face.OutputResolution;
|
outputResolution ??= face.OutputResolution;
|
||||||
}
|
}
|
||||||
int before = results.Count;
|
int before = results.Count;
|
||||||
foreach (LocationContainer locationContainer in locationContainers)
|
|
||||||
{
|
|
||||||
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)
|
||||||
@ -289,19 +283,6 @@ 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 locationContainer in locationContainers)
|
|
||||||
{
|
|
||||||
if (any)
|
|
||||||
continue;
|
|
||||||
if (locationContainer.Rectangle is null)
|
|
||||||
continue;
|
|
||||||
percent = GetIntersectPercent(prismRectangle.Value, prismArea, locationContainer.Rectangle.Value);
|
|
||||||
if (percent is null || percent < rectangleIntersectMinimum)
|
|
||||||
continue;
|
|
||||||
if (!any)
|
|
||||||
any = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
foreach (Models.Face face in faces)
|
foreach (Models.Face face in faces)
|
||||||
{
|
{
|
||||||
if (any)
|
if (any)
|
||||||
|
@ -147,12 +147,13 @@ internal abstract partial class XDirectory
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static List<FilePair> GetFiles(ReadOnlyCollection<string[]> filesCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, string extension, IReadOnlyDictionary<string, List<string>> compareFileNamesToFiles)
|
internal static List<FilePair> GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, string extension, IReadOnlyDictionary<string, List<string>> compareFileNamesToFiles)
|
||||||
{
|
{
|
||||||
List<FilePair> results = [];
|
List<FilePair> results = [];
|
||||||
string? match;
|
string? match;
|
||||||
string fileName;
|
string fileName;
|
||||||
bool uniqueFileName;
|
bool uniqueFileName;
|
||||||
|
string fileExtension;
|
||||||
List<string>? collection;
|
List<string>? collection;
|
||||||
bool? isNotUniqueAndNeedsReview;
|
bool? isNotUniqueAndNeedsReview;
|
||||||
foreach (string[] files in filesCollection)
|
foreach (string[] files in filesCollection)
|
||||||
@ -161,6 +162,9 @@ internal abstract partial class XDirectory
|
|||||||
{
|
{
|
||||||
isNotUniqueAndNeedsReview = null;
|
isNotUniqueAndNeedsReview = null;
|
||||||
fileName = Path.GetFileName(file);
|
fileName = Path.GetFileName(file);
|
||||||
|
fileExtension = Path.GetExtension(file);
|
||||||
|
if (propertyConfiguration.IgnoreExtensions.Contains(fileExtension))
|
||||||
|
continue;
|
||||||
if (!fileNamesToFiles.TryGetValue(fileName, out collection))
|
if (!fileNamesToFiles.TryGetValue(fileName, out collection))
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
uniqueFileName = collection.Count == 1;
|
uniqueFileName = collection.Count == 1;
|
||||||
@ -260,7 +264,10 @@ internal abstract partial class XDirectory
|
|||||||
continue;
|
continue;
|
||||||
checkFile = file.Replace(find, replace);
|
checkFile = file.Replace(find, replace);
|
||||||
if (File.Exists(checkFile))
|
if (File.Exists(checkFile))
|
||||||
|
{
|
||||||
|
File.Delete(checkFile);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
File.Move(file, checkFile);
|
File.Move(file, checkFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user