Switched to ThumbHasher over BlurHasher

This commit is contained in:
2023-05-21 23:56:10 -07:00
parent 514637b9c6
commit a0c880c7ba
26 changed files with 803 additions and 121 deletions

View File

@ -2,7 +2,6 @@
using Phares.Shared;
using ShellProgressBar;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text.Json;
using System.Text.RegularExpressions;
@ -32,8 +31,8 @@ public partial class DlibDotNet
private readonly Serilog.ILogger? _Log;
private readonly D2_FaceParts _FaceParts;
private readonly AppSettings _AppSettings;
private readonly IBlurHasher _IBlurHasher;
private readonly List<string> _Exceptions;
private readonly IThumbHasher _IThumbHasher;
private readonly IsEnvironment _IsEnvironment;
private readonly bool _PropertyRootExistedBefore;
private readonly Models.Configuration _Configuration;
@ -59,7 +58,7 @@ public partial class DlibDotNet
long ticks = DateTime.Now.Ticks;
_Exceptions = new List<string>();
_Log = Serilog.Log.ForContext<DlibDotNet>();
_IBlurHasher = new BlurHash.Models.BlurHasher();
_IThumbHasher = new ThumbHash.Models.C2_ThumbHasher();
Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot);
Models.Configuration configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration);
_Log.Information(propertyConfiguration.RootDirectory);
@ -355,9 +354,8 @@ public partial class DlibDotNet
MapLogic mapLogic,
string outputResolution,
string cResultsFullGroupDirectory,
string dResultsDateGroupDirectory,
string c2ResultsFullGroupDirectory,
string dResultsFullGroupDirectory,
string eDistanceContentDirectory,
List<Tuple<string, DateTime>> sourceDirectoryChanges,
Dictionary<string, List<MappingFromPhotoPrism>> fileNameToCollection,
Container container,
@ -377,7 +375,8 @@ public partial class DlibDotNet
List<string> parseExceptions = new();
List<Tuple<string, DateTime>> subFileTuples = new();
List<KeyValuePair<string, string>> metadataCollection;
if (item.Property is not null && item.Property.Id is not null && !item.Any() && item.Property.BlurHash is null)
FileHolder resizedFileHolder = _Resize.GetResizedFileHolder(item);
if (item.Property is not null && item.Property.Id is not null && resizedFileHolder.Exists && item.Property.ThumbHashBytes is null)
{
(string aResultsFullGroupDirectory, _) = GetResultsFullGroupDirectories();
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, "{}");
@ -389,19 +388,60 @@ public partial class DlibDotNet
string find = "\"CreationTime\":";
if (!json.Contains(find))
throw new NotImplementedException();
#pragma warning disable CA1416
using Image image = Image.FromFile(item.ImageFileHolder.FullName);
#pragma warning restore CA1416
string blurHash = _IBlurHasher.Encode(image);
json = json.Replace(find, $"\"{nameof(item.Property.BlurHash)}\": \"{blurHash}\", {find}");
byte[]? thumbHashBytes = _IThumbHasher.Encode(resizedFileHolder.FullName);
string thumbHashJson = JsonSerializer.Serialize(thumbHashBytes);
json = json.Replace(find, $"\"{nameof(property.ThumbHashBytes)}\": {thumbHashJson}, {find}");
property = JsonSerializer.Deserialize<Shared.Models.Property>(json);
if (property is null || property.BlurHash is null)
if (property is null || property.ThumbHashBytes is null)
throw new NullReferenceException(nameof(property));
json = JsonSerializer.Serialize(property, new JsonSerializerOptions { WriteIndented = true });
if (thumbHashBytes is null || thumbHashBytes.Length != property.ThumbHashBytes.Length)
throw new Exception(nameof(property.ThumbHashBytes));
for (int i = 0; i < thumbHashBytes.Length; i++)
{
if (thumbHashBytes[i] != property.ThumbHashBytes[i])
throw new Exception(nameof(property.ThumbHashBytes));
}
thumbHashBytes = JsonSerializer.Deserialize<byte[]>(thumbHashJson);
if (thumbHashBytes is null || thumbHashBytes.Length != property.ThumbHashBytes.Length)
throw new Exception(nameof(property.ThumbHashBytes));
for (int i = 0; i < thumbHashBytes.Length; i++)
{
if (thumbHashBytes[i] != property.ThumbHashBytes[i])
throw new Exception(nameof(property.ThumbHashBytes));
}
File.WriteAllText(matchFile, json);
File.SetLastWriteTime(matchFile, item.Property.LastWriteTime);
}
}
if (item.Property is not null && item.Property.Id is not null && resizedFileHolder.Exists && item.Property.Width is not null && item.Property.Height is not null && item.Property.ThumbHashBytes is not null)
{
string fileName;
string c2ThumbHasherContentDirectory = Path.Combine(c2ResultsFullGroupDirectory, "()");
string c2ThumbHasherSingletonDirectory = Path.Combine(c2ResultsFullGroupDirectory, "{}");
if (!Directory.Exists(c2ThumbHasherContentDirectory))
_ = Directory.CreateDirectory(c2ThumbHasherContentDirectory);
if (!Directory.Exists(c2ThumbHasherSingletonDirectory))
_ = Directory.CreateDirectory(c2ThumbHasherSingletonDirectory);
MemoryStream memoryStream = _IThumbHasher.GetMemoryStream(item.Property.ThumbHashBytes, item.Property.Width.Value, item.Property.Height.Value);
string thumbHashJson = JsonSerializer.Serialize(item.Property.ThumbHashBytes)[1..^1];
if (!Regex.Matches(thumbHashJson, @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]").Any())
fileName = Path.Combine(c2ThumbHasherSingletonDirectory, $"{thumbHashJson}.png");
else
{
// string thumbHash = BitConverter.ToString(item.Property.ThumbHashBytes).Replace("-", string.Empty);
// fileName = Path.Combine(c2ThumbHasherContentDirectory, $"{thumbHash}.png");
fileName = Path.Combine(c2ThumbHasherContentDirectory, $"{resizedFileHolder.NameWithoutExtension}.png");
}
if (!File.Exists(fileName))
{
using FileStream fileStream = new(fileName, FileMode.CreateNew);
memoryStream.WriteTo(fileStream);
memoryStream.Dispose();
if (resizedFileHolder.LastWriteTime is not null)
File.SetLastWriteTime(fileName, resizedFileHolder.LastWriteTime.Value);
}
}
if (item.Property is not null && item.Property.Id is not null && !item.Any())
{
property = item.Property;
@ -427,7 +467,7 @@ public partial class DlibDotNet
_Log.Information(string.Concat("LastWriteTimeChanged <", item.ImageFileHolder.FullName, '>'));
else if (item.Moved.HasValue && item.Moved.Value)
_Log.Information(string.Concat("Moved <", item.ImageFileHolder.FullName, '>'));
property = propertyLogic.GetProperty(_IBlurHasher, item, subFileTuples, parseExceptions);
property = propertyLogic.GetProperty(_IThumbHasher, item, subFileTuples, parseExceptions);
item.Update(property);
if (propertyHashCode is null)
{
@ -442,7 +482,6 @@ public partial class DlibDotNet
}
if (property is null || item.Property is null)
throw new NullReferenceException(nameof(property));
FileHolder resizedFileHolder = _Resize.GetResizedFileHolder(item);
item.SetResizedFileHolder(_Resize.FileNameExtension, resizedFileHolder);
string facesDirectory = _Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution) ? _Faces.GetFacesDirectory(dResultsFullGroupDirectory, item) : string.Empty;
string facePartsDirectory = _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution) ? _FaceParts.GetFacePartsDirectory(_Configuration.PropertyConfiguration, dResultsFullGroupDirectory, item, includeNameWithoutExtension: true) : string.Empty;
@ -485,7 +524,7 @@ public partial class DlibDotNet
if ((_Configuration.DistanceMoveUnableToMatch || _Configuration.DistanceRenameToMatch)
&& _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution)
&& collection is not null && faceCollection.All(l => !l.Saved))
_Distance.LookForMatchFacesAndPossiblyRename(_Faces.FileNameExtension, eDistanceContentDirectory, mappingFromItem, faces, collection);
_Distance.LookForMatchFacesAndPossiblyRename(_Faces.FileNameExtension, mappingFromItem, faces, collection);
if (_Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution))
{
bool saveRotated = false;
@ -509,10 +548,9 @@ public partial class DlibDotNet
MapLogic mapLogic,
string outputResolution,
string cResultsFullGroupDirectory,
string dResultsDateGroupDirectory,
string c2ResultsFullGroupDirectory,
string dResultsFullGroupDirectory,
string d2ResultsFullGroupDirectory,
string eDistanceContentDirectory,
List<Tuple<string, DateTime>> sourceDirectoryChanges,
Dictionary<string, List<MappingFromPhotoPrism>> fileNameToCollection,
Container container,
@ -540,9 +578,8 @@ public partial class DlibDotNet
mapLogic,
outputResolution,
cResultsFullGroupDirectory,
dResultsDateGroupDirectory,
c2ResultsFullGroupDirectory,
dResultsFullGroupDirectory,
eDistanceContentDirectory,
sourceDirectoryChanges,
fileNameToCollection,
container,
@ -620,7 +657,7 @@ public partial class DlibDotNet
return new(aResultsFullGroupDirectory, bResultsFullGroupDirectory);
}
private (string, string, string) GetResultsFullGroupDirectories(string outputResolution)
private (string, string, string, string) GetResultsFullGroupDirectories(string outputResolution)
{
string cResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(
_Configuration.PropertyConfiguration,
@ -629,6 +666,13 @@ public partial class DlibDotNet
includeResizeGroup: true,
includeModel: false,
includePredictorModel: false);
string c2ResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(
_Configuration.PropertyConfiguration,
nameof(ThumbHash.Models.C2_ThumbHasher),
outputResolution,
includeResizeGroup: true,
includeModel: false,
includePredictorModel: false);
string dResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(
_Configuration.PropertyConfiguration,
nameof(D_Face),
@ -643,10 +687,10 @@ public partial class DlibDotNet
includeResizeGroup: true,
includeModel: true,
includePredictorModel: true);
return new(cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory);
return new(cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory);
}
private void FullDoWork(string argZero, string propertyRoot, long ticks, string aResultsFullGroupDirectory, string bResultsFullGroupDirectory, int t, Container[] containers, A_Property propertyLogic, B_Metadata metadata, string eDistanceContentDirectory, Dictionary<string, List<MappingFromPhotoPrism>> fileNameToCollection, ReadOnlyDictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> idToLocationContainers, MapLogic mapLogic)
private void FullDoWork(string argZero, string propertyRoot, long ticks, string aResultsFullGroupDirectory, string bResultsFullGroupDirectory, int t, Container[] containers, A_Property propertyLogic, B_Metadata metadata, Dictionary<string, List<MappingFromPhotoPrism>> fileNameToCollection, ReadOnlyDictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> idToLocationContainers, MapLogic mapLogic)
{
if (_Log is null)
throw new NullReferenceException(nameof(_Log));
@ -659,6 +703,7 @@ public partial class DlibDotNet
bool anyNullOrNoIsUniqueFileName;
string cResultsFullGroupDirectory;
string dResultsFullGroupDirectory;
string c2ResultsFullGroupDirectory;
string d2ResultsFullGroupDirectory;
int containersLength = containers.Length;
List<Tuple<string, DateTime>> sourceDirectoryChanges = new();
@ -667,7 +712,7 @@ public partial class DlibDotNet
foreach (string outputResolution in _Configuration.OutputResolutions)
{
total = 0;
(cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution);
(cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution);
for (int i = 0; i < containers.Length; i++)
{
container = containers[i];
@ -695,10 +740,9 @@ public partial class DlibDotNet
mapLogic,
outputResolution,
cResultsFullGroupDirectory,
dResultsDateGroupDirectory,
c2ResultsFullGroupDirectory,
dResultsFullGroupDirectory,
d2ResultsFullGroupDirectory,
eDistanceContentDirectory,
sourceDirectoryChanges,
fileNameToCollection,
container,
@ -911,13 +955,14 @@ public partial class DlibDotNet
string? directoryName;
string cResultsFullGroupDirectory;
string dResultsFullGroupDirectory;
string c2ResultsFullGroupDirectory;
string d2ResultsFullGroupDirectory;
List<int> distinctFilteredIds = Shared.Models.Stateless.Methods.IContainer.GetFilteredDistinctIds(_Configuration.PropertyConfiguration, containers);
LookForAbandoned(idToLocationContainers, distinctFilteredIds);
LookForAbandoned(bResultsFullGroupDirectory, distinctFilteredIds);
foreach (string outputResolution in _Configuration.OutputResolutions)
{
(cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution);
(cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution);
directories = Directory.GetDirectories(cResultsFullGroupDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string directory in directories)
{
@ -1101,6 +1146,7 @@ public partial class DlibDotNet
string bResultsFullGroupDirectory;
string cResultsFullGroupDirectory;
string dResultsFullGroupDirectory;
string c2ResultsFullGroupDirectory;
string d2ResultsFullGroupDirectory;
string fPhotoPrismContentDirectory;
string fPhotoPrismSingletonDirectory;
@ -1152,7 +1198,7 @@ public partial class DlibDotNet
Shared.Models.Stateless.Methods.IGenealogicalDataCommunication.CreateTree(_Configuration.MappingDefaultName, _Configuration.PersonBirthdayFormat, _Configuration.PropertyConfiguration.ResultAllInOne, _PersonContainers, _GenealogicalDataCommunicationHeaderLines, _GenealogicalDataCommunicationFooterLines, ticks, a2PeopleContentDirectory, personKeyToIds);
ReadOnlyDictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> idToLocationContainers = mapLogic.GetIdToLocationContainers();
fileNameToCollection = !Directory.Exists(fPhotoPrismSingletonDirectory) ? fileNameToCollection = new() : F_PhotoPrism.GetFileNameToCollection(fPhotoPrismSingletonDirectory);
FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, bResultsFullGroupDirectory, t, containers, propertyLogic, metadata, eDistanceContentDirectory, fileNameToCollection, idToLocationContainers, mapLogic);
FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, bResultsFullGroupDirectory, t, containers, propertyLogic, metadata, fileNameToCollection, idToLocationContainers, mapLogic);
if (_Configuration.LookForAbandoned)
LookForAbandoned(bResultsFullGroupDirectory, containers, idToLocationContainers);
_Distance.Clear();
@ -1175,7 +1221,7 @@ public partial class DlibDotNet
mapLogic.SaveShortcutsForOutputResolutionsPreMapLogic(eDistanceContentDirectory, personKeyToIds, distinctFilteredMappingCollection);
if (!string.IsNullOrEmpty(a2PeopleContentDirectory) && _Configuration.SaveFilteredOriginalImagesFromJLinksForOutputResolutions.Contains(outputResolution))
mapLogic.SaveFilteredOriginalImagesFromJLinks(_Configuration.JLinks, _PersonContainers, a2PeopleContentDirectory, personKeyToIds, distinctFilteredMappingCollection, totalNotMapped);
(cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution);
(cResultsFullGroupDirectory, c2ResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory) = GetResultsFullGroupDirectories(outputResolution);
if (_ArgZeroIsConfigurationRootDirectory
&& _Configuration.SaveResizedSubfiles
&& outputResolution == _Configuration.OutputResolutions[0]