PhotoPrism for more locations

This commit is contained in:
Mike Phares 2022-12-25 13:54:17 -07:00
parent a510019c1d
commit 37c7b6760d
31 changed files with 395 additions and 509 deletions

View File

@ -257,7 +257,7 @@ public partial class E_Distance
{ {
useOldWay = i == 1; 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); 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(sourceRectangle, checkRectangle); intersectRectangle = System.Drawing.Rectangle.Intersect(checkRectangle, sourceRectangle);
if (intersectRectangle.Width == 0 || intersectRectangle.Height == 0) if (intersectRectangle.Width == 0 || intersectRectangle.Height == 0)
continue; continue;
percent = (double)intersectRectangle.Width * intersectRectangle.Height / (checkRectangle.Width * checkRectangle.Height); percent = (double)intersectRectangle.Width * intersectRectangle.Height / (checkRectangle.Width * checkRectangle.Height);

View File

@ -179,8 +179,11 @@ public partial class Form : System.Windows.Forms.Form
_ProgressBar.Step = 1; _ProgressBar.Step = 1;
bool isIgnoreExtension; bool isIgnoreExtension;
_ProgressBar.Value = 0; _ProgressBar.Value = 0;
string checkFileExtension;
bool skipOneAllAreNumbers; bool skipOneAllAreNumbers;
DateTime? minimumDateTime; DateTime? minimumDateTime;
const string jpg = ".jpg";
const string jpeg = ".jpeg";
_ProgressBar.Visible = true; _ProgressBar.Visible = true;
bool isValidImageFormatExtension; bool isValidImageFormatExtension;
string? extraLargeBitmapThumbnail; string? extraLargeBitmapThumbnail;
@ -201,7 +204,15 @@ public partial class Form : System.Windows.Forms.Form
{ {
skipOneAllAreNumbers = fileHolder.NameWithoutExtension[1..].All(l => char.IsNumber(l)); skipOneAllAreNumbers = fileHolder.NameWithoutExtension[1..].All(l => char.IsNumber(l));
if ((skipOneAllAreNumbers && fileHolder.NameWithoutExtension[0] == '-') || (skipOneAllAreNumbers && char.IsNumber(fileHolder.NameWithoutExtension[0]))) if ((skipOneAllAreNumbers && fileHolder.NameWithoutExtension[0] == '-') || (skipOneAllAreNumbers && char.IsNumber(fileHolder.NameWithoutExtension[0])))
{
if (fileHolder.ExtensionLowered == jpeg)
{
if (File.Exists($"{fileHolder.FullName}.id"))
File.Move($"{fileHolder.FullName}.id", Path.Combine(fileHolder.DirectoryName, $"{fileHolder.NameWithoutExtension}{jpg}.id"));
File.Move(fileHolder.FullName, Path.Combine(fileHolder.DirectoryName, $"{fileHolder.NameWithoutExtension}{jpg}"));
}
continue; continue;
}
} }
if (!isIgnoreExtension && isValidImageFormatExtension) if (!isIgnoreExtension && isValidImageFormatExtension)
extraLargeBitmapThumbnail = null; extraLargeBitmapThumbnail = null;
@ -224,7 +235,8 @@ public partial class Form : System.Windows.Forms.Form
dateTime = IProperty.GetDateTimeFromName(fileHolder); dateTime = IProperty.GetDateTimeFromName(fileHolder);
if (dateTime is not null && minimumDateTime is not null && new TimeSpan(Math.Abs(minimumDateTime.Value.Ticks - dateTime.Value.Ticks)).TotalMinutes > 2) if (dateTime is not null && minimumDateTime is not null && new TimeSpan(Math.Abs(minimumDateTime.Value.Ticks - dateTime.Value.Ticks)).TotalMinutes > 2)
{ {
checkFile = Path.Combine(fileHolder.DirectoryName, $"{dateTime.Value:yyyy-MM-dd}.{dateTime.Value.Ticks}{fileHolder.ExtensionLowered}"); checkFileExtension = fileHolder.ExtensionLowered == jpeg ? jpg : fileHolder.ExtensionLowered;
checkFile = Path.Combine(fileHolder.DirectoryName, $"{dateTime.Value:yyyy-MM-dd}.{dateTime.Value.Ticks}{checkFileExtension}");
if (checkFile == fileHolder.FullName || File.Exists(checkFile)) if (checkFile == fileHolder.FullName || File.Exists(checkFile))
continue; continue;
File.Move(fileHolder.FullName, checkFile); File.Move(fileHolder.FullName, checkFile);
@ -238,7 +250,8 @@ public partial class Form : System.Windows.Forms.Form
if (fileHolder.DirectoryName is null) if (fileHolder.DirectoryName is null)
continue; continue;
} }
checkFile = Path.Combine(fileHolder.DirectoryName, $"{id.Value}{fileHolder.ExtensionLowered}"); checkFileExtension = fileHolder.ExtensionLowered == jpeg ? jpg : fileHolder.ExtensionLowered;
checkFile = Path.Combine(fileHolder.DirectoryName, $"{id.Value}{checkFileExtension}");
if (checkFile == fileHolder.FullName || File.Exists(checkFile)) if (checkFile == fileHolder.FullName || File.Exists(checkFile))
continue; continue;
File.Move(fileHolder.FullName, checkFile); File.Move(fileHolder.FullName, checkFile);

View File

@ -43,7 +43,6 @@ public class D_Face
private readonly int _FaceDistanceHiddenImageFactor; private readonly int _FaceDistanceHiddenImageFactor;
private readonly EncoderParameters _EncoderParameters; private readonly EncoderParameters _EncoderParameters;
private readonly ImageCodecInfo _HiddenImageCodecInfo; private readonly ImageCodecInfo _HiddenImageCodecInfo;
private readonly bool _RetryImagesWithoutAFaceLocation;
private readonly bool _ForceFaceLastWriteTimeToCreationTime; private readonly bool _ForceFaceLastWriteTimeToCreationTime;
private readonly EncoderParameters _HiddenEncoderParameters; private readonly EncoderParameters _HiddenEncoderParameters;
private readonly JsonSerializerOptions _WriteIndentedAndWhenWritingNull; private readonly JsonSerializerOptions _WriteIndentedAndWhenWritingNull;
@ -63,7 +62,6 @@ public class D_Face
string modelDirectory, string modelDirectory,
string modelName, string modelName,
bool overrideForFaceImages, bool overrideForFaceImages,
bool retryImagesWithoutAFaceLocation,
string predictorModelName, string predictorModelName,
bool propertiesChangedForFaces) bool propertiesChangedForFaces)
{ {
@ -81,7 +79,6 @@ public class D_Face
_CheckDFaceAndUpWriteDates = checkDFaceAndUpWriteDates; _CheckDFaceAndUpWriteDates = checkDFaceAndUpWriteDates;
_PropertiesChangedForFaces = propertiesChangedForFaces; _PropertiesChangedForFaces = propertiesChangedForFaces;
_FaceDistanceHiddenImageFactor = faceDistanceHiddenImageFactor; _FaceDistanceHiddenImageFactor = faceDistanceHiddenImageFactor;
_RetryImagesWithoutAFaceLocation = retryImagesWithoutAFaceLocation;
_ForceFaceLastWriteTimeToCreationTime = forceFaceLastWriteTimeToCreationTime; _ForceFaceLastWriteTimeToCreationTime = forceFaceLastWriteTimeToCreationTime;
(Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(modelDirectory, modelName, predictorModelName); (Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(modelDirectory, modelName, predictorModelName);
_Model = model; _Model = model;
@ -215,7 +212,7 @@ public class D_Face
} }
} }
private List<Shared.Models.Face> GetFaces(Shared.Models.Property property, MappingFromItem mappingFromItem, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) private List<Shared.Models.Face> GetFaces(Shared.Models.Property property, MappingFromItem mappingFromItem, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, List<Location> locations)
{ {
if (_Log is null) if (_Log is null)
throw new NullReferenceException(nameof(_Log)); throw new NullReferenceException(nameof(_Log));
@ -225,25 +222,18 @@ public class D_Face
throw new NullReferenceException(nameof(_Configuration.NumberOfTimesToUpsample)); throw new NullReferenceException(nameof(_Configuration.NumberOfTimesToUpsample));
List<Shared.Models.Face> results = new(); List<Shared.Models.Face> results = new();
FaceRecognitionDotNet.Image? unknownImage; FaceRecognitionDotNet.Image? unknownImage;
if (!mappingFromItem.ResizedFileHolder.Exists) try
unknownImage = null; { unknownImage = FaceRecognition.LoadImageFile(mappingFromItem.ResizedFileHolder.FullName); }
else catch (Exception)
{ {
try unknownImage = null;
{ unknownImage = FaceRecognition.LoadImageFile(mappingFromItem.ResizedFileHolder.FullName); } _Log.Info(string.Concat(new StackFrame().GetMethod()?.Name, " <", mappingFromItem.ResizedFileHolder.FullName, ">"));
catch (Exception)
{
unknownImage = null;
_Log.Info(string.Concat(new StackFrame().GetMethod()?.Name, " <", mappingFromItem.ResizedFileHolder.FullName, ">"));
}
} }
if (unknownImage is null) if (unknownImage is not null)
results.Add(new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, location: null));
else
{ {
List<(Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary<FacePart, FacePoint[]>? FaceParts)> collection; List<(Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary<FacePart, FacePoint[]>? FaceParts)> collection;
FaceRecognition faceRecognition = new(_Configuration.NumberOfJitters.Value, _Configuration.NumberOfTimesToUpsample.Value, _Model, _ModelParameter, _PredictorModel); FaceRecognition faceRecognition = new(_Configuration.NumberOfJitters.Value, _Configuration.NumberOfTimesToUpsample.Value, _Model, _ModelParameter, _PredictorModel);
collection = faceRecognition.GetCollection(unknownImage, includeFaceEncoding: true, includeFaceParts: true); collection = faceRecognition.GetCollection(unknownImage, locations, includeFaceEncoding: true, includeFaceParts: true);
if (!collection.Any()) if (!collection.Any())
results.Add(new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, location: null)); results.Add(new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, location: null));
else else
@ -268,8 +258,6 @@ public class D_Face
unknownImage.Dispose(); unknownImage.Dispose();
faceRecognition.Dispose(); faceRecognition.Dispose();
} }
if (!results.Any())
throw new Exception();
return results; return results;
} }
@ -303,12 +291,13 @@ public class D_Face
#pragma warning restore CA1416 #pragma warning restore CA1416
public List<Shared.Models.Face> GetFaces(string dResultsFullGroupDirectory, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) 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)
{ {
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 = new();
string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize) }; string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize) };
List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList();
string dCollectionFile = Path.Combine(dResultsFullGroupDirectory, "[]", _Configuration.ResultAllInOne, $"{mappingFromItem.Id}{mappingFromItem.ImageFileHolder.ExtensionLowered}.json"); string dCollectionFile = Path.Combine(dResultsFullGroupDirectory, "[]", _Configuration.ResultAllInOne, $"{mappingFromItem.Id}{mappingFromItem.ImageFileHolder.ExtensionLowered}.json");
@ -345,18 +334,21 @@ public class D_Face
parseExceptions.Add(nameof(D_Face)); parseExceptions.Add(nameof(D_Face));
} }
} }
if (results is null || (_RetryImagesWithoutAFaceLocation && results.Count == 1 && results[0].Location is null)) if (mappingFromPhotoPrismCollection is not null && results is not null)
locations.AddRange(Shared.Models.Stateless.Methods.ILocation.GetLocations(mappingFromPhotoPrismCollection, results));
if (results is null || locations.Any())
{ {
bool wasNull = results is null; results = GetFaces(property, mappingFromItem, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, locations);
results = GetFaces(property, mappingFromItem, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation); if (!results.Any())
if (wasNull || (!wasNull && results.Any(l => l.Location is not null))) File.Move(mappingFromItem.ResizedFileHolder.FullName, $"{mappingFromItem.ResizedFileHolder.FullName}.err");
else
{ {
json = JsonSerializer.Serialize(results, _WriteIndentedAndWhenWritingNull); json = JsonSerializer.Serialize(results, _WriteIndentedAndWhenWritingNull);
bool updateDateWhenMatches = dateTimes.Any() && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime; bool updateDateWhenMatches = dateTimes.Any() && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime;
DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime))
{ {
if (!_ForceFaceLastWriteTimeToCreationTime && (!fileInfo.Exists || fileInfo.LastWriteTime == fileInfo.CreationTime)) if (!_ForceFaceLastWriteTimeToCreationTime)
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), DateTime.Now)); subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), DateTime.Now));
else else
{ {
@ -370,126 +362,6 @@ public class D_Face
return results; return results;
} }
private void WriteAllText(Dictionary<string, List<RelativeLocation>>? results, List<DateTime> dateTimes, FileInfo fileInfo)
{
string json = JsonSerializer.Serialize(results, _WriteIndentedAndWhenWritingNull);
bool updateDateWhenMatches = dateTimes.Any() && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime;
DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime))
{
if (!_ForceFaceLastWriteTimeToCreationTime && (!fileInfo.Exists || fileInfo.LastWriteTime == fileInfo.CreationTime))
; // subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), DateTime.Now));
else
{
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
fileInfo.Refresh();
// subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), fileInfo.CreationTime));
}
}
}
public Dictionary<string, List<RelativeLocation>> GetRelativeLocations(string outputResolution, string dResultsDateGroupDirectory, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, string original, Dictionary<string, int[]> imageResizeKeyValuePairs, List<Shared.Models.Face> faces)
{
Dictionary<string, List<RelativeLocation>>? results;
if (string.IsNullOrEmpty(dResultsDateGroupDirectory))
throw new NullReferenceException(nameof(dResultsDateGroupDirectory));
if (!imageResizeKeyValuePairs.ContainsKey(original))
throw new Exception();
if (!imageResizeKeyValuePairs.ContainsKey(outputResolution))
throw new Exception();
string json;
decimal? h, l, t, w;
RelativeLocation relativeLocation;
List<RelativeLocation> relativeLocations = new();
int[] resize = imageResizeKeyValuePairs[outputResolution];
string key = $"{resize[0].ToString().PadLeft(6, '0')}.{resize[1].ToString().PadLeft(6, '0')}";
string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize), nameof(D_Face) };
List<DateTime> dateTimes = (from d in subFileTuples where changesFrom.Contains(d.Item1) select d.Item2).ToList();
string dCollectionDirectory = Path.Combine(dResultsDateGroupDirectory, "[]", _Configuration.ResultAllInOne);
string dCollectionFile = Path.Combine(dCollectionDirectory, $"{mappingFromItem.Id}{mappingFromItem.ImageFileHolder.ExtensionLowered}.json");
if (!Directory.Exists(dCollectionDirectory))
_ = Directory.CreateDirectory(dCollectionDirectory);
FileInfo fileInfo = new(dCollectionFile);
if (_ForceFaceLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete")))
{
File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName);
fileInfo.Refresh();
}
if (_ForceFaceLastWriteTimeToCreationTime && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime)
{
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
fileInfo.Refresh();
}
if (_PropertiesChangedForFaces)
results = null;
else if (!fileInfo.Exists)
results = null;
else if (_CheckDFaceAndUpWriteDates && dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime)
results = null;
else
{
json = Shared.Models.Stateless.Methods.IFace.GetJson(fileInfo.FullName);
try
{
results = JsonSerializer.Deserialize<Dictionary<string, List<RelativeLocation>>>(json);
if (results is null)
throw new NullReferenceException(nameof(results));
bool added = false;
relativeLocations.Clear();
foreach (KeyValuePair<string, List<RelativeLocation>> keyValuePair in results)
relativeLocations.AddRange(keyValuePair.Value);
if (!results.ContainsKey(key))
results.Add(key, new());
foreach (Shared.Models.Face face in faces)
{
if (face.Location is null || face.OutputResolution is null)
continue;
(h, l, t, w) = Shared.Models.Stateless.Methods.ILocation.GetHeightLeftTopWidth(face.Location, face.OutputResolution);
if (h is null || l is null || t is null || w is null)
continue;
relativeLocation = new(face.Location.Confidence, h.Value.ToString(), l.Value.ToString(), t.Value.ToString(), w.Value.ToString());
if (relativeLocations.Any(r => r.Match(h, l, t, w)))
continue;
if (!added)
added = true;
results[key].Add(relativeLocation);
}
if (added)
{
List<(string Key, List<RelativeLocation> Value)> sort = new();
foreach (KeyValuePair<string, List<RelativeLocation>> keyValuePair in results)
sort.Add(new(keyValuePair.Key, keyValuePair.Value));
results.Clear();
foreach ((string k, List<RelativeLocation> v) in sort.OrderBy(l => l.Key))
results.Add(k, v.OrderByDescending(l => l.Confidence).ToList());
WriteAllText(results, dateTimes, fileInfo);
}
// subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), fileInfo.LastWriteTime));
}
catch (Exception)
{
results = null;
parseExceptions.Add(nameof(D_Face));
}
}
if (results is null)
{
results = new() { { key, new() } };
foreach (Shared.Models.Face face in faces)
{
if (face.Location is null || face.OutputResolution is null)
continue;
(h, l, t, w) = Shared.Models.Stateless.Methods.ILocation.GetHeightLeftTopWidth(face.Location, face.OutputResolution);
if (h is null || l is null || t is null || w is null)
continue;
relativeLocation = new(face.Location.Confidence, h.Value.ToString(), l.Value.ToString(), t.Value.ToString(), w.Value.ToString());
results[key].Add(relativeLocation);
}
WriteAllText(results, dateTimes, fileInfo);
}
return results;
}
public bool SaveFaces(string dResultsFullGroupDirectory, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, string facesDirectory, List<Shared.Models.Face> faces) public bool SaveFaces(string dResultsFullGroupDirectory, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, string facesDirectory, List<Shared.Models.Face> faces)
{ {
FileInfo fileInfo; FileInfo fileInfo;

View File

@ -198,7 +198,7 @@ public class FaceRecognition : DisposableObject
return results; return results;
} }
public List<(Location, FaceEncoding?, Dictionary<FacePart, FacePoint[]>?)> GetCollection(Image image, 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 = new(); List<(Location, FaceEncoding?, Dictionary<FacePart, FacePoint[]>?)> results = new();
if (image is null) if (image is null)
@ -207,7 +207,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.");
List<Location> locations = 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)
throw new Exception(); throw new Exception();

View File

@ -33,9 +33,11 @@ public partial class DlibDotNet
private readonly List<string> _Exceptions; private readonly List<string> _Exceptions;
private readonly IsEnvironment _IsEnvironment; private readonly IsEnvironment _IsEnvironment;
private readonly bool _PropertyRootExistedBefore; private readonly bool _PropertyRootExistedBefore;
private readonly PersonContainer[] _PersonContainers;
private readonly Models.Configuration _Configuration; private readonly Models.Configuration _Configuration;
private readonly bool _ArgZeroIsConfigurationRootDirectory; private readonly bool _ArgZeroIsConfigurationRootDirectory;
private readonly Map.Models.Configuration _MapConfiguration; private readonly Map.Models.Configuration _MapConfiguration;
private readonly Dictionary<string, List<MappingFromPhotoPrism>> _FileNameToCollection;
public DlibDotNet( public DlibDotNet(
List<string> args, List<string> args,
@ -46,13 +48,13 @@ public partial class DlibDotNet
bool isSilent, bool isSilent,
IConsole console) IConsole console)
{ {
_Console = console;
string message; string message;
_Console = console;
_AppSettings = appSettings; _AppSettings = appSettings;
_FileNameToCollection = new();
_IsEnvironment = isEnvironment; _IsEnvironment = isEnvironment;
long ticks = DateTime.Now.Ticks; long ticks = DateTime.Now.Ticks;
_Exceptions = new List<string>(); _Exceptions = new List<string>();
PersonContainer[] personContainers;
_Log = Serilog.Log.ForContext<DlibDotNet>(); _Log = Serilog.Log.ForContext<DlibDotNet>();
Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot);
Models.Configuration configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration); Models.Configuration configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration);
@ -94,7 +96,6 @@ public partial class DlibDotNet
configuration.ModelDirectory, configuration.ModelDirectory,
configuration.ModelName, configuration.ModelName,
configuration.OverrideForFaceImages, configuration.OverrideForFaceImages,
configuration.RetryImagesWithoutAFaceLocation,
configuration.PredictorModelName, configuration.PredictorModelName,
configuration.PropertiesChangedForFaces); configuration.PropertiesChangedForFaces);
} }
@ -106,7 +107,7 @@ public partial class DlibDotNet
_MapConfiguration = Get(configuration, _Faces.FileNameExtension, _Faces.HiddenFileNameExtension, _FaceParts.FileNameExtension); _MapConfiguration = Get(configuration, _Faces.FileNameExtension, _Faces.HiddenFileNameExtension, _FaceParts.FileNameExtension);
_Distance = new(configuration.DistanceMoveUnableToMatch, configuration.DistanceRenameToMatch, _Configuration.FaceConfidencePercent, configuration.RangeDistanceTolerance, configuration.RangeFaceConfidence); _Distance = new(configuration.DistanceMoveUnableToMatch, configuration.DistanceRenameToMatch, _Configuration.FaceConfidencePercent, configuration.RangeDistanceTolerance, configuration.RangeFaceConfidence);
if (_PropertyRootExistedBefore || !_ArgZeroIsConfigurationRootDirectory) if (_PropertyRootExistedBefore || !_ArgZeroIsConfigurationRootDirectory)
personContainers = Array.Empty<PersonContainer>(); _PersonContainers = Array.Empty<PersonContainer>();
else else
{ {
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
@ -120,7 +121,7 @@ public partial class DlibDotNet
if (rootResultsDirectory is null) if (rootResultsDirectory is null)
throw new Exception(); throw new Exception();
Storage storage = new(rootDirectory, rootResultsDirectory, peopleRootDirectory); Storage storage = new(rootDirectory, rootResultsDirectory, peopleRootDirectory);
personContainers = Shared.Models.Stateless.Methods.IPersonContainer.GetPersonContainers(storage, configuration.PersonBirthdayFormat, _Faces.FileNameExtension); _PersonContainers = Shared.Models.Stateless.Methods.IPersonContainer.GetPersonContainers(storage, configuration.PersonBirthdayFormat, _Faces.FileNameExtension);
} }
if (!isSilent && configuration.TestDistanceResults) if (!isSilent && configuration.TestDistanceResults)
{ {
@ -142,7 +143,7 @@ public partial class DlibDotNet
filenameExtension); filenameExtension);
} }
if (!configuration.SkipSearch) if (!configuration.SkipSearch)
Search(ticks, argZero, propertyRoot, personContainers); Search(ticks, argZero, propertyRoot);
if (!_PropertyRootExistedBefore && !_IsEnvironment.Development && _Exceptions.Count == 0 && _ArgZeroIsConfigurationRootDirectory) if (!_PropertyRootExistedBefore && !_IsEnvironment.Development && _Exceptions.Count == 0 && _ArgZeroIsConfigurationRootDirectory)
{ {
List<string[]> directoryCollections = _Rename.GetDirectoryRenameCollections( List<string[]> directoryCollections = _Rename.GetDirectoryRenameCollections(
@ -205,7 +206,7 @@ public partial class DlibDotNet
private void Verify(Models.Configuration configuration) private void Verify(Models.Configuration configuration)
{ {
if (!configuration.OutputResolutions.Any() || string.IsNullOrEmpty(configuration.OutputResolutions[0]) || !configuration.ValidResolutions.Contains(configuration.OutputResolutions[0])) if (!configuration.OutputResolutions.Any() || string.IsNullOrEmpty(configuration.OutputResolutions[0]) || !configuration.ValidResolutions.Contains(configuration.OutputResolutions[0]))
throw new NullReferenceException($"{nameof(configuration.OutputResolutions)} must be a valid outputResolution!"); throw new NullReferenceException($"{nameof(configuration.OutputResolutions)} must be _FileNameToCollection valid outputResolution!");
if ((from l in configuration.OutputResolutions where !configuration.ValidResolutions.Contains(l) select false).Any()) if ((from l in configuration.OutputResolutions where !configuration.ValidResolutions.Contains(l) select false).Any())
throw new Exception($"One or more {nameof(configuration.OutputResolutions)} are not in the ValidResolutions list!"); throw new Exception($"One or more {nameof(configuration.OutputResolutions)} are not in the ValidResolutions list!");
if ((from l in configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions where !configuration.ValidResolutions.Contains(l) select false).Any()) if ((from l in configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions where !configuration.ValidResolutions.Contains(l) select false).Any())
@ -249,13 +250,13 @@ public partial class DlibDotNet
string[] segments = sourceDirectoryNames[0].Split(' '); string[] segments = sourceDirectoryNames[0].Split(' ');
century = segments[^1].Length == 4 ? segments[^1][..2] : null; century = segments[^1].Length == 4 ? segments[^1][..2] : null;
if (segments.Length < 2 || century is null || (century != "18" && century != "19" && century != "20")) if (segments.Length < 2 || century is null || (century != "18" && century != "19" && century != "20"))
throw new Exception("root subdirectory must have a year at the end or directory name needs to be added to the exclude list!"); throw new Exception("root subdirectory must have _FileNameToCollection year at the end or directory name needs to be added to the exclude list!");
} }
} }
} }
string[] resizeMatch = (from l in sourceDirectoryNames where configuration.ValidResolutions.Contains(l) select l).ToArray(); string[] resizeMatch = (from l in sourceDirectoryNames where configuration.ValidResolutions.Contains(l) select l).ToArray();
if (resizeMatch.Any()) if (resizeMatch.Any())
throw new Exception("Input directory should be the source and not a resized directory!"); throw new Exception("Input directory should be the source and not _FileNameToCollection resized directory!");
if (configuration.LocationDigits != Shared.Models.Stateless.ILocation.Digits) if (configuration.LocationDigits != Shared.Models.Stateless.ILocation.Digits)
throw new Exception("Configuration has to match interface!"); throw new Exception("Configuration has to match interface!");
if (configuration.LocationFactor != Shared.Models.Stateless.ILocation.Factor) if (configuration.LocationFactor != Shared.Models.Stateless.ILocation.Factor)
@ -294,7 +295,6 @@ public partial class DlibDotNet
Dictionary<string, int[]> imageResizeKeyValuePairs; Dictionary<string, int[]> imageResizeKeyValuePairs;
List<Tuple<string, DateTime>> subFileTuples = new(); List<Tuple<string, DateTime>> subFileTuples = new();
List<KeyValuePair<string, string>> metadataCollection; List<KeyValuePair<string, string>> metadataCollection;
// Dictionary<string, List<RelativeLocation>> relativeLocations;
if (item.Property is not null && item.Property.Id is not null && !item.Any()) if (item.Property is not null && item.Property.Id is not null && !item.Any())
{ {
property = item.Property; property = item.Property;
@ -354,17 +354,21 @@ public partial class DlibDotNet
string path = Path.Combine(resizedFileHolder.DirectoryName, resizedFileHolder.NameWithoutExtension); string path = Path.Combine(resizedFileHolder.DirectoryName, resizedFileHolder.NameWithoutExtension);
File.WriteAllBytes(path, bytes); File.WriteAllBytes(path, bytes);
} }
if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution)) if (!mappingFromItem.ResizedFileHolder.Exists && !File.Exists(mappingFromItem.ResizedFileHolder.FullName))
faces = new();
else if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution))
faces = new(); faces = new();
else else
{ {
List<(string, int, IReadOnlyList<MetadataExtractor.Directory>?)>? collection;
int[] outputResolutionCollection = imageResizeKeyValuePairs[outputResolution]; int[] outputResolutionCollection = imageResizeKeyValuePairs[outputResolution];
int outputResolutionWidth = outputResolutionCollection[0]; int outputResolutionWidth = outputResolutionCollection[0];
int outputResolutionHeight = outputResolutionCollection[1]; int outputResolutionHeight = outputResolutionCollection[1];
int outputResolutionOrientation = outputResolutionCollection[2]; int outputResolutionOrientation = outputResolutionCollection[2];
faces = _Faces.GetFaces(dResultsFullGroupDirectory, subFileTuples, parseExceptions, property, mappingFromItem, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation); List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection;
// relativeLocations = _Faces.GetRelativeLocations(outputResolution, dResultsDateGroupDirectory, subFileTuples, parseExceptions, property, mappingFromItem, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, original, imageResizeKeyValuePairs, faces); List<(string, int, IReadOnlyList<MetadataExtractor.Directory>?)>? collection;
if (!_FileNameToCollection.TryGetValue(mappingFromItem.RelativePath[1..], out mappingFromPhotoPrismCollection))
mappingFromPhotoPrismCollection = null;
faces = _Faces.GetFaces(dResultsFullGroupDirectory, subFileTuples, parseExceptions, property, mappingFromItem, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, mappingFromPhotoPrismCollection);
if (_AppSettings.MaxDegreeOfParallelism < 2) if (_AppSettings.MaxDegreeOfParallelism < 2)
ticks = LogDelta(ticks, nameof(D_Face.GetFaces)); ticks = LogDelta(ticks, nameof(D_Face.GetFaces));
bool anyFacesSaved = _Faces.SaveFaces(dResultsFullGroupDirectory, subFileTuples, parseExceptions, mappingFromItem, facesDirectory, faces); bool anyFacesSaved = _Faces.SaveFaces(dResultsFullGroupDirectory, subFileTuples, parseExceptions, mappingFromItem, facesDirectory, faces);
@ -439,25 +443,24 @@ public partial class DlibDotNet
{ {
try try
{ {
FullParallelForWork( FullParallelForWork(propertyLogic,
propertyLogic, idToMappedFaceFilesWithCollection,
idToMappedFaceFilesWithCollection, outputResolution,
outputResolution, bResultsFullGroupDirectory,
bResultsFullGroupDirectory, cResultsFullGroupDirectory,
cResultsFullGroupDirectory, dResultsDateGroupDirectory,
dResultsDateGroupDirectory, dResultsFullGroupDirectory,
dResultsFullGroupDirectory, eDistanceContentDirectory,
eDistanceContentDirectory, sourceDirectoryChanges,
sourceDirectoryChanges, propertyFileHolderCollection,
propertyFileHolderCollection, propertyCollection,
propertyCollection, metadataCollection,
metadataCollection, resizeKeyValuePairs,
resizeKeyValuePairs, imageFaceCollections,
imageFaceCollections, container,
container, index: i,
index: i, filteredItems[i],
filteredItems[i], containerDateTimes);
containerDateTimes);
if (i == 0 || sourceDirectoryChanges.Any()) if (i == 0 || sourceDirectoryChanges.Any())
progressBar.Tick(); progressBar.Tick();
} }
@ -627,7 +630,7 @@ public partial class DlibDotNet
_Metadata.SetAngleBracketCollection(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, container.SourceDirectory); _Metadata.SetAngleBracketCollection(_Configuration.PropertyConfiguration, bResultsFullGroupDirectory, container.SourceDirectory);
} }
private void FullDoWork(string argZero, string propertyRoot, long ticks, PersonContainer[] personContainers, A_Property propertyLogic, int t, Container[] containers, string? a2PeopleContentDirectory, string eDistanceContentDirectory) private void FullDoWork(string argZero, string propertyRoot, long ticks, A_Property propertyLogic, int t, Container[] containers, string? a2PeopleContentDirectory, string eDistanceContentDirectory)
{ {
if (_Log is null) if (_Log is null)
throw new NullReferenceException(nameof(_Log)); throw new NullReferenceException(nameof(_Log));
@ -651,7 +654,7 @@ public partial class DlibDotNet
int maxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism; int maxDegreeOfParallelism = _AppSettings.MaxDegreeOfParallelism;
List<Shared.Models.Property?> nullablePropertyCollection = new(); List<Shared.Models.Property?> nullablePropertyCollection = new();
List<List<KeyValuePair<string, string>>> metadataCollection = new(); List<List<KeyValuePair<string, string>>> metadataCollection = new();
Dictionary<int, List<(string, int, IReadOnlyList<MetadataExtractor.Directory>?)>> idToMappedFaceFilesWithCollection = GetCollection(ticks, personContainers, a2PeopleContentDirectory, eDistanceContentDirectory); Dictionary<int, List<(string, int, IReadOnlyList<MetadataExtractor.Directory>?)>> idToMappedFaceFilesWithCollection = GetCollection(ticks, a2PeopleContentDirectory, eDistanceContentDirectory);
string dResultsDateGroupDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(D_Face)); string dResultsDateGroupDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(D_Face));
foreach (string outputResolution in _Configuration.OutputResolutions) foreach (string outputResolution in _Configuration.OutputResolutions)
{ {
@ -739,7 +742,7 @@ public partial class DlibDotNet
} }
} }
private void SetMapping(string argZero, Container[] containers) private void SetMapping(Dictionary<string, List<MappingFromPhotoPrism>> fileNameToCollection, string argZero, Container[] containers)
{ {
Mapping mapping; Mapping mapping;
int faceAreaPermille; int faceAreaPermille;
@ -751,6 +754,7 @@ public partial class DlibDotNet
string deterministicHashCodeKey; string deterministicHashCodeKey;
MappingFromItem mappingFromItem; MappingFromItem mappingFromItem;
MappingFromLocation mappingFromLocation; MappingFromLocation mappingFromLocation;
List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection;
foreach (Container container in containers) foreach (Container container in containers)
{ {
if (!container.Items.Any()) if (!container.Items.Any())
@ -776,7 +780,9 @@ public partial class DlibDotNet
normalizedRectangle = Shared.Models.Stateless.Methods.ILocation.GetNormalizedRectangle(face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); normalizedRectangle = Shared.Models.Stateless.Methods.ILocation.GetNormalizedRectangle(face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution); deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item.Property.Id.Value, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
mappingFromLocation = new(faceAreaPermille, confidencePercent, deterministicHashCodeKey, normalizedRectangle); mappingFromLocation = new(faceAreaPermille, confidencePercent, deterministicHashCodeKey, normalizedRectangle);
mapping = new(mappingFromItem, mappingFromLocation); if (!fileNameToCollection.TryGetValue(mappingFromItem.RelativePath[1..], out mappingFromPhotoPrismCollection))
mappingFromPhotoPrismCollection = null;
mapping = new(mappingFromItem, mappingFromLocation, mappingFromPhotoPrismCollection);
face.SetMapping(mapping); face.SetMapping(mapping);
} }
} }
@ -847,7 +853,7 @@ public partial class DlibDotNet
return items; return items;
} }
private void MapLogic(string argZero, long ticks, PersonContainer[] personContainers, Container[] containers, string a2PeopleSingletonDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, MapLogicSupport mapLogicSupport, MapLogic mapLogic, string outputResolution) private void MapLogic(string argZero, long ticks, Container[] containers, string a2PeopleSingletonDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, MapLogicSupport mapLogicSupport, MapLogic mapLogic, string outputResolution)
{ {
int? useFiltersCounter = null; int? useFiltersCounter = null;
SortingContainer[] sortingContainers; SortingContainer[] sortingContainers;
@ -857,17 +863,12 @@ public partial class DlibDotNet
Mapping[] mappingCollection = MapLogicSupport.GetSelectedMappingCollection(distinctFilteredFaces); Mapping[] mappingCollection = MapLogicSupport.GetSelectedMappingCollection(distinctFilteredFaces);
string dFacesCollectionDirectory = Path.Combine(dResultsFullGroupDirectory, "[]", _Configuration.PropertyConfiguration.ResultAllInOne); string dFacesCollectionDirectory = Path.Combine(dResultsFullGroupDirectory, "[]", _Configuration.PropertyConfiguration.ResultAllInOne);
(Dictionary<long, int> personKeyToCount, int totalNotMapped) = mapLogic.AddToMapping(mappingCollection); (Dictionary<long, int> personKeyToCount, int totalNotMapped) = mapLogic.AddToMapping(mappingCollection);
if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution) || (!string.IsNullOrEmpty(_Configuration.PhotoPrismDirectory) && Directory.Exists(_Configuration.PhotoPrismDirectory))) if (!string.IsNullOrEmpty(_Configuration.PhotoPrismDirectory) && Directory.Exists(_Configuration.PhotoPrismDirectory))
mapLogic.WriteMatches(ticks, distinctFilteredFaces);
if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution))
{ {
List<Item> filteredItems = GetItems(argZero, containers); List<Item> filteredItems = GetItems(argZero, containers);
if (!string.IsNullOrEmpty(_Configuration.PhotoPrismDirectory)) mapLogic.SaveShortcutsForOutputResolutions(filteredItems, mappingCollection, personKeyToCount);
{
mapLogic.SaveMarkers();
mapLogic.FindMatch(filteredItems);
mapLogic.LoadMatches();
}
if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution))
mapLogic.SaveShortcutsForOutputResolutions(filteredItems, mappingCollection, personKeyToCount);
} }
Dictionary<int, Dictionary<int, Mapping>> idToNormalizedRectangleToMapping = MapLogicSupport.GetIdToNormalizedRectangleToFace(mappingCollection); Dictionary<int, Dictionary<int, Mapping>> idToNormalizedRectangleToMapping = MapLogicSupport.GetIdToNormalizedRectangleToFace(mappingCollection);
mapLogic.CopyManualFiles(dFacesContentDirectory, idToNormalizedRectangleToMapping); mapLogic.CopyManualFiles(dFacesContentDirectory, idToNormalizedRectangleToMapping);
@ -876,7 +877,7 @@ public partial class DlibDotNet
if (_Configuration.SaveMappedForOutputResolutions.Contains(outputResolution)) if (_Configuration.SaveMappedForOutputResolutions.Contains(outputResolution))
mapLogic.SaveMapped(dFacesContentDirectory, d2FacePartsContentDirectory, mappingCollection, idToNormalizedRectangleToMapping, personKeyToCount, totalNotMapped); mapLogic.SaveMapped(dFacesContentDirectory, d2FacePartsContentDirectory, mappingCollection, idToNormalizedRectangleToMapping, personKeyToCount, totalNotMapped);
if (_Configuration.SaveFilteredOriginalImagesFromJLinksForOutputResolutions.Contains(outputResolution)) if (_Configuration.SaveFilteredOriginalImagesFromJLinksForOutputResolutions.Contains(outputResolution))
mapLogic.SaveFilteredOriginalImagesFromJLinks(_Configuration.JLinks, a2PeopleSingletonDirectory, personContainers, mappingCollection, personKeyToCount, totalNotMapped); mapLogic.SaveFilteredOriginalImagesFromJLinks(_Configuration.JLinks, _PersonContainers, a2PeopleSingletonDirectory, mappingCollection, personKeyToCount, totalNotMapped);
if (_Configuration.SaveFaceDistancesForOutputResolutions.Contains(outputResolution)) if (_Configuration.SaveFaceDistancesForOutputResolutions.Contains(outputResolution))
{ {
mapLogic.UpdatedPersonKeyToRanges(_MapConfiguration, ticks, mappingCollection); mapLogic.UpdatedPersonKeyToRanges(_MapConfiguration, ticks, mappingCollection);
@ -952,7 +953,7 @@ public partial class DlibDotNet
bool isValidImageFormatExtension; bool isValidImageFormatExtension;
for (int y = 0; y < int.MaxValue; y++) for (int y = 0; y < int.MaxValue; y++)
{ {
_Log.Information("Enter a url for a image"); _Log.Information("Enter _FileNameToCollection url for _FileNameToCollection image");
line = _Console.ReadLine(); line = _Console.ReadLine();
if (string.IsNullOrEmpty(line)) if (string.IsNullOrEmpty(line))
break; break;
@ -1011,12 +1012,12 @@ public partial class DlibDotNet
collection.Add(new(value.MappedFaceFile, normalizedRectangle.Value, directories)); collection.Add(new(value.MappedFaceFile, normalizedRectangle.Value, directories));
} }
private Dictionary<int, List<(string, int, IReadOnlyList<MetadataExtractor.Directory>?)>> GetCollection(long ticks, PersonContainer[] personContainers, string? a2PeopleContentDirectory, string? eDistanceContentDirectory) private Dictionary<int, List<(string, int, IReadOnlyList<MetadataExtractor.Directory>?)>> GetCollection(long ticks, string? a2PeopleContentDirectory, string? eDistanceContentDirectory)
{ {
Dictionary<int, List<(string, int, IReadOnlyList<MetadataExtractor.Directory>?)>> results = new(); Dictionary<int, List<(string, int, IReadOnlyList<MetadataExtractor.Directory>?)>> results = new();
int? id; int? id;
int? normalizedRectangle; int? normalizedRectangle;
List<(string, string[], string)> collection = Map.Models.Stateless.Methods.IMapLogic.DeleteEmptyDirectoriesAndGetMappedFaceFiles(_MapConfiguration, ticks, a2PeopleContentDirectory, eDistanceContentDirectory, personContainers); List<(string, string[], string)> collection = Map.Models.Stateless.Methods.IMapLogic.DeleteEmptyDirectoriesAndGetMappedFaceFiles(_MapConfiguration, _PersonContainers, ticks, a2PeopleContentDirectory, eDistanceContentDirectory);
foreach ((string personKeyFormatted, string[] personDisplayDirectoryNames, string mappedFaceFile) in collection) foreach ((string personKeyFormatted, string[] personDisplayDirectoryNames, string mappedFaceFile) in collection)
{ {
(id, normalizedRectangle) = Shared.Models.Stateless.Methods.IMapping.GetConverted(_Faces.FileNameExtension, mappedFaceFile); (id, normalizedRectangle) = Shared.Models.Stateless.Methods.IMapping.GetConverted(_Faces.FileNameExtension, mappedFaceFile);
@ -1043,7 +1044,7 @@ public partial class DlibDotNet
return results; return results;
} }
private void Search(long ticks, string argZero, string propertyRoot, PersonContainer[] personContainers) private void Search(long ticks, string argZero, string propertyRoot)
{ {
int j; int j;
int f; int f;
@ -1056,6 +1057,13 @@ public partial class DlibDotNet
string dResultsFullGroupDirectory; string dResultsFullGroupDirectory;
string? eDistanceContentDirectory; string? eDistanceContentDirectory;
string d2ResultsFullGroupDirectory; string d2ResultsFullGroupDirectory;
if (!string.IsNullOrEmpty(_Configuration.PhotoPrismDirectory) && Directory.Exists(_Configuration.PhotoPrismDirectory))
{
Map.Models.MapLogic.SaveMarkers(_Configuration.PhotoPrismDirectory);
Dictionary<string, List<MappingFromPhotoPrism>> fileNameToCollection = Map.Models.MapLogic.GetFileNameToCollection(_Configuration.PhotoPrismDirectory);
foreach (KeyValuePair<string, List<MappingFromPhotoPrism>> keyValuePair in fileNameToCollection)
_FileNameToCollection.Add(keyValuePair.Key, keyValuePair.Value);
}
string a2PeopleSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "{}"); string a2PeopleSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "{}");
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
string message = $") Building Container(s) - {totalSeconds} total second(s)"; string message = $") Building Container(s) - {totalSeconds} total second(s)";
@ -1092,10 +1100,10 @@ public partial class DlibDotNet
} }
containers = Shared.Models.Stateless.Methods.IContainer.SortContainers(_Configuration.PropertyConfiguration, _Configuration.IgnoreRelativePaths, _ArgZeroIsConfigurationRootDirectory, argZero, containers); containers = Shared.Models.Stateless.Methods.IContainer.SortContainers(_Configuration.PropertyConfiguration, _Configuration.IgnoreRelativePaths, _ArgZeroIsConfigurationRootDirectory, argZero, containers);
MapLogicSupport mapLogicSupport = new(_Configuration.FaceConfidencePercent, _Configuration.FaceDistancePermyriad, _Configuration.RangeDaysDeltaTolerance, _Configuration.RangeFaceAreaPermilleTolerance, _Configuration.SortingMaximumPerFaceShouldBeHigh); MapLogicSupport mapLogicSupport = new(_Configuration.FaceConfidencePercent, _Configuration.FaceDistancePermyriad, _Configuration.RangeDaysDeltaTolerance, _Configuration.RangeFaceAreaPermilleTolerance, _Configuration.SortingMaximumPerFaceShouldBeHigh);
MapLogic? mapLogic = _Configuration.DistanceMoveUnableToMatch ? null : new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, ticks, personContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory, mapLogicSupport); MapLogic? mapLogic = _Configuration.DistanceMoveUnableToMatch ? null : new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, ticks, _PersonContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory, mapLogicSupport);
FullDoWork(argZero, propertyRoot, ticks, personContainers, propertyLogic, t, containers, a2PeopleContentDirectory, eDistanceContentDirectory); FullDoWork(argZero, propertyRoot, ticks, propertyLogic, t, containers, a2PeopleContentDirectory, eDistanceContentDirectory);
_Distance.Clear(); _Distance.Clear();
mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, ticks, personContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory, mapLogicSupport); mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, ticks, _PersonContainers, a2PeopleSingletonDirectory, eDistanceContentDirectory, mapLogicSupport);
foreach (string outputResolution in _Configuration.OutputResolutions) foreach (string outputResolution in _Configuration.OutputResolutions)
{ {
if (_PropertyRootExistedBefore || container is not null) if (_PropertyRootExistedBefore || container is not null)
@ -1112,8 +1120,8 @@ public partial class DlibDotNet
{ {
if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Any()) if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Any())
break; break;
SetMapping(argZero, containers); SetMapping(_FileNameToCollection, argZero, containers);
MapLogic(argZero, ticks, personContainers, containers, a2PeopleSingletonDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, mapLogicSupport, mapLogic, outputResolution); MapLogic(argZero, ticks, containers, a2PeopleSingletonDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, mapLogicSupport, mapLogic, outputResolution);
if (_IsEnvironment.Development) if (_IsEnvironment.Development)
continue; continue;
List<MappingFromItem> mappingFromItemCollection = GetMappingFromItemCollection(containers); List<MappingFromItem> mappingFromItemCollection = GetMappingFromItemCollection(containers);

View File

@ -62,7 +62,6 @@ public class Configuration
[Display(Name = "Face Distance Tolerance"), Required] public double[] RangeDistanceTolerance { get; set; } [Display(Name = "Face Distance Tolerance"), Required] public double[] RangeDistanceTolerance { get; set; }
[Display(Name = "Face Area Permille Tolerance"), Required] public int[] RangeFaceAreaPermilleTolerance { get; set; } [Display(Name = "Face Area Permille Tolerance"), Required] public int[] RangeFaceAreaPermilleTolerance { get; set; }
[Display(Name = "Location Minimum Confidence"), Required] public double[] RangeFaceConfidence { get; set; } [Display(Name = "Location Minimum Confidence"), Required] public double[] RangeFaceConfidence { get; set; }
[Display(Name = "Retry Images Without a Face"), Required] public bool? RetryImagesWithoutAFaceLocation { get; set; }
[Display(Name = "Reverse"), Required] public bool? Reverse { get; set; } [Display(Name = "Reverse"), Required] public bool? Reverse { get; set; }
[Display(Name = "Save Face Distances"), Required] public string[] SaveFaceDistancesForOutputResolutions { get; set; } [Display(Name = "Save Face Distances"), Required] public string[] SaveFaceDistancesForOutputResolutions { get; set; }
[Display(Name = "Save Face Landmark For Output Resolutions"), Required] public string[] SaveFaceLandmarkForOutputResolutions { get; set; } [Display(Name = "Save Face Landmark For Output Resolutions"), Required] public string[] SaveFaceLandmarkForOutputResolutions { get; set; }
@ -180,8 +179,6 @@ public class Configuration
throw new NullReferenceException(nameof(configuration.RangeFaceConfidence)); throw new NullReferenceException(nameof(configuration.RangeFaceConfidence));
if (configuration.RangeDistanceTolerance is null || configuration.RangeDistanceTolerance.Length != 3) if (configuration.RangeDistanceTolerance is null || configuration.RangeDistanceTolerance.Length != 3)
throw new NullReferenceException(nameof(configuration.RangeDistanceTolerance)); throw new NullReferenceException(nameof(configuration.RangeDistanceTolerance));
if (configuration.RetryImagesWithoutAFaceLocation is null)
throw new NullReferenceException(nameof(configuration.RetryImagesWithoutAFaceLocation));
if (configuration.Reverse is null) if (configuration.Reverse is null)
throw new NullReferenceException(nameof(configuration.Reverse)); throw new NullReferenceException(nameof(configuration.Reverse));
configuration.SaveFaceDistancesForOutputResolutions ??= Array.Empty<string>(); configuration.SaveFaceDistancesForOutputResolutions ??= Array.Empty<string>();
@ -258,7 +255,6 @@ public class Configuration
configuration.RangeFaceAreaPermilleTolerance, configuration.RangeFaceAreaPermilleTolerance,
configuration.RangeFaceConfidence, configuration.RangeFaceConfidence,
configuration.RangeDistanceTolerance, configuration.RangeDistanceTolerance,
configuration.RetryImagesWithoutAFaceLocation.Value,
configuration.Reverse.Value, configuration.Reverse.Value,
configuration.SaveFaceDistancesForOutputResolutions, configuration.SaveFaceDistancesForOutputResolutions,
configuration.SaveFaceLandmarkForOutputResolutions, configuration.SaveFaceLandmarkForOutputResolutions,

View File

@ -58,7 +58,6 @@ public class Configuration
public int[] RangeFaceAreaPermilleTolerance { init; get; } public int[] RangeFaceAreaPermilleTolerance { init; get; }
public double[] RangeFaceConfidence { init; get; } public double[] RangeFaceConfidence { init; get; }
public double[] RangeDistanceTolerance { init; get; } public double[] RangeDistanceTolerance { init; get; }
public bool RetryImagesWithoutAFaceLocation { init; get; }
public bool Reverse { init; get; } public bool Reverse { init; get; }
public string[] SaveFaceDistancesForOutputResolutions { init; get; } public string[] SaveFaceDistancesForOutputResolutions { init; get; }
public string[] SaveFaceLandmarkForOutputResolutions { init; get; } public string[] SaveFaceLandmarkForOutputResolutions { init; get; }
@ -126,7 +125,6 @@ public class Configuration
int[] rangeFaceAreaPermilleTolerance, int[] rangeFaceAreaPermilleTolerance,
double[] rangeFaceConfidence, double[] rangeFaceConfidence,
double[] rangeDistanceTolerance, double[] rangeDistanceTolerance,
bool retryImagesWithoutAFaceLocation,
bool reverse, bool reverse,
string[] saveFaceDistancesForOutputResolutions, string[] saveFaceDistancesForOutputResolutions,
string[] saveFaceLandmarkForOutputResolutions, string[] saveFaceLandmarkForOutputResolutions,
@ -193,7 +191,6 @@ public class Configuration
RangeFaceAreaPermilleTolerance = rangeFaceAreaPermilleTolerance; RangeFaceAreaPermilleTolerance = rangeFaceAreaPermilleTolerance;
RangeFaceConfidence = rangeFaceConfidence; RangeFaceConfidence = rangeFaceConfidence;
RangeDistanceTolerance = rangeDistanceTolerance; RangeDistanceTolerance = rangeDistanceTolerance;
RetryImagesWithoutAFaceLocation = retryImagesWithoutAFaceLocation;
Reverse = reverse; Reverse = reverse;
SaveFaceDistancesForOutputResolutions = saveFaceDistancesForOutputResolutions; SaveFaceDistancesForOutputResolutions = saveFaceDistancesForOutputResolutions;
SaveFaceLandmarkForOutputResolutions = saveFaceLandmarkForOutputResolutions; SaveFaceLandmarkForOutputResolutions = saveFaceLandmarkForOutputResolutions;

View File

@ -101,7 +101,6 @@
"ResultCollection": "[]", "ResultCollection": "[]",
"ResultContent": "()", "ResultContent": "()",
"ResultSingleton": "{}", "ResultSingleton": "{}",
"RetryImagesWithoutAFaceLocation": false,
"Reverse": false, "Reverse": false,
"RootDirectory": "D:/Images", "RootDirectory": "D:/Images",
"SaveFullYearOfRandomFiles": true, "SaveFullYearOfRandomFiles": true,

View File

@ -1,8 +0,0 @@
using System.Text.Json.Serialization;
namespace View_by_Distance.Map.Models;
public record DatabaseFileRoot(
[property: JsonPropertyName("table")] string Table,
[property: JsonPropertyName("rows")] IReadOnlyList<DatabaseFile> Files
);

View File

@ -936,7 +936,7 @@ public class MapLogic
return results; return results;
} }
public void SaveFilteredOriginalImagesFromJLinks(string[] jLinks, string a2PeopleSingletonDirectory, PersonContainer[] personContainers, Mapping[] mappingCollection, Dictionary<long, int> personKeyToCount, int totalNotMapped) public void SaveFilteredOriginalImagesFromJLinks(string[] jLinks, PersonContainer[] personContainers, string a2PeopleSingletonDirectory, Mapping[] mappingCollection, Dictionary<long, int> personKeyToCount, int totalNotMapped)
{ {
if (_Configuration is null) if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration)); throw new NullReferenceException(nameof(_Configuration));
@ -1149,237 +1149,166 @@ public class MapLogic
} }
} }
private DatabaseFileRoot GetDatabaseFileRoot() private static JsonProperty[] GetJsonProperty(string fileName)
{ {
if (_Configuration is null) JsonProperty[] results;
throw new NullReferenceException(nameof(_Configuration)); string json = File.ReadAllText(fileName);
string file = Path.Combine(_Configuration.PhotoPrismDirectory, "files.json"); JsonElement? jsonElement = JsonSerializer.Deserialize<JsonElement>(json);
string json = File.ReadAllText(file); results = jsonElement.Value.EnumerateObject().ToArray();
DatabaseFileRoot? databaseFileRoot = JsonSerializer.Deserialize<DatabaseFileRoot>(json);
if (databaseFileRoot is null)
throw new NullReferenceException(nameof(databaseFileRoot));
return databaseFileRoot;
}
private Marker[] GetMarkers()
{
if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration));
string file = Path.Combine(_Configuration.PhotoPrismDirectory, "markers.json");
string json = File.ReadAllText(file);
Marker[]? markerRoot = JsonSerializer.Deserialize<Marker[]>(json);
if (markerRoot is null)
throw new NullReferenceException(nameof(markerRoot));
return markerRoot;
}
private static Dictionary<string, DatabaseFile> Get(DatabaseFileRoot databaseFileRoot)
{
Dictionary<string, DatabaseFile> fileUidToFile = new();
for (int i = 0; i < databaseFileRoot.Files.Count; i++)
fileUidToFile.Add(databaseFileRoot.Files[i].FileUid, databaseFileRoot.Files[i]);
return fileUidToFile;
}
private static MarkerWith GetMarkerWith(int? dlib, DatabaseFile databaseFile, Marker marker, int? count, double? percent, int? normalizedRectangle, long? personKey, string personKeyFormatted)
{
return new(marker.MarkerUid,
marker.FileUid,
marker.MarkerType,
marker.MarkerSrc,
marker.MarkerName,
marker.MarkerReview,
marker.MarkerInvalid,
marker.SubjUid,
marker.SubjSrc,
marker.FaceId,
marker.FaceDist,
marker.EmbeddingsJson,
marker.LandmarksJson,
marker.X,
marker.Y,
marker.W,
marker.H,
marker.Q,
marker.Size,
marker.Score,
marker.Thumb,
marker.MatchedAt,
marker.CreatedAt,
marker.UpdatedAt,
databaseFile.Id,
databaseFile.FileName,
dlib,
count,
percent,
normalizedRectangle,
personKey,
personKeyFormatted);
}
private static Dictionary<string, List<Face>> GetFacesByFileName(List<Item> filteredItems)
{
Dictionary<string, List<Face>> results = new();
string key;
foreach (Item item in filteredItems)
{
foreach (Face face in item.Faces)
{
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null || face.Mapping is null)
continue;
key = Path.GetFileNameWithoutExtension(face.Mapping.MappingFromItem.RelativePath);
if (!results.ContainsKey(key))
results.Add(key, new());
results[key].Add(face);
}
}
return results; return results;
} }
public void FindMatch(List<Item> filteredItems) private static Marker[]? GetMarkers(string photoPrismDirectory)
{ {
if (_Configuration is null) Marker[]? results;
throw new NullReferenceException(nameof(_Configuration)); string file = Path.Combine(photoPrismDirectory, "markers.json");
int? dlib; JsonProperty[] jsonProperties = GetJsonProperty(file);
double? percent; results = JsonSerializer.Deserialize<Marker[]>(jsonProperties[1].Value);
long? personKey; return results;
const int zero = 0;
List<Face>? matches;
MarkerWith markerWith;
int? normalizedRectangle;
string personKeyFormatted;
DatabaseFile? databaseFile;
PersonBirthday personBirthday;
Marker[] markers = GetMarkers();
string fileNameWithoutExtension;
PersonContainer[]? personContainers;
System.Drawing.Rectangle dlibRectangle;
System.Drawing.Rectangle prismRectangle;
System.Drawing.Rectangle intersectRectangle;
(Face Face, double Percent)[] sortedCollection;
List<(Face Face, double Percent)> collection = new();
DatabaseFileRoot databaseFileRoot = GetDatabaseFileRoot();
Dictionary<string, DatabaseFile> fileUidToFile = Get(databaseFileRoot);
Dictionary<int, PersonContainer[]>? normalizedRectangleToPersonContainers;
Dictionary<string, List<Face>> keyValuePairs = GetFacesByFileName(filteredItems);
foreach (Marker marker in markers)
{
dlib = null;
personKey = null;
collection.Clear();
normalizedRectangle = null;
personKeyFormatted = string.Empty;
normalizedRectangleToPersonContainers = null;
if (!fileUidToFile.TryGetValue(marker.FileUid, out databaseFile))
continue;
fileNameWithoutExtension = Path.GetFileNameWithoutExtension(Path.Combine("C:", databaseFile.FileName));
prismRectangle = new((int)(marker.X * databaseFile.FileWidth), (int)(marker.Y * databaseFile.FileHeight), (int)(marker.W * databaseFile.FileWidth), (int)(marker.H * databaseFile.FileHeight));
if (!keyValuePairs.TryGetValue(fileNameWithoutExtension, out matches) || !int.TryParse(fileNameWithoutExtension, out int id))
percent = null;
else
{
dlib = id;
_ = _IdThenNormalizedRectangleToPersonContainers.TryGetValue(dlib.Value, out normalizedRectangleToPersonContainers);
foreach (Face face in matches)
{
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 = System.Drawing.Rectangle.Intersect(prismRectangle, dlibRectangle);
if (intersectRectangle.Width == 0 || intersectRectangle.Height == 0)
continue;
percent = (double)intersectRectangle.Width * intersectRectangle.Height / (dlibRectangle.Width * dlibRectangle.Height);
if (percent < 0.000001)
continue;
collection.Add(new(face, percent.Value));
}
}
if (!collection.Any())
percent = null;
else
{
sortedCollection = collection.OrderByDescending(l => l.Percent).ToArray();
percent = sortedCollection[zero].Percent;
normalizedRectangle = sortedCollection[zero].Face.Mapping?.MappingFromLocation.NormalizedRectangle;
if (normalizedRectangleToPersonContainers is null || normalizedRectangle is null || !normalizedRectangleToPersonContainers.TryGetValue(normalizedRectangle.Value, out personContainers))
personContainers = null;
else
{
foreach (PersonContainer personContainer in personContainers)
{
if (personContainer.Key is null || personContainer.Birthdays is null || !personContainer.Birthdays.Any())
continue;
personBirthday = personContainer.Birthdays[zero];
personKey = personBirthday.Value.Ticks;
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday);
break;
}
}
}
markerWith = GetMarkerWith(dlib, databaseFile, marker, collection.Count, percent, normalizedRectangle, personKey, personKeyFormatted);
string json = JsonSerializer.Serialize(markerWith, new JsonSerializerOptions() { WriteIndented = true });
if (IPath.WriteAllText(Path.Combine(_Configuration.PhotoPrismDirectory, "With", $"{marker.MarkerUid}.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true))
continue;
}
} }
public void SaveMarkers() public static void SaveMarkers(string photoPrismDirectory)
{ {
if (_Configuration is null) if (string.IsNullOrEmpty(photoPrismDirectory))
throw new NullReferenceException(nameof(_Configuration)); throw new Exception();
double[]? encoding; // double[]? encoding;
string file = Path.Combine(_Configuration.PhotoPrismDirectory, "markers.json"); // Marker[]? markers = GetMarkers(photoPrismDirectory);
string json = File.ReadAllText(file); // if (markers is null)
Marker[]? markers = JsonSerializer.Deserialize<Marker[]>(json); // throw new NullReferenceException(nameof(markers));
// foreach (Marker marker in markers)
// {
// encoding = JsonSerializer.Deserialize<double[]>(marker.EmbeddingsJson[1..^1]);
// File.WriteAllText(Path.Combine(photoPrismDirectory, "EmbeddingsJson", $"{marker.MarkerUid}.json"), marker.EmbeddingsJson);
// if (encoding is null)
// continue;
// }
}
private static Dictionary<string, List<Marker>> GetFileUIdToMarkers(string photoPrismDirectory)
{
Dictionary<string, List<Marker>> results = new();
Marker[]? markers = GetMarkers(photoPrismDirectory);
if (markers is null) if (markers is null)
throw new NullReferenceException(nameof(markers)); throw new NullReferenceException(nameof(markers));
foreach (Marker marker in markers) foreach (Marker marker in markers)
{ {
encoding = JsonSerializer.Deserialize<double[]>(marker.EmbeddingsJson[1..^1]); if (!results.ContainsKey(marker.FileUid))
File.WriteAllText(Path.Combine(_Configuration.PhotoPrismDirectory, "EmbeddingsJson", $"{marker.MarkerUid}.json"), marker.EmbeddingsJson); results.Add(marker.FileUid, new());
if (encoding is null) results[marker.FileUid].Add(marker);
continue;
} }
return results;
} }
public void LoadMatches() private static DatabaseFile[]? GetDatabaseFiles(string photoPrismDirectory)
{
DatabaseFile[]? results;
string file = Path.Combine(photoPrismDirectory, "files.json");
JsonProperty[] jsonProperties = GetJsonProperty(file);
results = JsonSerializer.Deserialize<DatabaseFile[]>(jsonProperties[1].Value);
return results;
}
public static Dictionary<string, List<MappingFromPhotoPrism>> GetFileNameToCollection(string photoPrismDirectory)
{
Dictionary<string, List<MappingFromPhotoPrism>> results = new();
List<Marker>? makers;
MappingFromPhotoPrism mappingFromPhotoPrism;
List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection;
DatabaseFile[]? databaseFiles = GetDatabaseFiles(photoPrismDirectory);
if (databaseFiles is null)
throw new NullReferenceException(nameof(databaseFiles));
Dictionary<string, List<Marker>> fileUIdToMarkers = GetFileUIdToMarkers(photoPrismDirectory);
foreach (DatabaseFile databaseFile in databaseFiles)
{
if (!results.TryGetValue(databaseFile.FileName, out mappingFromPhotoPrismCollection))
{
results.Add(databaseFile.FileName, new());
if (!results.TryGetValue(databaseFile.FileName, out mappingFromPhotoPrismCollection))
throw new Exception();
}
if (!fileUIdToMarkers.TryGetValue(databaseFile.FileUid, out makers))
mappingFromPhotoPrism = new(databaseFile, new());
else
mappingFromPhotoPrism = new(databaseFile, makers);
mappingFromPhotoPrismCollection.Add(mappingFromPhotoPrism);
}
return results;
}
public void WriteMatches(long ticks, Face[] distinctFilteredFaces)
{ {
if (_Configuration is null) if (_Configuration is null)
throw new NullReferenceException(nameof(_Configuration)); throw new NullReferenceException(nameof(_Configuration));
string json; long? personKey;
MarkerWith? markerWith; const int zero = 0;
List<MarkerWith> collection = new(); int? normalizedRectangle;
string personKeyFormatted;
List<string> subjects = new();
PersonBirthday personBirthday;
string personDisplayDirectoryName;
StringBuilder stringBuilder = new(); StringBuilder stringBuilder = new();
List<(int Count, MarkerWith MarkerWith)> countCollection = new(); PersonContainer[]? personContainers;
List<(double Percent, MarkerWith MarkerWith)> percentCollection = new(); System.Drawing.Rectangle dlibRectangle;
string[] files = Directory.GetFiles(Path.Combine(_Configuration.PhotoPrismDirectory, "With"), "*.json", SearchOption.TopDirectoryOnly); System.Drawing.Rectangle? prismRectangle;
foreach (string file in files) System.Drawing.Rectangle intersectRectangle;
Dictionary<int, PersonContainer[]>? normalizedRectangleToPersonContainers;
(MappingFromPhotoPrism MappingFromPhotoPrism, Marker Marker, double Percent)[] sortedCollection;
List<(MappingFromPhotoPrism MappingFromPhotoPrism, Marker Marker, double Percent)> collection = new();
foreach (Face face in distinctFilteredFaces)
{ {
json = File.ReadAllText(file); collection.Clear();
markerWith = JsonSerializer.Deserialize<MarkerWith>(json); normalizedRectangle = face.Mapping?.MappingFromLocation.NormalizedRectangle;
if (markerWith is null || markerWith.DlibId is null) if (normalizedRectangle is null)
continue; continue;
collection.Add(markerWith); if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null || face.Mapping is null)
if (markerWith.Count is null || markerWith.Count.Value == 0)
continue; continue;
countCollection.Add(new(markerWith.Count.Value, markerWith)); if (face.Mapping.MappingFromPhotoPrismCollection is null)
if (markerWith.Percent is null)
continue; continue;
percentCollection.Add(new(markerWith.Percent.Value, markerWith)); _ = _IdThenNormalizedRectangleToPersonContainers.TryGetValue(face.Mapping.MappingFromItem.Id, out normalizedRectangleToPersonContainers);
if (string.IsNullOrEmpty(markerWith.PersonKeyFormatted)) if (normalizedRectangleToPersonContainers is null || !normalizedRectangleToPersonContainers.TryGetValue(normalizedRectangle.Value, out personContainers))
continue; continue;
_ = stringBuilder. dlibRectangle = new(face.Location.Left, face.Location.Top, face.Location.Right - face.Location.Left, face.Location.Bottom - face.Location.Top);
Append("update `markers` set subj_src = 'manual' marker_name = '"). foreach (MappingFromPhotoPrism mappingFromPhotoPrism in face.Mapping.MappingFromPhotoPrismCollection)
Append(markerWith.PersonKeyFormatted). {
Append("' where marker_uid = '"). foreach (Marker marker in mappingFromPhotoPrism.Markers)
Append(markerWith.MarkerUid). {
AppendLine("';"); prismRectangle = ILocation.GetRectangle(face.OutputResolution, mappingFromPhotoPrism.DatabaseFile, marker);
if (prismRectangle is null)
continue;
intersectRectangle = System.Drawing.Rectangle.Intersect(dlibRectangle, prismRectangle.Value);
if (intersectRectangle.Width == 0 || intersectRectangle.Height == 0)
continue;
double percent = (double)intersectRectangle.Width * intersectRectangle.Height / (dlibRectangle.Width * dlibRectangle.Height);
if (percent < 0.000001)
continue;
collection.Add(new(mappingFromPhotoPrism, marker, percent));
}
}
if (!collection.Any())
continue;
sortedCollection = collection.OrderByDescending(l => l.Percent).ToArray();
foreach ((MappingFromPhotoPrism mappingFromPhotoPrism, Marker marker, double percent) in sortedCollection)
{
foreach (PersonContainer personContainer in personContainers)
{
if (personContainer.Key is null || personContainer.Birthdays is null || !personContainer.Birthdays.Any())
continue;
personBirthday = personContainer.Birthdays[zero];
personKey = personBirthday.Value.Ticks;
personDisplayDirectoryName = personContainer.DisplayDirectoryName;
personKeyFormatted = IPersonBirthday.GetFormatted(_Configuration.PersonBirthdayFormat, personBirthday);
subjects.Add($"update `subjects` set subj_alias = '{personKeyFormatted}' where subj_name = '{personDisplayDirectoryName}';");
_ = stringBuilder.
Append("update `markers` set subj_src = 'manual', marker_name = '").
Append(personDisplayDirectoryName).
Append("' where marker_uid = '").
Append(marker.MarkerUid).
AppendLine("';");
}
}
} }
(int, MarkerWith)[] countSorted = countCollection.OrderByDescending(l => l.Count).ToArray(); File.WriteAllLines(Path.Combine(_Configuration.PhotoPrismDirectory, $"{ticks}-subject_alias_update.sql"), subjects.Distinct());
(double, MarkerWith)[] percentSorted = percentCollection.OrderBy(l => l.Percent).ToArray(); File.WriteAllText(Path.Combine(_Configuration.PhotoPrismDirectory, $"{ticks}-marker_name_update.sql"), stringBuilder.ToString());
if (collection.Any())
{ }
File.WriteAllText(Path.Combine(_Configuration.PhotoPrismDirectory, "marker_name_update.sql"), stringBuilder.ToString());
} }
public Dictionary<int, Dictionary<int, PersonContainer[]>> GetMissing(Dictionary<int, Dictionary<int, Mapping>> idToNormalizedRectangleToMapping) public Dictionary<int, Dictionary<int, PersonContainer[]>> GetMissing(Dictionary<int, Dictionary<int, Mapping>> idToNormalizedRectangleToMapping)

View File

@ -189,7 +189,7 @@ internal abstract class MapLogic
return results; return results;
} }
internal static List<(string, string[], string)> DeleteEmptyDirectoriesAndGetMappedFaceFiles(Configuration configuration, long ticks, string? a2PeopleContentDirectory, string? eDistanceContentDirectory, PersonContainer[] personContainers) internal static List<(string, string[], string)> DeleteEmptyDirectoriesAndGetMappedFaceFiles(Configuration configuration, PersonContainer[] personContainers, long ticks, string? a2PeopleContentDirectory, string? eDistanceContentDirectory)
{ {
List<(string, string[], string)> results; List<(string, string[], string)> results;
string personKeyFormatted; string personKeyFormatted;

View File

@ -3,9 +3,9 @@ namespace View_by_Distance.Map.Models.Stateless.Methods;
public interface IMapLogic public interface IMapLogic
{ // ... { // ...
List<(string, string[], string)> TestStatic_DeleteEmptyDirectoriesAndGetMappedFaceFiles(Configuration configuration, long ticks, string? a2PeopleContentDirectory, string? eDistanceContentDirectory, Shared.Models.PersonContainer[] personContainers) => List<(string, string[], string)> TestStatic_DeleteEmptyDirectoriesAndGetMappedFaceFiles(Configuration configuration, Shared.Models.PersonContainer[] personContainers, long ticks, string? a2PeopleContentDirectory, string? eDistanceContentDirectory) =>
DeleteEmptyDirectoriesAndGetMappedFaceFiles(configuration, ticks, a2PeopleContentDirectory, eDistanceContentDirectory, personContainers); DeleteEmptyDirectoriesAndGetMappedFaceFiles(configuration, personContainers, ticks, a2PeopleContentDirectory, eDistanceContentDirectory);
static List<(string, string[], string)> DeleteEmptyDirectoriesAndGetMappedFaceFiles(Configuration configuration, long ticks, string? a2PeopleContentDirectory, string? eDistanceContentDirectory, Shared.Models.PersonContainer[] personContainers) => static List<(string, string[], string)> DeleteEmptyDirectoriesAndGetMappedFaceFiles(Configuration configuration, Shared.Models.PersonContainer[] personContainers, long ticks, string? a2PeopleContentDirectory, string? eDistanceContentDirectory) =>
MapLogic.DeleteEmptyDirectoriesAndGetMappedFaceFiles(configuration, ticks, a2PeopleContentDirectory, eDistanceContentDirectory, personContainers); MapLogic.DeleteEmptyDirectoriesAndGetMappedFaceFiles(configuration, personContainers, ticks, a2PeopleContentDirectory, eDistanceContentDirectory);
} }

View File

@ -142,7 +142,7 @@ public class B_Metadata
DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime))
{ {
if (!_ForceMetadataLastWriteTimeToCreationTime && (!fileInfo.Exists || fileInfo.LastWriteTime == fileInfo.CreationTime)) if (!_ForceMetadataLastWriteTimeToCreationTime)
subFileTuples.Add(new Tuple<string, DateTime>(nameof(B_Metadata), DateTime.Now)); subFileTuples.Add(new Tuple<string, DateTime>(nameof(B_Metadata), DateTime.Now));
else else
{ {

View File

@ -267,7 +267,7 @@
// propertyTicks = null; // propertyTicks = null;
// foreach (PropertyCompare.Models.PropertyCompare propertyCompare in propertyCompareCollection) // foreach (PropertyCompare.Models.PropertyCompare propertyCompare in propertyCompareCollection)
// { // {
// if (propertyCompare?.Property?.Id is null) // if (propertyCompare?.Property?.FileId is null)
// continue; // continue;
// if (ticks != propertyCompare.MinimumDateTime.Ticks) // if (ticks != propertyCompare.MinimumDateTime.Ticks)
// { // {
@ -276,7 +276,7 @@
// } // }
// if (!regexResult.Equals(propertyCompare.RegexResult, StringComparison.CurrentCultureIgnoreCase)) // if (!regexResult.Equals(propertyCompare.RegexResult, StringComparison.CurrentCultureIgnoreCase))
// continue; // continue;
// propertyId = propertyCompare.Property.Id; // propertyId = propertyCompare.Property.FileId;
// propertyTicks = propertyCompare.MinimumDateTime.Ticks; // propertyTicks = propertyCompare.MinimumDateTime.Ticks;
// mappedIndex = mappedIndices.IndexOf(index); // mappedIndex = mappedIndices.IndexOf(index);
// if (mappedIndex > -1) // if (mappedIndex > -1)
@ -290,7 +290,7 @@
// string[] duplicatesLines = ( // string[] duplicatesLines = (
// from l // from l
// in duplicates // in duplicates
// select $"{l.Property.Id}\t{l.RegexResult}\t{l.MinimumDateTime:yyyy-MM-dd_HH-mm-ss}\t{l.MinimumDateTime}\t{l.RelativeDirectory}\t{l.FileNameWithoutExtension}{l.Extension}.___" // select $"{l.Property.FileId}\t{l.RegexResult}\t{l.MinimumDateTime:yyyy-MM-dd_HH-mm-ss}\t{l.MinimumDateTime}\t{l.RelativeDirectory}\t{l.FileNameWithoutExtension}{l.Extension}.___"
// ).ToArray(); // ).ToArray();
// string[] matchedLines = ( // string[] matchedLines = (
// from l // from l
@ -575,11 +575,11 @@
// Dictionary<int, List<PropertyCompare.Models.PropertyCompare>> results = new(); // Dictionary<int, List<PropertyCompare.Models.PropertyCompare>> results = new();
// foreach (PropertyCompare.Models.PropertyCompare propertyCompare in propertyCompares) // foreach (PropertyCompare.Models.PropertyCompare propertyCompare in propertyCompares)
// { // {
// if (propertyCompare?.Property?.Id is null) // if (propertyCompare?.Property?.FileId is null)
// continue; // continue;
// if (!results.ContainsKey(propertyCompare.Property.Id.Value)) // if (!results.ContainsKey(propertyCompare.Property.FileId.Value))
// results.Add(propertyCompare.Property.Id.Value, new()); // results.Add(propertyCompare.Property.FileId.Value, new());
// results[propertyCompare.Property.Id.Value].Add(propertyCompare); // results[propertyCompare.Property.FileId.Value].Add(propertyCompare);
// } // }
// return results; // return results;
// } // }
@ -628,9 +628,9 @@
// if (keyValuePairs.ContainsKey(index)) // if (keyValuePairs.ContainsKey(index))
// { // {
// propertyCompare = keyValuePairs[index][0]; // propertyCompare = keyValuePairs[index][0];
// if (propertyCompare?.Property?.Id is null) // if (propertyCompare?.Property?.FileId is null)
// continue; // continue;
// propertyId = propertyCompare.Property.Id; // propertyId = propertyCompare.Property.FileId;
// propertyTicks = propertyCompare.MinimumDateTime.Ticks; // propertyTicks = propertyCompare.MinimumDateTime.Ticks;
// } // }
// collection.Add(new(index, relativeDirectory, $"{fileNameWithoutExtension}{extension}", regexResult, ticks, propertyId, propertyTicks)); // collection.Add(new(index, relativeDirectory, $"{fileNameWithoutExtension}{extension}", regexResult, ticks, propertyId, propertyTicks));

View File

@ -44,7 +44,7 @@ public partial class PropertyCompare
return result; return result;
} }
// internal static string GetSelect(PropertyCompare item) => string.Concat(item.JsonFileNameWithoutExtension, item.ImageFileName, '\t', item.Property.CreationTime.Ticks, '\t', GetDateTime(item.Property).ToString("yyyy-MM-dd_HH-mm-ss"), '\t', item.Property.Id, '\t', item.Property.FileSize, '\t', item.Property.Width, '\t', item.Property.Height); // internal static string GetSelect(PropertyCompare item) => string.Concat(item.JsonFileNameWithoutExtension, item.ImageFileName, '\t', item.Property.CreationTime.Ticks, '\t', GetDateTime(item.Property).ToString("yyyy-MM-dd_HH-mm-ss"), '\t', item.Property.FileId, '\t', item.Property.FileSize, '\t', item.Property.Width, '\t', item.Property.Height);
#nullable disable #nullable disable

View File

@ -176,7 +176,7 @@
// extension = Path.GetExtension(files[index]); // extension = Path.GetExtension(files[index]);
// string json = File.ReadAllText(jsonFile); // string json = File.ReadAllText(jsonFile);
// Shared.Models.Property? property = JsonSerializer.Deserialize<Shared.Models.Property>(json); // Shared.Models.Property? property = JsonSerializer.Deserialize<Shared.Models.Property>(json);
// if (property?.Id is null) // if (property?.FileId is null)
// throw new NullReferenceException(nameof(property)); // throw new NullReferenceException(nameof(property));
// DateTime minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(property); // DateTime minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(property);
// corrected = string.Concat(relativeDirectory, jsonFileNameWithoutExtension); // corrected = string.Concat(relativeDirectory, jsonFileNameWithoutExtension);
@ -195,11 +195,11 @@
// { // {
// n = i switch // n = i switch
// { // {
// 0 => property.Id.Value, // 0 => property.FileId.Value,
// 1 => property.Id.Value, // 1 => property.FileId.Value,
// 2 => property.Id.Value, // 2 => property.FileId.Value,
// 3 => property.Id.Value, // 3 => property.FileId.Value,
// 4 => property.Id.Value, // 4 => property.FileId.Value,
// 5 => Shared.Models.Stateless.Methods.IProperty.GetDateTime(property).Ticks, // 5 => Shared.Models.Stateless.Methods.IProperty.GetDateTime(property).Ticks,
// 6 => property.CreationTime.Ticks, // 6 => property.CreationTime.Ticks,
// 7 => property.FileSize, // 7 => property.FileSize,
@ -229,8 +229,8 @@
// results.Add(propertyCompare); // results.Add(propertyCompare);
// if (duplicates is not null) // if (duplicates is not null)
// { // {
// string value = $"{property.Id.Value}\t{property}"; // string value = $"{property.FileId.Value}\t{property}";
// index = ids.IndexOf(property.Id.Value); // index = ids.IndexOf(property.FileId.Value);
// if (index > -1) // if (index > -1)
// { // {
// lock (@lock) // lock (@lock)
@ -241,7 +241,7 @@
// } // }
// lock (@lock) // lock (@lock)
// { // {
// ids.Add(property.Id.Value); // ids.Add(property.FileId.Value);
// collection.Add(propertyCompare); // collection.Add(propertyCompare);
// } // }
// } // }

View File

@ -333,7 +333,7 @@ public class A_Property
json = JsonSerializer.Serialize(result, _WriteIndentedJsonSerializerOptions); json = JsonSerializer.Serialize(result, _WriteIndentedJsonSerializerOptions);
if (populateId && Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true)) if (populateId && Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true))
{ {
if (!_Configuration.ForcePropertyLastWriteTimeToCreationTime && (!fileInfo.Exists || fileInfo.LastWriteTime == fileInfo.CreationTime)) if (!_Configuration.ForcePropertyLastWriteTimeToCreationTime)
sourceDirectoryFileTuples.Add(new Tuple<string, DateTime>(nameof(A_Property), DateTime.Now)); sourceDirectoryFileTuples.Add(new Tuple<string, DateTime>(nameof(A_Property), DateTime.Now));
else else
{ {

View File

@ -16,7 +16,7 @@ public class Configuration
[Display(Name = "Ignore Extensions"), Required] public string[] IgnoreExtensions { get; set; } [Display(Name = "Ignore Extensions"), Required] public string[] IgnoreExtensions { get; set; }
[Display(Name = "Max Images In Directory For Top Level First Pass"), Required] public int? MaxImagesInDirectoryForTopLevelFirstPass { get; set; } [Display(Name = "Max Images In Directory For Top Level First Pass"), Required] public int? MaxImagesInDirectoryForTopLevelFirstPass { get; set; }
[Display(Name = "Pattern"), Required] public string Pattern { get; set; } [Display(Name = "Pattern"), Required] public string Pattern { get; set; }
[Display(Name = "Populate Properties Id"), Required] public bool? PopulatePropertyId { get; set; } [Display(Name = "Populate Properties FileId"), Required] public bool? PopulatePropertyId { get; set; }
[Display(Name = "Properties Changed For Property"), Required] public bool? PropertiesChangedForProperty { get; set; } [Display(Name = "Properties Changed For Property"), Required] public bool? PropertiesChangedForProperty { get; set; }
[Display(Name = "Property Content Collection Files"), Required] public string[] PropertyContentCollectionFiles { get; set; } [Display(Name = "Property Content Collection Files"), Required] public string[] PropertyContentCollectionFiles { get; set; }
[Display(Name = "Result All In One"), Required] public string ResultAllInOne { get; set; } [Display(Name = "Result All In One"), Required] public string ResultAllInOne { get; set; }

View File

@ -216,6 +216,7 @@ public class Container
{ {
string relativePath; string relativePath;
string checkFileName; string checkFileName;
string? checkDirectoryName;
List<string> checkCollection = new(); List<string> checkCollection = new();
checkCollection.AddRange(otherCollection); checkCollection.AddRange(otherCollection);
int length = configuration.RootDirectory.Length; int length = configuration.RootDirectory.Length;
@ -225,6 +226,9 @@ public class Container
{ {
relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(fileHolder.FullName, length); relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(fileHolder.FullName, length);
checkFileName = Path.GetFullPath(string.Concat(aPropertySingletonDirectory, relativePath)); checkFileName = Path.GetFullPath(string.Concat(aPropertySingletonDirectory, relativePath));
checkDirectoryName = Path.GetDirectoryName(checkFileName);
if (string.IsNullOrEmpty(checkDirectoryName) || !Directory.Exists(checkDirectoryName))
continue;
if (!checkCollection.Remove(checkFileName)) if (!checkCollection.Remove(checkFileName))
File.WriteAllText(checkFileName, string.Empty); File.WriteAllText(checkFileName, string.Empty);
} }

View File

@ -505,7 +505,7 @@ public class C_Resize
DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime))
{ {
if (!_ForceResizeLastWriteTimeToCreationTime && (!fileInfo.Exists || fileInfo.LastWriteTime == fileInfo.CreationTime)) if (!_ForceResizeLastWriteTimeToCreationTime)
subFileTuples.Add(new Tuple<string, DateTime>(nameof(C_Resize), DateTime.Now)); subFileTuples.Add(new Tuple<string, DateTime>(nameof(C_Resize), DateTime.Now));
else else
{ {

View File

@ -1,6 +1,6 @@
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace View_by_Distance.Map.Models; namespace View_by_Distance.Shared.Models;
public record DatabaseFile( public record DatabaseFile(
[property: JsonPropertyName("id")] int Id, [property: JsonPropertyName("id")] int Id,

View File

@ -74,6 +74,21 @@ public class MappingFromLocation : Properties.IMappingFromLocation
} }
public class MappingFromPhotoPrism : Properties.IMappingFromPhotoPrism
{
public DatabaseFile DatabaseFile { init; get; }
public List<Marker> Markers { init; get; }
[JsonConstructor]
public MappingFromPhotoPrism(DatabaseFile databaseFile, List<Marker> markers)
{
DatabaseFile = databaseFile;
Markers = markers;
}
}
public class MappingFromPerson : Properties.IMappingFromPerson public class MappingFromPerson : Properties.IMappingFromPerson
{ {
@ -109,23 +124,25 @@ public class Mapping : Properties.IMapping
public int? By => _By; public int? By => _By;
public MappingFromItem MappingFromItem { init; get; } public MappingFromItem MappingFromItem { init; get; }
public MappingFromLocation MappingFromLocation { init; get; } public MappingFromLocation MappingFromLocation { init; get; }
public List<MappingFromPhotoPrism>? MappingFromPhotoPrismCollection { init; get; }
public MappingFromPerson? MappingFromPerson => _MappingFromPerson; public MappingFromPerson? MappingFromPerson => _MappingFromPerson;
public string? SegmentC => _SegmentC; public string? SegmentC => _SegmentC;
public SortingContainer? SortingContainer => _SortingContainer; public SortingContainer? SortingContainer => _SortingContainer;
[JsonConstructor] [JsonConstructor]
public Mapping(int? by, MappingFromItem mappingFromItem, MappingFromLocation mappingFromLocation, MappingFromPerson? mappingFromPerson, string? segmentC, SortingContainer? sortingContainer) public Mapping(int? by, MappingFromItem mappingFromItem, MappingFromLocation mappingFromLocation, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection, MappingFromPerson? mappingFromPerson, string? segmentC, SortingContainer? sortingContainer)
{ {
_By = by; _By = by;
_SegmentC = segmentC; _SegmentC = segmentC;
MappingFromItem = mappingFromItem; MappingFromItem = mappingFromItem;
MappingFromLocation = mappingFromLocation; MappingFromLocation = mappingFromLocation;
MappingFromPhotoPrismCollection = mappingFromPhotoPrismCollection;
_MappingFromPerson = mappingFromPerson; _MappingFromPerson = mappingFromPerson;
_SortingContainer = sortingContainer; _SortingContainer = sortingContainer;
} }
public Mapping(MappingFromItem mappingFromItem, MappingFromLocation mappingFromLocation) : public Mapping(MappingFromItem mappingFromItem, MappingFromLocation mappingFromLocation, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection) :
this(null, mappingFromItem, mappingFromLocation, null, null, null) this(null, mappingFromItem, mappingFromLocation, mappingFromPhotoPrismCollection, null, null, null)
{ } { }
public override string ToString() public override string ToString()

View File

@ -14,8 +14,8 @@ public record Marker(
[property: JsonPropertyName("subj_src")] string SubjSrc, [property: JsonPropertyName("subj_src")] string SubjSrc,
[property: JsonPropertyName("face_id")] string FaceId, [property: JsonPropertyName("face_id")] string FaceId,
[property: JsonPropertyName("face_dist")] double FaceDist, [property: JsonPropertyName("face_dist")] double FaceDist,
[property: JsonPropertyName("embeddings_json")] string EmbeddingsJson, // [property: JsonPropertyName("embeddings_json")] string EmbeddingsJson,
[property: JsonPropertyName("landmarks_json")] string LandmarksJson, // [property: JsonPropertyName("landmarks_json")] string LandmarksJson,
[property: JsonPropertyName("x")] double X, [property: JsonPropertyName("x")] double X,
[property: JsonPropertyName("y")] double Y, [property: JsonPropertyName("y")] double Y,
[property: JsonPropertyName("w")] double W, [property: JsonPropertyName("w")] double W,

View File

@ -1,36 +0,0 @@
namespace View_by_Distance.Shared.Models;
public record MarkerWith(
string MarkerUid,
string FileUid,
string MarkerType,
string MarkerSrc,
string MarkerName,
int MarkerReview,
int MarkerInvalid,
string SubjUid,
string SubjSrc,
string FaceId,
double FaceDist,
string EmbeddingsJson,
string LandmarksJson,
double X,
double Y,
double W,
double H,
int Q,
int Size,
int Score,
string Thumb,
string MatchedAt,
string CreatedAt,
string UpdatedAt,
int FileId,
string FileName,
int? DlibId,
int? Count,
double? Percent,
int? NormalizedRectangle,
long? PersonKey,
string PersonKeyFormatted
);

View File

@ -23,6 +23,14 @@ public interface IMappingFromLocation
} }
public interface IMappingFromPhotoPrism
{
public DatabaseFile DatabaseFile { init; get; }
public List<Marker> Markers { init; get; }
}
public interface IMappingFromPerson public interface IMappingFromPerson
{ {
@ -40,6 +48,7 @@ public interface IMapping
public string? SegmentC { get; } public string? SegmentC { get; }
public MappingFromItem MappingFromItem { init; get; } public MappingFromItem MappingFromItem { init; get; }
public MappingFromLocation MappingFromLocation { init; get; } public MappingFromLocation MappingFromLocation { init; get; }
public List<MappingFromPhotoPrism>? MappingFromPhotoPrismCollection { init; get; }
public MappingFromPerson? MappingFromPerson { get; } public MappingFromPerson? MappingFromPerson { get; }
public SortingContainer? SortingContainer { get; } public SortingContainer? SortingContainer { get; }

View File

@ -5,6 +5,21 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods;
public interface ILocation public interface ILocation
{ // ... { // ...
Rectangle? TestStatic_GetRectangle(Models.OutputResolution outputResolution, DatabaseFile databaseFile, Marker marker) =>
GetRectangle(outputResolution, databaseFile, marker);
static Rectangle? GetRectangle(Models.OutputResolution outputResolution, DatabaseFile databaseFile, Marker marker) =>
Location.GetRectangle(outputResolution, databaseFile, marker);
Models.Location? TestStatic_GetLocation(Models.OutputResolution outputResolution, DatabaseFile databaseFile, Marker marker) =>
GetLocation(outputResolution, databaseFile, marker);
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);
Rectangle TestStatic_GetRectangle(Rectangle checkRectangle, int locationDigits, int locationFactor, int normalizedRectangle, Models.OutputResolution outputResolution, bool useOldWay) => Rectangle TestStatic_GetRectangle(Rectangle checkRectangle, int locationDigits, int locationFactor, int normalizedRectangle, Models.OutputResolution outputResolution, bool useOldWay) =>
GetRectangle(checkRectangle, locationDigits, locationFactor, normalizedRectangle, outputResolution, useOldWay); GetRectangle(checkRectangle, locationDigits, locationFactor, normalizedRectangle, outputResolution, useOldWay);
static Rectangle GetRectangle(Rectangle checkRectangle, int locationDigits, int locationFactor, int normalizedRectangle, Models.OutputResolution outputResolution, bool useOldWay) => static Rectangle GetRectangle(Rectangle checkRectangle, int locationDigits, int locationFactor, int normalizedRectangle, Models.OutputResolution outputResolution, bool useOldWay) =>

View File

@ -17,6 +17,7 @@ public interface IPath
DeleteEmptyDirectories(rootDirectory, deletedDirectories); DeleteEmptyDirectories(rootDirectory, deletedDirectories);
static void DeleteEmptyDirectories(string rootDirectory, List<string> deletedDirectories) => static void DeleteEmptyDirectories(string rootDirectory, List<string> deletedDirectories) =>
XPath.DeleteEmptyDirectories(rootDirectory, deletedDirectories); XPath.DeleteEmptyDirectories(rootDirectory, deletedDirectories);
// $dirs = gci "" -directory -recurse | Where { (gci $_.fullName).count -eq 0 } | select -expandproperty FullName $dirs | Foreach-Object { Remove-Item $_ }
string[] TestStatic_GetDirectoryNames(string directory) => string[] TestStatic_GetDirectoryNames(string directory) =>
GetDirectoryNames(directory); GetDirectoryNames(directory);

View File

@ -189,4 +189,81 @@ internal abstract class Location
return result.Value; return result.Value;
} }
private static bool Matches(Models.OutputResolution outputResolution, DatabaseFile databaseFile)
{
bool result = outputResolution.Height == databaseFile.FileHeight && outputResolution.Width == databaseFile.FileWidth;
return result;
}
internal static Rectangle? GetRectangle(Models.OutputResolution outputResolution, DatabaseFile databaseFile, Marker marker)
{
Rectangle? result;
bool matches = Matches(outputResolution, databaseFile);
if (!matches)
result = null;
else
result = new((int)Math.Ceiling(marker.X * databaseFile.FileWidth), (int)Math.Ceiling(marker.Y * databaseFile.FileHeight), (int)Math.Ceiling(marker.W * databaseFile.FileWidth), (int)Math.Ceiling(marker.H * databaseFile.FileHeight));
return result;
}
internal static Models.Location? GetLocation(Marker marker, Rectangle rectangle)
{
Models.Location? result;
bool verified = Check(rectangle.Bottom, rectangle.Height, rectangle.Left, rectangle.Right, rectangle.Top, rectangle.Width, zCount: 1, throwException: false);
if (!verified)
result = null;
else
result = new(rectangle.Bottom, marker.Score / 100, rectangle.Left, rectangle.Right, rectangle.Top);
return result;
}
internal static Models.Location? GetLocation(Models.OutputResolution outputResolution, DatabaseFile databaseFile, Marker marker)
{
Models.Location? result;
Rectangle? rectangle = GetRectangle(outputResolution, databaseFile, marker);
if (rectangle is null)
result = null;
else
result = GetLocation(marker, rectangle.Value);
return result;
}
internal static List<Models.Location> GetLocations(List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, List<Models.Face> faces)
{
List<Models.Location> results = new();
double percent;
Rectangle dlibRectangle;
Rectangle? prismRectangle;
Models.Location? location;
Rectangle intersectRectangle;
foreach (Models.Face face in faces)
{
if (face.Location is null || face.OutputResolution is null)
continue;
foreach (MappingFromPhotoPrism mappingFromPhotoPrism in mappingFromPhotoPrismCollection)
{
dlibRectangle = new(face.Location.Left, face.Location.Top, face.Location.Right - face.Location.Left, face.Location.Bottom - face.Location.Top);
foreach (Marker marker in mappingFromPhotoPrism.Markers)
{
prismRectangle = GetRectangle(face.OutputResolution, mappingFromPhotoPrism.DatabaseFile, marker);
if (prismRectangle is null)
{
location = new(1, 0, 0, 1, 0);
results.Add(location);
continue;
}
location = GetLocation(marker, prismRectangle.Value);
if (location is null)
continue;
intersectRectangle = Rectangle.Intersect(dlibRectangle, prismRectangle.Value);
percent = (double)intersectRectangle.Width * intersectRectangle.Height / (dlibRectangle.Width * dlibRectangle.Height);
if (percent > 0.000001)
continue;
results.Add(location);
}
}
}
return results;
}
} }

View File

@ -60,7 +60,6 @@ public class Configuration
[Display(Name = "Face Area Permille Tolerance"), Required] public int[] RangeFaceAreaPermilleTolerance { get; set; } [Display(Name = "Face Area Permille Tolerance"), Required] public int[] RangeFaceAreaPermilleTolerance { get; set; }
[Display(Name = "Location Minimum Confidence"), Required] public double[] RangeFaceConfidence { get; set; } [Display(Name = "Location Minimum Confidence"), Required] public double[] RangeFaceConfidence { get; set; }
[Display(Name = "Face Distance Tolerance"), Required] public double[] RangeDistanceTolerance { get; set; } [Display(Name = "Face Distance Tolerance"), Required] public double[] RangeDistanceTolerance { get; set; }
[Display(Name = "Retry Images Without a Face"), Required] public bool? RetryImagesWithoutAFaceLocation { get; set; }
[Display(Name = "Reverse"), Required] public bool? Reverse { get; set; } [Display(Name = "Reverse"), Required] public bool? Reverse { get; set; }
[Display(Name = "Save Face Landmark For Output Resolutions"), Required] public string[] SaveFaceLandmarkForOutputResolutions { get; set; } [Display(Name = "Save Face Landmark For Output Resolutions"), Required] public string[] SaveFaceLandmarkForOutputResolutions { get; set; }
[Display(Name = "Save Full Year Of Random Files"), Required] public bool? SaveFullYearOfRandomFiles { get; set; } [Display(Name = "Save Full Year Of Random Files"), Required] public bool? SaveFullYearOfRandomFiles { get; set; }
@ -171,8 +170,6 @@ public class Configuration
throw new NullReferenceException(nameof(configuration.RangeFaceConfidence)); throw new NullReferenceException(nameof(configuration.RangeFaceConfidence));
if (configuration.RangeDistanceTolerance is null || configuration.RangeDistanceTolerance.Length != 3) if (configuration.RangeDistanceTolerance is null || configuration.RangeDistanceTolerance.Length != 3)
throw new NullReferenceException(nameof(configuration.RangeDistanceTolerance)); throw new NullReferenceException(nameof(configuration.RangeDistanceTolerance));
if (configuration.RetryImagesWithoutAFaceLocation is null)
throw new NullReferenceException(nameof(configuration.RetryImagesWithoutAFaceLocation));
if (configuration.Reverse is null) if (configuration.Reverse is null)
throw new NullReferenceException(nameof(configuration.Reverse)); throw new NullReferenceException(nameof(configuration.Reverse));
configuration.SaveFaceLandmarkForOutputResolutions ??= Array.Empty<string>(); configuration.SaveFaceLandmarkForOutputResolutions ??= Array.Empty<string>();
@ -245,7 +242,6 @@ public class Configuration
configuration.RangeFaceAreaPermilleTolerance, configuration.RangeFaceAreaPermilleTolerance,
configuration.RangeFaceConfidence, configuration.RangeFaceConfidence,
configuration.RangeDistanceTolerance, configuration.RangeDistanceTolerance,
configuration.RetryImagesWithoutAFaceLocation.Value,
configuration.Reverse.Value, configuration.Reverse.Value,
configuration.SaveFaceLandmarkForOutputResolutions, configuration.SaveFaceLandmarkForOutputResolutions,
configuration.SaveFullYearOfRandomFiles.Value, configuration.SaveFullYearOfRandomFiles.Value,

View File

@ -58,7 +58,6 @@ public class Configuration
public int[] RangeFaceAreaPermilleTolerance { init; get; } public int[] RangeFaceAreaPermilleTolerance { init; get; }
public double[] RangeFaceConfidence { init; get; } public double[] RangeFaceConfidence { init; get; }
public double[] RangeDistanceTolerance { init; get; } public double[] RangeDistanceTolerance { init; get; }
public bool RetryImagesWithoutAFaceLocation { init; get; }
public bool Reverse { init; get; } public bool Reverse { init; get; }
public string[] SaveFaceLandmarkForOutputResolutions { init; get; } public string[] SaveFaceLandmarkForOutputResolutions { init; get; }
public bool SaveFullYearOfRandomFiles { init; get; } public bool SaveFullYearOfRandomFiles { init; get; }
@ -123,7 +122,6 @@ public class Configuration
int[] rangeFaceAreaPermilleTolerance, int[] rangeFaceAreaPermilleTolerance,
double[] rangeFaceConfidence, double[] rangeFaceConfidence,
double[] rangeDistanceTolerance, double[] rangeDistanceTolerance,
bool retryImagesWithoutAFaceLocation,
bool reverse, bool reverse,
string[] saveFaceLandmarkForOutputResolutions, string[] saveFaceLandmarkForOutputResolutions,
bool saveFullYearOfRandomFiles, bool saveFullYearOfRandomFiles,
@ -187,7 +185,6 @@ public class Configuration
RangeFaceAreaPermilleTolerance = rangeFaceAreaPermilleTolerance; RangeFaceAreaPermilleTolerance = rangeFaceAreaPermilleTolerance;
RangeFaceConfidence = rangeFaceConfidence; RangeFaceConfidence = rangeFaceConfidence;
RangeDistanceTolerance = rangeDistanceTolerance; RangeDistanceTolerance = rangeDistanceTolerance;
RetryImagesWithoutAFaceLocation = retryImagesWithoutAFaceLocation;
Reverse = reverse; Reverse = reverse;
SaveFaceLandmarkForOutputResolutions = saveFaceLandmarkForOutputResolutions; SaveFaceLandmarkForOutputResolutions = saveFaceLandmarkForOutputResolutions;
SaveFullYearOfRandomFiles = saveFullYearOfRandomFiles; SaveFullYearOfRandomFiles = saveFullYearOfRandomFiles;

View File

@ -231,7 +231,7 @@ public class UnitTestFace
(Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(_Configuration); (Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(_Configuration);
FaceRecognition faceRecognition = new(_Configuration.NumberOfJitters, _Configuration.NumberOfTimesToUpsample, model, modelParameter, predictorModel); FaceRecognition faceRecognition = new(_Configuration.NumberOfJitters, _Configuration.NumberOfTimesToUpsample, model, modelParameter, predictorModel);
List<(Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary<FacePart, FacePoint[]>? FaceParts)> collection; List<(Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary<FacePart, FacePoint[]>? FaceParts)> collection;
collection = faceRecognition.GetCollection(image, includeFaceEncoding: true, includeFaceParts: true); collection = faceRecognition.GetCollection(image, locations: new(), includeFaceEncoding: true, includeFaceParts: true);
Assert.IsTrue(collection.Count == 2); Assert.IsTrue(collection.Count == 2);
List<FaceDistance> faceDistanceEncodings = (from l in collection where l.FaceEncoding is not null select new FaceDistance(l.FaceEncoding)).ToList(); List<FaceDistance> faceDistanceEncodings = (from l in collection where l.FaceEncoding is not null select new FaceDistance(l.FaceEncoding)).ToList();
List<FaceDistance> faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncodings[0]); List<FaceDistance> faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncodings[0]);