PhotoPrism for more locations

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

View File

@ -43,7 +43,6 @@ public class D_Face
private readonly int _FaceDistanceHiddenImageFactor;
private readonly EncoderParameters _EncoderParameters;
private readonly ImageCodecInfo _HiddenImageCodecInfo;
private readonly bool _RetryImagesWithoutAFaceLocation;
private readonly bool _ForceFaceLastWriteTimeToCreationTime;
private readonly EncoderParameters _HiddenEncoderParameters;
private readonly JsonSerializerOptions _WriteIndentedAndWhenWritingNull;
@ -63,7 +62,6 @@ public class D_Face
string modelDirectory,
string modelName,
bool overrideForFaceImages,
bool retryImagesWithoutAFaceLocation,
string predictorModelName,
bool propertiesChangedForFaces)
{
@ -81,7 +79,6 @@ public class D_Face
_CheckDFaceAndUpWriteDates = checkDFaceAndUpWriteDates;
_PropertiesChangedForFaces = propertiesChangedForFaces;
_FaceDistanceHiddenImageFactor = faceDistanceHiddenImageFactor;
_RetryImagesWithoutAFaceLocation = retryImagesWithoutAFaceLocation;
_ForceFaceLastWriteTimeToCreationTime = forceFaceLastWriteTimeToCreationTime;
(Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(modelDirectory, modelName, predictorModelName);
_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)
throw new NullReferenceException(nameof(_Log));
@ -225,25 +222,18 @@ public class D_Face
throw new NullReferenceException(nameof(_Configuration.NumberOfTimesToUpsample));
List<Shared.Models.Face> results = new();
FaceRecognitionDotNet.Image? unknownImage;
if (!mappingFromItem.ResizedFileHolder.Exists)
unknownImage = null;
else
try
{ unknownImage = FaceRecognition.LoadImageFile(mappingFromItem.ResizedFileHolder.FullName); }
catch (Exception)
{
try
{ unknownImage = FaceRecognition.LoadImageFile(mappingFromItem.ResizedFileHolder.FullName); }
catch (Exception)
{
unknownImage = null;
_Log.Info(string.Concat(new StackFrame().GetMethod()?.Name, " <", mappingFromItem.ResizedFileHolder.FullName, ">"));
}
unknownImage = null;
_Log.Info(string.Concat(new StackFrame().GetMethod()?.Name, " <", mappingFromItem.ResizedFileHolder.FullName, ">"));
}
if (unknownImage is null)
results.Add(new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, location: null));
else
if (unknownImage is not null)
{
List<(Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary<FacePart, FacePoint[]>? FaceParts)> collection;
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())
results.Add(new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, location: null));
else
@ -268,8 +258,6 @@ public class D_Face
unknownImage.Dispose();
faceRecognition.Dispose();
}
if (!results.Any())
throw new Exception();
return results;
}
@ -303,12 +291,13 @@ public class D_Face
#pragma warning restore CA1416
public List<Shared.Models.Face> GetFaces(string dResultsFullGroupDirectory, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation)
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;
if (string.IsNullOrEmpty(dResultsFullGroupDirectory))
throw new NullReferenceException(nameof(dResultsFullGroupDirectory));
string json;
List<Location> locations = new();
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();
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));
}
}
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);
if (wasNull || (!wasNull && results.Any(l => l.Location is not null)))
results = GetFaces(property, mappingFromItem, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, locations);
if (!results.Any())
File.Move(mappingFromItem.ResizedFileHolder.FullName, $"{mappingFromItem.ResizedFileHolder.FullName}.err");
else
{
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))
if (!_ForceFaceLastWriteTimeToCreationTime)
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), DateTime.Now));
else
{
@ -370,126 +362,6 @@ public class D_Face
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)
{
FileInfo fileInfo;