IgnoreExtensions-nef

Config-LoadPhotoPrismLocations
TestMethodIntersect
This commit is contained in:
Mike Phares 2023-06-23 19:19:41 -07:00
parent 1d0506d74c
commit 6f22929136
34 changed files with 364 additions and 140 deletions

View File

@ -13,6 +13,9 @@ completedColumns:
## Todo ## Todo
- [nef-support](tasks/nef-support.md)
- [determine-if-location-container-collection-is-needed-in-get-faces](tasks/determine-if-location-container-collection-is-needed-in-get-faces.md)
- [use-eyes-to-find-orientation](tasks/use-eyes-to-find-orientation.md)
- [use-photo-prism-to-map](tasks/use-photo-prism-to-map.md) - [use-photo-prism-to-map](tasks/use-photo-prism-to-map.md)
- [import-face-region-metadata](tasks/import-face-region-metadata.md) - [import-face-region-metadata](tasks/import-face-region-metadata.md)

View File

@ -0,0 +1,17 @@
---
created: 2023-06-12T15:44:11.932Z
updated: 2023-06-12T15:45:59.891Z
assigned: ""
progress: 0
tags: []
---
# determine-if-location-container-collection-is-needed-in-get-faces
```c#
locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(collection, results, mappingFromPhotoPrismCollection, _RectangleIntersectMinimum);
```
## Sub-tasks
- [ ] See code above

View File

@ -0,0 +1,13 @@
---
created: 2023-06-12T15:44:11.932Z
updated: 2023-06-12T15:45:59.891Z
assigned: ""
progress: 0
tags: []
---
# nef-support
## Sub-tasks
- [ ] asdf

View File

@ -0,0 +1,13 @@
---
created: 2023-06-12T15:44:11.932Z
updated: 2023-06-12T15:45:59.891Z
assigned: ""
progress: 0
tags: []
---
# use-eyes-to-find-orientation
## Sub-tasks
- [ ] asdf

View File

@ -18,6 +18,7 @@
"Greyscale", "Greyscale",
"Hasher", "Hasher",
"jfif", "jfif",
"JOSN",
"mmod", "mmod",
"Nicéphore", "Nicéphore",
"Niépce", "Niépce",
@ -42,5 +43,8 @@
"**/.git": false "**/.git": false
}, },
"coverage-gutters.coverageBaseDir": "./.vscode/ReportGenerator/Cobertura/*", "coverage-gutters.coverageBaseDir": "./.vscode/ReportGenerator/Cobertura/*",
"extensions.ignoreRecommendations": true "extensions.ignoreRecommendations": true,
"[markdown]": {
"editor.wordWrap": "off"
}
} }

View File

@ -92,6 +92,8 @@
"IgnoreExtensions": [ "IgnoreExtensions": [
".gif", ".gif",
".GIF", ".GIF",
".nef",
".NEF",
".pdf", ".pdf",
".PDF" ".PDF"
], ],

View File

@ -72,6 +72,8 @@
"IgnoreExtensions": [ "IgnoreExtensions": [
".gif", ".gif",
".GIF", ".GIF",
".nef",
".NEF",
".pdf", ".pdf",
".PDF" ".PDF"
], ],

View File

@ -72,6 +72,8 @@
"IgnoreExtensions": [ "IgnoreExtensions": [
".gif", ".gif",
".GIF", ".GIF",
".nef",
".NEF",
".pdf", ".pdf",
".PDF" ".PDF"
], ],

View File

@ -74,6 +74,8 @@
"IgnoreExtensions": [ "IgnoreExtensions": [
".gif", ".gif",
".GIF", ".GIF",
".nef",
".NEF",
".pdf", ".pdf",
".PDF" ".PDF"
], ],

View File

@ -69,6 +69,8 @@
"IgnoreExtensions": [ "IgnoreExtensions": [
".gif", ".gif",
".GIF", ".GIF",
".nef",
".NEF",
".pdf", ".pdf",
".PDF" ".PDF"
], ],

View File

@ -23,7 +23,7 @@ public partial class E_Distance
private readonly double _RangeDistanceToleranceAverage; private readonly double _RangeDistanceToleranceAverage;
private readonly List<string> _DuplicateMappedFaceFiles; private readonly List<string> _DuplicateMappedFaceFiles;
public E_Distance(bool distanceMoveUnableToMatch, bool distanceRenameToMatch, int faceConfidencePercent, float[] rangeDistanceTolerance, float[] rangeFaceConfidence, float[] rectangleIntersectMinimum) public E_Distance(bool distanceMoveUnableToMatch, bool distanceRenameToMatch, int faceConfidencePercent, float[] rangeDistanceTolerance, float[] rangeFaceConfidence, float[] rectangleIntersectMinimums)
{ {
_Debug = new(); _Debug = new();
_Moved = new(); _Moved = new();
@ -36,7 +36,7 @@ public partial class E_Distance
_DistanceRenameToMatch = distanceRenameToMatch; _DistanceRenameToMatch = distanceRenameToMatch;
_FaceConfidencePercent = faceConfidencePercent; _FaceConfidencePercent = faceConfidencePercent;
_DistanceMoveUnableToMatch = distanceMoveUnableToMatch; _DistanceMoveUnableToMatch = distanceMoveUnableToMatch;
_RectangleIntersectMinimum = rectangleIntersectMinimum.Max(); _RectangleIntersectMinimum = rectangleIntersectMinimums.Max();
_RangeDistanceToleranceAverage = rangeDistanceTolerance.Average(); _RangeDistanceToleranceAverage = rangeDistanceTolerance.Average();
} }
@ -199,7 +199,7 @@ public partial class E_Distance
} }
} }
public void LookForMatchFacesAndPossiblyRename(string facesFileNameExtension, MappingFromItem mappingFromItem, List<Face> faces, List<LocationContainer<MetadataExtractor.Directory>> collection) public void LookForMatchFacesAndPossiblyRename(string facesFileNameExtension, MappingFromItem mappingFromItem, List<Face> faces, List<LocationContainer<MetadataExtractor.Directory>> locationContainers)
{ {
string? json; string? json;
string fileName; string fileName;
@ -211,7 +211,7 @@ public partial class E_Distance
Face[] filteredFaces = (from l in faces where l.FaceEncoding is not null && l.Location is not null && l.OutputResolution is not null select l).ToArray(); Face[] filteredFaces = (from l in faces where l.FaceEncoding is not null && l.Location is not null && l.OutputResolution is not null select l).ToArray();
if (filteredFaces.Length != faces.Count) if (filteredFaces.Length != faces.Count)
checkFaces.Clear(); checkFaces.Clear();
foreach (LocationContainer<MetadataExtractor.Directory>? locationContainer in collection) foreach (LocationContainer<MetadataExtractor.Directory>? locationContainer in locationContainers)
{ {
if (_Renamed.Contains(locationContainer.File)) if (_Renamed.Contains(locationContainer.File))
continue; continue;

View File

@ -71,6 +71,8 @@
"IgnoreExtensions": [ "IgnoreExtensions": [
".gif", ".gif",
".GIF", ".GIF",
".nef",
".NEF",
".pdf", ".pdf",
".PDF" ".PDF"
], ],

View File

@ -34,12 +34,14 @@ public class D_Face
private readonly Serilog.ILogger? _Log; private readonly Serilog.ILogger? _Log;
private readonly bool _OverrideForFaceImages; private readonly bool _OverrideForFaceImages;
private readonly Configuration _Configuration; private readonly Configuration _Configuration;
private readonly bool _LoadPhotoPrismLocations;
private readonly ImageCodecInfo _ImageCodecInfo; private readonly ImageCodecInfo _ImageCodecInfo;
private readonly ModelParameter _ModelParameter; private readonly ModelParameter _ModelParameter;
private readonly PredictorModel _PredictorModel; private readonly PredictorModel _PredictorModel;
private readonly bool _CheckDFaceAndUpWriteDates; private readonly bool _CheckDFaceAndUpWriteDates;
private readonly bool _PropertiesChangedForFaces; private readonly bool _PropertiesChangedForFaces;
private readonly ConstructorInfo _ConstructorInfo; private readonly ConstructorInfo _ConstructorInfo;
private readonly float _RectangleIntersectMinimum;
private readonly int _FaceDistanceHiddenImageFactor; private readonly int _FaceDistanceHiddenImageFactor;
private readonly EncoderParameters _EncoderParameters; private readonly EncoderParameters _EncoderParameters;
private readonly ImageCodecInfo _HiddenImageCodecInfo; private readonly ImageCodecInfo _HiddenImageCodecInfo;
@ -59,11 +61,13 @@ public class D_Face
string hiddenFileNameExtension, string hiddenFileNameExtension,
ImageCodecInfo hiddenImageCodecInfo, ImageCodecInfo hiddenImageCodecInfo,
ImageCodecInfo imageCodecInfo, ImageCodecInfo imageCodecInfo,
bool loadPhotoPrismLocations,
string modelDirectory, string modelDirectory,
string modelName, string modelName,
bool overrideForFaceImages, bool overrideForFaceImages,
string predictorModelName, string predictorModelName,
bool propertiesChangedForFaces) bool propertiesChangedForFaces,
float[] rectangleIntersectMinimums)
{ {
_ArgZero = argZero; _ArgZero = argZero;
_Configuration = configuration; _Configuration = configuration;
@ -76,17 +80,17 @@ public class D_Face
_OverrideForFaceImages = overrideForFaceImages; _OverrideForFaceImages = overrideForFaceImages;
_HiddenEncoderParameters = hiddenEncoderParameters; _HiddenEncoderParameters = hiddenEncoderParameters;
_HiddenFileNameExtension = hiddenFileNameExtension; _HiddenFileNameExtension = hiddenFileNameExtension;
_LoadPhotoPrismLocations = loadPhotoPrismLocations;
_CheckDFaceAndUpWriteDates = checkDFaceAndUpWriteDates; _CheckDFaceAndUpWriteDates = checkDFaceAndUpWriteDates;
_PropertiesChangedForFaces = propertiesChangedForFaces; _PropertiesChangedForFaces = propertiesChangedForFaces;
_RectangleIntersectMinimum = rectangleIntersectMinimums.Min();
_FaceDistanceHiddenImageFactor = faceDistanceHiddenImageFactor; _FaceDistanceHiddenImageFactor = faceDistanceHiddenImageFactor;
_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;
_PredictorModel = predictorModel; _PredictorModel = predictorModel;
_ModelParameter = modelParameter; _ModelParameter = modelParameter;
ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, Array.Empty<Type>(), null); ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, Array.Empty<Type>(), null) ?? throw new Exception();
if (constructorInfo is null)
throw new Exception();
_ConstructorInfo = constructorInfo; _ConstructorInfo = constructorInfo;
_WriteIndentedAndWhenWritingNull = new JsonSerializerOptions { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }; _WriteIndentedAndWhenWritingNull = new JsonSerializerOptions { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull };
} }
@ -294,7 +298,7 @@ public class D_Face
#pragma warning restore CA1416 #pragma warning restore CA1416
private static List<LocationContainer<MetadataExtractor.Directory>> GetCollection(string outputResolution, List<LocationContainer<MetadataExtractor.Directory>> collection, Dictionary<string, int[]> outputResolutionToResize, List<Shared.Models.Face> faces) private static List<LocationContainer<MetadataExtractor.Directory>> GetLocationContainers(string outputResolution, List<LocationContainer<MetadataExtractor.Directory>> locationContainers, Dictionary<string, int[]> outputResolutionToResize, List<Shared.Models.Face> faces)
{ {
List<LocationContainer<MetadataExtractor.Directory>> results = new(); List<LocationContainer<MetadataExtractor.Directory>> results = new();
string? json; string? json;
@ -309,7 +313,7 @@ public class D_Face
continue; continue;
skip.Add(Shared.Models.Stateless.Methods.ILocation.GetWholePercentages(face.Location, ILocation.Digits, face.OutputResolution)); skip.Add(Shared.Models.Stateless.Methods.ILocation.GetWholePercentages(face.Location, ILocation.Digits, face.OutputResolution));
} }
foreach (LocationContainer<MetadataExtractor.Directory> locationContainer in collection) foreach (LocationContainer<MetadataExtractor.Directory> locationContainer in locationContainers)
{ {
if (locationContainer.Directories is null) if (locationContainer.Directories is null)
continue; continue;
@ -340,7 +344,7 @@ public class D_Face
return results; return results;
} }
public List<Shared.Models.Face> GetFaces(string outputResolution, string dResultsFullGroupDirectory, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<LocationContainer<MetadataExtractor.Directory>>? collection, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection) public List<Shared.Models.Face> GetFaces(string outputResolution, string dResultsFullGroupDirectory, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<LocationContainer<MetadataExtractor.Directory>>? locationContainers, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection)
{ {
List<Shared.Models.Face>? results; List<Shared.Models.Face>? results;
if (string.IsNullOrEmpty(dResultsFullGroupDirectory)) if (string.IsNullOrEmpty(dResultsFullGroupDirectory))
@ -383,15 +387,15 @@ public class D_Face
parseExceptions.Add(nameof(D_Face)); parseExceptions.Add(nameof(D_Face));
} }
} }
List<LocationContainer<MetadataExtractor.Directory>> locationContainers; List<LocationContainer<MetadataExtractor.Directory>> collection;
if (results is null || collection is null) if (results is null || locationContainers is null)
locationContainers = new(); collection = new();
else else
locationContainers = GetCollection(outputResolution, collection, outputResolutionToResize, results); collection = GetLocationContainers(outputResolution, locationContainers, outputResolutionToResize, results);
if (mappingFromPhotoPrismCollection is null || results is null) if (!_LoadPhotoPrismLocations || mappingFromPhotoPrismCollection is null || results is null)
locations = (from l in locationContainers where l is not null select l.Location).ToList(); locations = (from l in collection where l is not null select l.Location).ToList();
else else
locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(mappingFromPhotoPrismCollection, results, locationContainers); locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(collection, results, mappingFromPhotoPrismCollection, _RectangleIntersectMinimum);
if (results is null || (locations is not null && locations.Any())) if (results is null || (locations is not null && locations.Any()))
{ {
results = GetFaces(outputResolution, property, mappingFromItem, outputResolutionToResize, locations); results = GetFaces(outputResolution, property, mappingFromItem, outputResolutionToResize, locations);

View File

@ -3,7 +3,7 @@
/// <summary> /// <summary>
/// Represents an ordered pair of integer x- and y-coordinates that defines a point in a two-dimensional plane. /// Represents an ordered pair of integer x- and y-coordinates that defines a point in a two-dimensional plane.
/// </summary> /// </summary>
public struct Point : IEquatable<Point> public readonly struct Point : IEquatable<Point>
{ {
#region Constructors #region Constructors
@ -73,7 +73,9 @@ public struct Point : IEquatable<Point>
/// Returns the hash code for this <see cref="Point"/>. /// Returns the hash code for this <see cref="Point"/>.
/// </summary> /// </summary>
/// <returns>The hash code for this <see cref="Point"/> structure.</returns> /// <returns>The hash code for this <see cref="Point"/> structure.</returns>
#pragma warning disable IDE0070
public override int GetHashCode() public override int GetHashCode()
#pragma warning restore IDE0070
{ {
int hashCode = 1861411795; int hashCode = 1861411795;
hashCode = hashCode * -1521134295 + X.GetHashCode(); hashCode = hashCode * -1521134295 + X.GetHashCode();

View File

@ -95,11 +95,13 @@ public partial class DlibDotNet
hiddenFileNameExtension, hiddenFileNameExtension,
hiddenImageCodecInfo, hiddenImageCodecInfo,
imageCodecInfo, imageCodecInfo,
configuration.LoadPhotoPrismLocations,
configuration.ModelDirectory, configuration.ModelDirectory,
configuration.ModelName, configuration.ModelName,
configuration.OverrideForFaceImages, configuration.OverrideForFaceImages,
configuration.PredictorModelName, configuration.PredictorModelName,
configuration.PropertiesChangedForFaces); configuration.PropertiesChangedForFaces,
configuration.RectangleIntersectMinimums);
} }
{ {
(ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetGifLowQuality(); (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetGifLowQuality();
@ -456,14 +458,14 @@ public partial class DlibDotNet
else else
{ {
List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection; List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection;
List<LocationContainer<MetadataExtractor.Directory>>? collection; List<LocationContainer<MetadataExtractor.Directory>>? locationContainers;
if (item.Property?.Id is null) if (item.Property?.Id is null)
collection = null; locationContainers = null;
else else
_ = idToLocationContainers.TryGetValue(item.Property.Id.Value, out collection); _ = idToLocationContainers.TryGetValue(item.Property.Id.Value, out locationContainers);
if (!fileNameToCollection.TryGetValue(mappingFromItem.Id, out mappingFromPhotoPrismCollection)) if (!fileNameToCollection.TryGetValue(mappingFromItem.Id, out mappingFromPhotoPrismCollection))
mappingFromPhotoPrismCollection = null; mappingFromPhotoPrismCollection = null;
faces = _Faces.GetFaces(outputResolution, dResultsFullGroupDirectory, subFileTuples, parseExceptions, property, mappingFromItem, outputResolutionToResize, collection, mappingFromPhotoPrismCollection); faces = _Faces.GetFaces(outputResolution, dResultsFullGroupDirectory, subFileTuples, parseExceptions, property, mappingFromItem, outputResolutionToResize, locationContainers, mappingFromPhotoPrismCollection);
if (_AppSettings.MaxDegreeOfParallelism < 2) if (_AppSettings.MaxDegreeOfParallelism < 2)
ticks = LogDelta(ticks, nameof(D_Face.GetFaces)); ticks = LogDelta(ticks, nameof(D_Face.GetFaces));
List<(Shared.Models.Face, FileInfo?, string, bool Saved)> faceCollection = _Faces.SaveFaces(_FaceParts.FileNameExtension, dResultsFullGroupDirectory, subFileTuples, parseExceptions, mappingFromItem, facesDirectory, faces); List<(Shared.Models.Face, FileInfo?, string, bool Saved)> faceCollection = _Faces.SaveFaces(_FaceParts.FileNameExtension, dResultsFullGroupDirectory, subFileTuples, parseExceptions, mappingFromItem, facesDirectory, faces);
@ -474,8 +476,8 @@ public partial class DlibDotNet
ticks = LogDelta(ticks, nameof(D_Face.SaveFaces)); ticks = LogDelta(ticks, nameof(D_Face.SaveFaces));
if ((_Configuration.DistanceMoveUnableToMatch || _Configuration.DistanceRenameToMatch) if ((_Configuration.DistanceMoveUnableToMatch || _Configuration.DistanceRenameToMatch)
&& _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution) && _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution)
&& collection is not null && faceCollection.All(l => !l.Saved)) && locationContainers is not null && faceCollection.All(l => !l.Saved))
_Distance.LookForMatchFacesAndPossiblyRename(_Faces.FileNameExtension, mappingFromItem, faces, collection); _Distance.LookForMatchFacesAndPossiblyRename(_Faces.FileNameExtension, mappingFromItem, faces, locationContainers);
if (_Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) if (_Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution))
{ {
bool saveRotated = false; bool saveRotated = false;
@ -881,11 +883,11 @@ public partial class DlibDotNet
private static void LookForAbandoned(ReadOnlyDictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> idToLocationContainers, List<int> distinctFilteredIds) private static void LookForAbandoned(ReadOnlyDictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> idToLocationContainers, List<int> distinctFilteredIds)
{ {
List<string> renameCollection = new(); List<string> renameCollection = new();
foreach (KeyValuePair<int, List<LocationContainer<MetadataExtractor.Directory>>> idToCollection in idToLocationContainers) foreach (KeyValuePair<int, List<LocationContainer<MetadataExtractor.Directory>>> keyValuePair in idToLocationContainers)
{ {
if (distinctFilteredIds.Contains(idToCollection.Key)) if (distinctFilteredIds.Contains(keyValuePair.Key))
continue; continue;
foreach (LocationContainer<MetadataExtractor.Directory> locationContainer in idToCollection.Value) foreach (LocationContainer<MetadataExtractor.Directory> locationContainer in keyValuePair.Value)
{ {
if (locationContainer.File.Contains('!')) if (locationContainer.File.Contains('!'))
continue; continue;

View File

@ -34,6 +34,7 @@ public class Configuration
[Display(Name = "Julie Phares Copy Birthdays"), Required] public string[] JLinks { get; set; } [Display(Name = "Julie Phares Copy Birthdays"), Required] public string[] JLinks { get; set; }
[Display(Name = "Load Or Create Then Save Distance Results"), Required] public string[] LoadOrCreateThenSaveDistanceResultsForOutputResolutions { get; set; } [Display(Name = "Load Or Create Then Save Distance Results"), Required] public string[] LoadOrCreateThenSaveDistanceResultsForOutputResolutions { get; set; }
[Display(Name = "Load Or Create Then Save Image Faces Results"), Required] public string[] LoadOrCreateThenSaveImageFacesResultsForOutputResolutions { get; set; } [Display(Name = "Load Or Create Then Save Image Faces Results"), Required] public string[] LoadOrCreateThenSaveImageFacesResultsForOutputResolutions { get; set; }
[Display(Name = "Load PhotoPrism Locations"), Required] public bool? LoadPhotoPrismLocations { get; set; }
[Display(Name = "Location Digits"), Required] public int? LocationDigits { get; set; } [Display(Name = "Location Digits"), Required] public int? LocationDigits { get; set; }
[Display(Name = "Location Factor"), Required] public int? LocationFactor { get; set; } [Display(Name = "Location Factor"), Required] public int? LocationFactor { get; set; }
[Display(Name = "Look for Abandoned"), Required] public bool? LookForAbandoned { get; set; } [Display(Name = "Look for Abandoned"), Required] public bool? LookForAbandoned { get; set; }
@ -145,6 +146,8 @@ public class Configuration
configuration.IgnoreRelativePaths ??= Array.Empty<string>(); configuration.IgnoreRelativePaths ??= Array.Empty<string>();
configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions ??= Array.Empty<string>(); configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions ??= Array.Empty<string>();
configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions ??= Array.Empty<string>(); configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions ??= Array.Empty<string>();
if (configuration.LoadPhotoPrismLocations is null)
throw new NullReferenceException(nameof(configuration.LoadPhotoPrismLocations));
if (configuration.LocationDigits is null) if (configuration.LocationDigits is null)
throw new NullReferenceException(nameof(configuration.LocationDigits)); throw new NullReferenceException(nameof(configuration.LocationDigits));
if (configuration.LocationFactor is null) if (configuration.LocationFactor is null)
@ -261,6 +264,7 @@ public class Configuration
configuration.JLinks, configuration.JLinks,
configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions, configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions,
configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions, configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions,
configuration.LoadPhotoPrismLocations.Value,
configuration.LocationDigits.Value, configuration.LocationDigits.Value,
configuration.LocationFactor.Value, configuration.LocationFactor.Value,
configuration.LookForAbandoned.Value, configuration.LookForAbandoned.Value,

View File

@ -33,6 +33,7 @@ public class Configuration
public string[] JLinks { init; get; } public string[] JLinks { init; get; }
public string[] LoadOrCreateThenSaveDistanceResultsForOutputResolutions { init; get; } public string[] LoadOrCreateThenSaveDistanceResultsForOutputResolutions { init; get; }
public string[] LoadOrCreateThenSaveImageFacesResultsForOutputResolutions { init; get; } public string[] LoadOrCreateThenSaveImageFacesResultsForOutputResolutions { init; get; }
public bool LoadPhotoPrismLocations { init; get; }
public int LocationDigits { init; get; } public int LocationDigits { init; get; }
public int LocationFactor { init; get; } public int LocationFactor { init; get; }
public bool LookForAbandoned { init; get; } public bool LookForAbandoned { init; get; }
@ -112,6 +113,7 @@ public class Configuration
string[] jLinks, string[] jLinks,
string[] loadOrCreateThenSaveDistanceResultsForOutputResolutions, string[] loadOrCreateThenSaveDistanceResultsForOutputResolutions,
string[] loadOrCreateThenSaveImageFacesResultsForOutputResolutions, string[] loadOrCreateThenSaveImageFacesResultsForOutputResolutions,
bool loadPhotoPrismLocations,
int locationDigits, int locationDigits,
int locationFactor, int locationFactor,
bool lookForAbandoned, bool lookForAbandoned,
@ -190,6 +192,7 @@ public class Configuration
JLinks = jLinks; JLinks = jLinks;
LoadOrCreateThenSaveDistanceResultsForOutputResolutions = loadOrCreateThenSaveDistanceResultsForOutputResolutions; LoadOrCreateThenSaveDistanceResultsForOutputResolutions = loadOrCreateThenSaveDistanceResultsForOutputResolutions;
LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = loadOrCreateThenSaveImageFacesResultsForOutputResolutions; LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = loadOrCreateThenSaveImageFacesResultsForOutputResolutions;
LoadPhotoPrismLocations = loadPhotoPrismLocations;
LocationDigits = locationDigits; LocationDigits = locationDigits;
LocationFactor = locationFactor; LocationFactor = locationFactor;
LookForAbandoned = lookForAbandoned; LookForAbandoned = lookForAbandoned;

View File

@ -71,6 +71,7 @@
"FocusDirectory": "", "FocusDirectory": "",
"FocusModel": "", "FocusModel": "",
"GenealogicalDataCommunicationFile": "", "GenealogicalDataCommunicationFile": "",
"LoadPhotoPrismLocations": false,
"LocationDigits": 9, "LocationDigits": 9,
"LocationFactor": 10000, "LocationFactor": 10000,
"LookForAbandoned": true, "LookForAbandoned": true,

View File

@ -607,7 +607,7 @@ internal abstract class MapLogic
return results; return results;
} }
private static void ParallelFor(Configuration configuration, string eDistanceContentDirectory, List<LocationContainer<MetadataExtractor.Directory>> collection, long personKey, string file) private static void ParallelFor(Configuration configuration, string eDistanceContentDirectory, List<LocationContainer<MetadataExtractor.Directory>> locationContainers, long personKey, string file)
{ {
const string lnk = ".lnk"; const string lnk = ".lnk";
int? id, wholePercentages; int? id, wholePercentages;
@ -623,29 +623,29 @@ internal abstract class MapLogic
directories = new List<MetadataExtractor.Directory>(); directories = new List<MetadataExtractor.Directory>();
else else
directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(file); directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(file);
Rectangle? rectangle = ILocation.GetWholePercentages(configuration.LocationDigits, wholePercentages.Value); RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value);
lock (collection) lock (locationContainers)
collection.Add(new(fromDistanceContent, file, personKey, id.Value, wholePercentages.Value, directories, rectangle, null)); locationContainers.Add(new(fromDistanceContent, file, personKey, id.Value, wholePercentages.Value, directories, rectangle, null));
} }
private static void OpenPossibleDuplicates(Configuration configuration, List<(long, int, string, double?)> duplicates) private static void OpenPossibleDuplicates(Configuration configuration, List<(long, int, string, float?)> duplicates)
{ {
string personKeyFormatted; string personKeyFormatted;
foreach ((long personKey, int id, string file, double? percent) in duplicates) foreach ((long personKey, int id, string file, float? percent) in duplicates)
{ {
if (percent is null) if (percent is null)
continue; continue;
_ = Process.Start("explorer.exe", string.Concat("\"", Path.GetDirectoryName(file), "\"")); _ = Process.Start("explorer.exe", string.Concat("\"", Path.GetDirectoryName(file), "\""));
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey); personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey);
} }
foreach ((long personKey, int id, string file, double? percent) in duplicates) foreach ((long personKey, int id, string file, float? percent) in duplicates)
{ {
if (percent is not null && percent.Value == 0) if (percent is not null && percent.Value == 0)
continue; continue;
_ = Process.Start("explorer.exe", string.Concat("\"", Path.GetDirectoryName(file), "\"")); _ = Process.Start("explorer.exe", string.Concat("\"", Path.GetDirectoryName(file), "\""));
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey); personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey);
} }
foreach ((long personKey, int id, string file, double? percent) in duplicates) foreach ((long personKey, int id, string file, float? percent) in duplicates)
{ {
if (percent is not null && percent.Value > 0) if (percent is not null && percent.Value > 0)
continue; continue;
@ -654,35 +654,30 @@ internal abstract class MapLogic
} }
} }
private static void LookForPossibleDuplicates(Configuration configuration, List<LocationContainer<MetadataExtractor.Directory>> collection) private static void LookForPossibleDuplicates(Configuration configuration, List<LocationContainer<MetadataExtractor.Directory>> locationContainers)
{ {
string key; string key;
double? percent; float? percent;
Rectangle? rectangle; float itemPercentagesArea;
List<string> delete = new(); List<string> delete = new();
Rectangle intersectRectangle; RectangleF? itemPercentagesRectangle;
(string File, int WholePercentages) item; (string File, int WholePercentages) item;
Dictionary<string, (string, int)> distinct = new(); Dictionary<string, (string, int)> distinct = new();
List<(long, int, string, double?)> duplicates = new(); List<(long, int, string, float?)> duplicates = new();
foreach (LocationContainer<MetadataExtractor.Directory> locationContainer in collection) foreach (LocationContainer<MetadataExtractor.Directory> locationContainer in locationContainers)
{ {
key = string.Concat(locationContainer.PersonKey, locationContainer.Id); key = string.Concat(locationContainer.PersonKey, locationContainer.Id);
if (distinct.TryGetValue(key, out item)) if (distinct.TryGetValue(key, out item))
{ {
if (item.WholePercentages == locationContainer.WholePercentages) if (item.WholePercentages == locationContainer.WholePercentages)
continue; continue;
if (locationContainer.Rectangle is null) itemPercentagesRectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, item.WholePercentages);
if (itemPercentagesRectangle is null || locationContainer.Rectangle is null)
percent = null; percent = null;
else else
{ {
rectangle = ILocation.GetWholePercentages(configuration.LocationDigits, item.WholePercentages); itemPercentagesArea = itemPercentagesRectangle.Value.Width * itemPercentagesRectangle.Value.Height;
if (locationContainer.Rectangle is null || rectangle is null) percent = ILocation.GetIntersectPercent(itemPercentagesRectangle.Value, itemPercentagesArea, locationContainer.Rectangle.Value);
percent = null;
else
{
intersectRectangle = Rectangle.Intersect(locationContainer.Rectangle.Value, rectangle.Value);
percent = intersectRectangle.Width * intersectRectangle.Height;
}
} }
delete.Add(item.File); delete.Add(item.File);
delete.Add(locationContainer.File); delete.Add(locationContainer.File);

View File

@ -72,6 +72,8 @@
"IgnoreExtensions": [ "IgnoreExtensions": [
".gif", ".gif",
".GIF", ".GIF",
".nef",
".NEF",
".pdf", ".pdf",
".PDF" ".PDF"
], ],

View File

@ -22,6 +22,8 @@
"IgnoreExtensions": [ "IgnoreExtensions": [
".gif", ".gif",
".GIF", ".GIF",
".nef",
".NEF",
".pdf", ".pdf",
".PDF" ".PDF"
], ],
@ -137,6 +139,8 @@
"IgnoreExtensions": [ "IgnoreExtensions": [
".gif", ".gif",
".GIF", ".GIF",
".nef",
".NEF",
".pdf", ".pdf",
".PDF" ".PDF"
], ],

View File

@ -30,7 +30,7 @@ public record Marker(
internal static Shared.Models.Marker Map(Marker marker) internal static Shared.Models.Marker Map(Marker marker)
{ {
Shared.Models.Marker result; Shared.Models.Marker result;
(double x, double y, double w, double h, double score) = (double.Parse(marker.X), double.Parse(marker.Y), double.Parse(marker.W), double.Parse(marker.H), double.Parse(marker.Score)); (float x, float y, float w, float h, float score) = (float.Parse(marker.X), float.Parse(marker.Y), float.Parse(marker.W), float.Parse(marker.H), float.Parse(marker.Score));
result = new( result = new(
F_PhotoPrism.HexStringToString(marker.MarkerUid), F_PhotoPrism.HexStringToString(marker.MarkerUid),
F_PhotoPrism.HexStringToString(marker.FileUid), F_PhotoPrism.HexStringToString(marker.FileUid),

View File

@ -1,3 +1,4 @@
using System.Drawing;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models;
@ -139,14 +140,14 @@ public class F_PhotoPrism
return results; return results;
} }
private static void PopulateSubjects(string mappingDefaultName, string personBirthdayFormat, List<string> subjects, StringBuilder stringBuilder, PersonContainer[] personContainers, (MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, double Percent)[] sortedCollection) private static void PopulateSubjects(string mappingDefaultName, string personBirthdayFormat, List<string> subjects, StringBuilder stringBuilder, PersonContainer[] personContainers, (MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, float Percent)[] sortedCollection)
{ {
long? personKey; long? personKey;
string personName; string personName;
const int zero = 0; const int zero = 0;
string personKeyFormatted; string personKeyFormatted;
PersonBirthday personBirthday; PersonBirthday personBirthday;
foreach ((MappingFromPhotoPrism mappingFromPhotoPrism, Shared.Models.Marker marker, double percent) in sortedCollection) foreach ((MappingFromPhotoPrism mappingFromPhotoPrism, Shared.Models.Marker marker, float percent) in sortedCollection)
{ {
foreach (PersonContainer personContainer in personContainers) foreach (PersonContainer personContainer in personContainers)
{ {
@ -173,18 +174,22 @@ public class F_PhotoPrism
{ {
string file; string file;
string text; string text;
double percent; float dlibArea;
float? percent;
string directory;
int width, height;
int? wholePercentages; int? wholePercentages;
RectangleF? prismRectangle;
List<string> subjects = new(); List<string> subjects = new();
DateTime dateTime = new(ticks);
int dlibLocationWholePercentages;
PersonContainer[]? personContainers; PersonContainer[]? personContainers;
StringBuilder stringBuilder = new(); StringBuilder stringBuilder = new();
System.Drawing.Rectangle dlibRectangle; RectangleF? dlibPercentagesRectangle;
System.Drawing.Rectangle? prismRectangle;
System.Drawing.Rectangle intersectRectangle;
float rectangleIntersectMinimum = rectangleIntersectMinimums.Min(); float rectangleIntersectMinimum = rectangleIntersectMinimums.Min();
Dictionary<int, PersonContainer[]>? wholePercentagesToPersonContainers; Dictionary<int, PersonContainer[]>? wholePercentagesToPersonContainers;
(MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, double Percent)[] sortedCollection; (MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, float Percent)[] sortedCollection;
List<(MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, double Percent)> collection = new(); List<(MappingFromPhotoPrism MappingFromPhotoPrism, Shared.Models.Marker Marker, float Percent)> collection = new();
foreach (Face face in distinctFilteredFaces) foreach (Face face in distinctFilteredFaces)
{ {
collection.Clear(); collection.Clear();
@ -198,21 +203,23 @@ public class F_PhotoPrism
(_, wholePercentagesToPersonContainers) = mapLogic.GetWholePercentagesToPersonContainers(face.Mapping.MappingFromItem.Id); (_, wholePercentagesToPersonContainers) = mapLogic.GetWholePercentagesToPersonContainers(face.Mapping.MappingFromItem.Id);
if (wholePercentagesToPersonContainers is null || !wholePercentagesToPersonContainers.TryGetValue(wholePercentages.Value, out personContainers)) if (wholePercentagesToPersonContainers is null || !wholePercentagesToPersonContainers.TryGetValue(wholePercentages.Value, out personContainers))
continue; continue;
dlibRectangle = new(face.Location.Left, face.Location.Top, face.Location.Right - face.Location.Left, face.Location.Bottom - face.Location.Top); (width, height) = IOutputResolution.Get(face.OutputResolution);
dlibLocationWholePercentages = ILocation.GetWholePercentages(height, face.Location, Shared.Models.Stateless.ILocation.Digits, width);
dlibPercentagesRectangle = ILocation.GetPercentagesRectangle(Shared.Models.Stateless.ILocation.Digits, dlibLocationWholePercentages);
if (dlibPercentagesRectangle is null)
continue;
dlibArea = dlibPercentagesRectangle.Value.Width * dlibPercentagesRectangle.Value.Height;
foreach (MappingFromPhotoPrism mappingFromPhotoPrism in face.Mapping.MappingFromPhotoPrismCollection) foreach (MappingFromPhotoPrism mappingFromPhotoPrism in face.Mapping.MappingFromPhotoPrismCollection)
{ {
foreach (Shared.Models.Marker marker in mappingFromPhotoPrism.Markers) foreach (Shared.Models.Marker marker in mappingFromPhotoPrism.Markers)
{ {
prismRectangle = ILocation.GetRectangle(mappingFromPhotoPrism.DatabaseFile, marker, face.OutputResolution); prismRectangle = ILocation.GetPercentagesRectangle(mappingFromPhotoPrism.DatabaseFile, marker, face.OutputResolution);
if (prismRectangle is null) if (prismRectangle is null)
continue; continue;
intersectRectangle = System.Drawing.Rectangle.Intersect(dlibRectangle, prismRectangle.Value); percent = ILocation.GetIntersectPercent(dlibPercentagesRectangle.Value, dlibArea, prismRectangle.Value);
if (intersectRectangle.Width == 0 || intersectRectangle.Height == 0) if (percent is null || percent < rectangleIntersectMinimum)
continue; continue;
percent = (double)intersectRectangle.Width * intersectRectangle.Height / (dlibRectangle.Width * dlibRectangle.Height); collection.Add(new(mappingFromPhotoPrism, marker, percent.Value));
if (percent < rectangleIntersectMinimum)
continue;
collection.Add(new(mappingFromPhotoPrism, marker, percent));
} }
} }
if (!collection.Any()) if (!collection.Any())
@ -222,10 +229,13 @@ public class F_PhotoPrism
} }
if (subjects.Any()) if (subjects.Any())
{ {
file = Path.Combine(fPhotoPrismContentDirectory, $"{ticks}-{rectangleIntersectMinimum}-subject_alias_update.sql"); directory = Path.Combine(fPhotoPrismContentDirectory, dateTime.ToString("yyyy-MM-dd"));
if (!Directory.Exists(directory))
_ = Directory.CreateDirectory(directory);
file = Path.Combine(directory, $"{ticks}-{rectangleIntersectMinimum}-subject_alias_update.sql");
text = string.Join(Environment.NewLine, subjects.Distinct()); text = string.Join(Environment.NewLine, subjects.Distinct());
_ = IPath.WriteAllText(file, text, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); _ = IPath.WriteAllText(file, text, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
file = Path.Combine(fPhotoPrismContentDirectory, $"{ticks}-{rectangleIntersectMinimum}-marker_name_update.sql"); file = Path.Combine(directory, $"{ticks}-{rectangleIntersectMinimum}-marker_name_update.sql");
text = stringBuilder.ToString(); text = stringBuilder.ToString();
_ = IPath.WriteAllText(file, text, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); _ = IPath.WriteAllText(file, text, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
} }

View File

@ -63,6 +63,8 @@
"IgnoreExtensions": [ "IgnoreExtensions": [
".gif", ".gif",
".GIF", ".GIF",
".nef",
".NEF",
".pdf", ".pdf",
".PDF" ".PDF"
], ],

View File

@ -73,6 +73,8 @@
"IgnoreExtensions": [ "IgnoreExtensions": [
".gif", ".gif",
".GIF", ".GIF",
".nef",
".NEF",
".pdf", ".pdf",
".PDF" ".PDF"
], ],

View File

@ -37,7 +37,9 @@ public class FacePoint : Properties.IFacePoint
return result; return result;
} }
#pragma warning disable IDE0070
public override int GetHashCode() public override int GetHashCode()
#pragma warning restore IDE0070
{ {
int hashCode = 1861411795; int hashCode = 1861411795;
hashCode = hashCode * -1521134295 + _Point.GetHashCode(); hashCode = hashCode * -1521134295 + _Point.GetHashCode();

View File

@ -74,7 +74,9 @@ public class Location : Properties.ILocation, IEquatable<Location>
return result; return result;
} }
#pragma warning disable IDE0070
public override int GetHashCode() public override int GetHashCode()
#pragma warning restore IDE0070
{ {
int hashCode = -773114317; int hashCode = -773114317;
hashCode = hashCode * -1521134295 + Bottom.GetHashCode(); hashCode = hashCode * -1521134295 + Bottom.GetHashCode();

View File

@ -2,5 +2,5 @@ using System.Drawing;
namespace View_by_Distance.Shared.Models; namespace View_by_Distance.Shared.Models;
public record LocationContainer<T>(bool FromDistanceContent, string File, long PersonKey, int Id, int WholePercentages, IReadOnlyList<T> Directories, Rectangle? Rectangle, Location? Location) public record LocationContainer<T>(bool FromDistanceContent, string File, long PersonKey, int Id, int WholePercentages, IReadOnlyList<T> Directories, RectangleF? Rectangle, Location? Location)
{ } { }

View File

@ -12,13 +12,13 @@ public record Marker(
string? SubjSrc, string? SubjSrc,
string? FaceId, string? FaceId,
string FaceDist, string FaceDist,
double X, float X,
double Y, float Y,
double W, float W,
double H, float H,
string Q, string Q,
string Size, string Size,
double Score, float Score,
string? Thumb, string? Thumb,
string MatchedAt, string MatchedAt,
string CreatedAt, string CreatedAt,

View File

@ -31,9 +31,7 @@ internal abstract class Face
private static JsonElement[] GetJsonElements(string jsonFileFullName) private static JsonElement[] GetJsonElements(string jsonFileFullName)
{ {
string json = GetJson(jsonFileFullName); string json = GetJson(jsonFileFullName);
JsonElement[]? jsonElements = JsonSerializer.Deserialize<JsonElement[]>(json); JsonElement[]? jsonElements = JsonSerializer.Deserialize<JsonElement[]>(json) ?? throw new Exception();
if (jsonElements is null)
throw new Exception();
return jsonElements; return jsonElements;
} }

View File

@ -15,25 +15,25 @@ public interface ILocation
static List<Models.Face> FilterByIntersect(Models.Face[] faces, float rectangleIntersectMinimum, int wholePercentages) => static List<Models.Face> FilterByIntersect(Models.Face[] faces, float rectangleIntersectMinimum, int wholePercentages) =>
Location.FilterByIntersect(faces, rectangleIntersectMinimum, wholePercentages); Location.FilterByIntersect(faces, rectangleIntersectMinimum, wholePercentages);
Rectangle? TestStatic_GetRectangle(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution) => RectangleF? TestStatic_GetPercentagesRectangle(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution) =>
GetRectangle(databaseFile, marker, outputResolution); GetPercentagesRectangle(databaseFile, marker, outputResolution);
static Rectangle? GetRectangle(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution) => static RectangleF? GetPercentagesRectangle(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution) =>
Location.GetRectangle(databaseFile, marker, outputResolution); Location.GetPercentagesRectangle(databaseFile, marker, outputResolution);
Models.Location? TestStatic_GetLocation(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution) => Models.Location? TestStatic_GetLocation(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution) =>
GetLocation(databaseFile, marker, outputResolution); GetLocation(databaseFile, marker, outputResolution);
static Models.Location? GetLocation(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution) => static Models.Location? GetLocation(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution) =>
Location.GetLocation(databaseFile, marker, outputResolution); Location.GetLocation(databaseFile, marker, outputResolution);
List<Models.Location> TestStatic_GetLocations<T>(List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, List<Models.Face> faces, List<LocationContainer<T>> containers) => List<Models.Location> TestStatic_GetLocations<T>(List<LocationContainer<T>> locationContainers, List<Models.Face> faces, List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, float rectangleIntersectMinimum) =>
GetLocations(mappingFromPhotoPrismCollection, faces, containers); GetLocations(locationContainers, faces, mappingFromPhotoPrismCollection, rectangleIntersectMinimum);
static List<Models.Location> GetLocations<T>(List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, List<Models.Face> faces, List<LocationContainer<T>> containers) => static List<Models.Location> GetLocations<T>(List<LocationContainer<T>> locationContainers, List<Models.Face> faces, List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, float rectangleIntersectMinimum) =>
Location.GetLocations(mappingFromPhotoPrismCollection, faces, containers); Location.GetLocations(locationContainers, faces, mappingFromPhotoPrismCollection, rectangleIntersectMinimum);
Rectangle? TestStatic_GetWholePercentages(int locationDigits, int wholePercentages) => RectangleF? TestStatic_GetPercentagesRectangle(int locationDigits, int wholePercentages) =>
GetWholePercentages(locationDigits, wholePercentages); GetPercentagesRectangle(locationDigits, wholePercentages);
static Rectangle? GetWholePercentages(int locationDigits, int wholePercentages) => static RectangleF? GetPercentagesRectangle(int locationDigits, int wholePercentages) =>
Location.GetWholePercentages(locationDigits, wholePercentages.ToString()); Location.GetPercentagesRectangle(locationDigits, wholePercentages.ToString());
Rectangle? TestStatic_GetRectangle(int locationDigits, Models.OutputResolution outputResolution, int wholePercentages) => Rectangle? TestStatic_GetRectangle(int locationDigits, Models.OutputResolution outputResolution, int wholePercentages) =>
GetRectangle(locationDigits, outputResolution, wholePercentages); GetRectangle(locationDigits, outputResolution, wholePercentages);
@ -90,6 +90,11 @@ public interface ILocation
static int GetWholePercentages(int locationDigits) => static int GetWholePercentages(int locationDigits) =>
Location.GetWholePercentages(1, 1, 0, locationDigits, 1, 0, 1, zCount: 1); Location.GetWholePercentages(1, 1, 0, locationDigits, 1, 0, 1, zCount: 1);
int TestStatic_GetWholePercentages(int height, Models.Location location, int locationDigits, int width) =>
GetWholePercentages(height, location, locationDigits, width);
static int GetWholePercentages(int height, Models.Location location, int locationDigits, int width) =>
Location.GetWholePercentages(height, location, locationDigits, width);
int TestStatic_GetWholePercentages(int bottom, int height, int left, int locationDigits, int right, int top, int width) => int TestStatic_GetWholePercentages(int bottom, int height, int left, int locationDigits, int right, int top, int width) =>
GetWholePercentages(bottom, height, left, locationDigits, right, top, width); GetWholePercentages(bottom, height, left, locationDigits, right, top, width);
static int GetWholePercentages(int bottom, int height, int left, int locationDigits, int right, int top, int width) => static int GetWholePercentages(int bottom, int height, int left, int locationDigits, int right, int top, int width) =>
@ -109,4 +114,9 @@ public interface ILocation
width, width,
facesCount); facesCount);
float? TestStatic_GetIntersectPercent(RectangleF rectangleA, float? areaA, RectangleF rectangleB) =>
GetIntersectPercent(rectangleA, areaA, rectangleB);
static float? GetIntersectPercent(RectangleF rectangleA, float? areaA, RectangleF rectangleB) =>
Location.GetIntersectPercent(rectangleA, areaA, rectangleB);
} }

View File

@ -3,6 +3,11 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods;
public interface IOutputResolution public interface IOutputResolution
{ // ... { // ...
(int, int) TestStatic_Get(Models.OutputResolution outputResolution) =>
Get(outputResolution);
static (int, int) Get(Models.OutputResolution outputResolution) =>
OutputResolution.Get(outputResolution);
int TestStatic_GetHeight(Models.OutputResolution outputResolution) => int TestStatic_GetHeight(Models.OutputResolution outputResolution) =>
GetHeight(outputResolution); GetHeight(outputResolution);
static int GetHeight(Models.OutputResolution outputResolution) => static int GetHeight(Models.OutputResolution outputResolution) =>

View File

@ -108,15 +108,21 @@ internal abstract class Location
return result; return result;
} }
internal static int GetWholePercentages(int height, Models.Location location, int locationDigits, int width)
{
int result = GetWholePercentages(location.Bottom, height, location.Left, locationDigits, location.Right, location.Top, width, zCount: 1);
return result;
}
internal static int GetConfidencePercent(int faceConfidencePercent, float[] rangeFaceConfidence, double confidence) internal static int GetConfidencePercent(int faceConfidencePercent, float[] rangeFaceConfidence, double confidence)
{ {
int result = (int)(confidence / rangeFaceConfidence[1] * faceConfidencePercent); int result = (int)(confidence / rangeFaceConfidence[1] * faceConfidencePercent);
return result; return result;
} }
internal static Rectangle? GetWholePercentages(int locationDigits, string wholePercentages) internal static RectangleF? GetPercentagesRectangle(int locationDigits, string wholePercentages)
{ {
Rectangle? result; RectangleF? result;
int length = (locationDigits - 1) / 4; int length = (locationDigits - 1) / 4;
string[] segments = new string[] string[] segments = new string[]
{ {
@ -133,7 +139,10 @@ internal abstract class Location
if (!int.TryParse(segments[1], out int xWholePercent) || !int.TryParse(segments[2], out int yWholePercent) || !int.TryParse(segments[3], out int wWholePercent) || !int.TryParse(segments[4], out int hWholePercent)) if (!int.TryParse(segments[1], out int xWholePercent) || !int.TryParse(segments[2], out int yWholePercent) || !int.TryParse(segments[3], out int wWholePercent) || !int.TryParse(segments[4], out int hWholePercent))
result = null; result = null;
else else
result = new(xWholePercent, yWholePercent, wWholePercent, hWholePercent); {
float factor = 100;
result = new(xWholePercent / factor, yWholePercent / factor, wWholePercent / factor, hWholePercent / factor);
}
} }
return result; return result;
} }
@ -144,13 +153,12 @@ internal abstract class Location
if (wholePercentages.Length != locationDigits || wholePercentages[0] is not '4' and not '8') if (wholePercentages.Length != locationDigits || wholePercentages[0] is not '4' and not '8')
throw new NotSupportedException("Old way has been removed!"); throw new NotSupportedException("Old way has been removed!");
(int width, int height) = OutputResolution.Get(outputResolution); (int width, int height) = OutputResolution.Get(outputResolution);
Rectangle? rectangle = GetWholePercentages(locationDigits, wholePercentages); RectangleF? rectangle = GetPercentagesRectangle(locationDigits, wholePercentages);
if (rectangle is null) if (rectangle is null)
result = null; result = null;
else else
{ {
decimal factor = 100; result = new((int)(rectangle.Value.X * width), (int)(rectangle.Value.Y * height), (int)(rectangle.Value.Width * width), (int)(rectangle.Value.Height * height));
result = new((int)(rectangle.Value.X / factor * width), (int)(rectangle.Value.Y / factor * height), (int)(rectangle.Value.Width / factor * width), (int)(rectangle.Value.Height / factor * height));
} }
if (result is null) if (result is null)
throw new NullReferenceException(nameof(result)); throw new NullReferenceException(nameof(result));
@ -163,25 +171,29 @@ internal abstract class Location
return result; return result;
} }
internal static Rectangle? GetRectangle(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution) internal static RectangleF? GetPercentagesRectangle(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution)
{ {
Rectangle? result; RectangleF? result;
bool matches = Matches(outputResolution, databaseFile); bool matches = Matches(outputResolution, databaseFile);
if (!matches) if (!matches)
result = null; result = null;
else 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)); result = new(marker.X, marker.Y, marker.W, marker.H);
return result; return result;
} }
private static Models.Location? GetLocation(DatabaseFile databaseFile, Marker marker, Rectangle rectangle) private static Models.Location? GetLocation(DatabaseFile databaseFile, Marker marker, RectangleF rectangle)
{ {
Models.Location? result; Models.Location? result;
bool verified = Check(rectangle.Bottom, databaseFile.FileHeight, rectangle.Left, rectangle.Right, rectangle.Top, databaseFile.FileWidth, zCount: 1, throwException: false); int top = (int)Math.Ceiling(rectangle.Top * databaseFile.FileHeight);
int left = (int)Math.Ceiling(rectangle.Left * databaseFile.FileWidth);
int right = (int)Math.Ceiling(rectangle.Right * databaseFile.FileWidth);
int bottom = (int)Math.Ceiling(rectangle.Bottom * databaseFile.FileHeight);
bool verified = Check(bottom, databaseFile.FileHeight, left, right, top, databaseFile.FileWidth, zCount: 1, throwException: false);
if (!verified) if (!verified)
result = null; result = null;
else else
result = new(rectangle.Bottom, marker.Score / 100, rectangle.Left, rectangle.Right, rectangle.Top); result = new(bottom, marker.Score / 100, left, right, top);
return result; return result;
} }
@ -200,7 +212,7 @@ internal abstract class Location
internal static Models.Location? GetLocation(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution) internal static Models.Location? GetLocation(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution)
{ {
Models.Location? result; Models.Location? result;
Rectangle? rectangle = GetRectangle(databaseFile, marker, outputResolution); RectangleF? rectangle = GetPercentagesRectangle(databaseFile, marker, outputResolution);
if (rectangle is null) if (rectangle is null)
result = null; result = null;
else else
@ -208,15 +220,43 @@ internal abstract class Location
return result; return result;
} }
internal static List<Models.Location> GetLocations<T>(List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, List<Models.Face> faces, List<LocationContainer<T>> containers) internal static float? GetIntersectPercent(RectangleF rectangleA, float? areaA, RectangleF rectangleB)
{
float? result;
if (rectangleA.Equals(rectangleB))
result = 1;
else
{
float intersectArea;
RectangleF intersectRectangle;
areaA ??= rectangleA.Width * rectangleA.Height;
float areaB = rectangleB.Width * rectangleB.Height;
bool check = areaA > areaB;
if (check)
intersectRectangle = RectangleF.Intersect(rectangleB, rectangleA);
else
intersectRectangle = RectangleF.Intersect(rectangleA, rectangleB);
intersectArea = intersectRectangle.Width * intersectRectangle.Height;
if (check)
result = intersectArea / areaA;
else
result = intersectArea / areaB;
}
return result;
}
internal static List<Models.Location> GetLocations<T>(List<LocationContainer<T>> locationContainers, List<Models.Face> faces, List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, float rectangleIntersectMinimum)
{ {
List<Models.Location> results = new(); List<Models.Location> results = new();
bool any; bool any;
bool matches; bool matches;
Rectangle dlibRectangle; float? percent;
Rectangle? prismRectangle; float prismArea;
int width, height;
Models.Location? location; Models.Location? location;
Rectangle intersectRectangle; RectangleF? prismRectangle;
int dlibLocationWholePercentages;
RectangleF? dlibPercentagesRectangle;
Models.OutputResolution? outputResolution = null; Models.OutputResolution? outputResolution = null;
foreach (Models.Face face in faces) foreach (Models.Face face in faces)
{ {
@ -226,7 +266,7 @@ internal abstract class Location
outputResolution ??= face.OutputResolution; outputResolution ??= face.OutputResolution;
} }
int before = results.Count; int before = results.Count;
foreach (LocationContainer<T> locationContainer in containers) foreach (LocationContainer<T> locationContainer in locationContainers)
{ {
if (locationContainer.Location is null) if (locationContainer.Location is null)
continue; continue;
@ -242,23 +282,24 @@ internal abstract class Location
foreach (Marker marker in mappingFromPhotoPrism.Markers) foreach (Marker marker in mappingFromPhotoPrism.Markers)
{ {
any = false; any = false;
prismRectangle = GetRectangle(mappingFromPhotoPrism.DatabaseFile, marker, outputResolution); prismRectangle = GetPercentagesRectangle(mappingFromPhotoPrism.DatabaseFile, marker, outputResolution);
if (prismRectangle is null) if (prismRectangle is null)
break; break;
prismArea = prismRectangle.Value.Width * prismRectangle.Value.Height;
location = GetLocation(mappingFromPhotoPrism.DatabaseFile, marker, prismRectangle.Value); location = GetLocation(mappingFromPhotoPrism.DatabaseFile, marker, prismRectangle.Value);
if (location is null) if (location is null)
break; break;
foreach (LocationContainer<T> locationContainer in containers) foreach (LocationContainer<T> locationContainer in locationContainers)
{ {
if (any) if (any)
continue; continue;
if (locationContainer.Location is null) if (locationContainer.Rectangle is null)
continue; continue;
dlibRectangle = new(locationContainer.Location.Left, locationContainer.Location.Top, locationContainer.Location.Right - locationContainer.Location.Left, locationContainer.Location.Bottom - locationContainer.Location.Top); percent = GetIntersectPercent(prismRectangle.Value, prismArea, locationContainer.Rectangle.Value);
intersectRectangle = Rectangle.Intersect(prismRectangle.Value, dlibRectangle); if (percent is null || percent < rectangleIntersectMinimum)
if (intersectRectangle.Width == 0 && intersectRectangle.Height == 0)
continue; continue;
any = true; if (!any)
any = true;
break; break;
} }
foreach (Models.Face face in faces) foreach (Models.Face face in faces)
@ -267,11 +308,16 @@ internal abstract class Location
continue; continue;
if (face.Location is null || face.OutputResolution is null) if (face.Location is null || face.OutputResolution is null)
continue; continue;
dlibRectangle = new(face.Location.Left, face.Location.Top, face.Location.Right - face.Location.Left, face.Location.Bottom - face.Location.Top); (width, height) = OutputResolution.Get(face.OutputResolution);
intersectRectangle = Rectangle.Intersect(prismRectangle.Value, dlibRectangle); dlibLocationWholePercentages = GetWholePercentages(height, face.Location, Stateless.ILocation.Digits, width);
if (intersectRectangle.Width == 0 && intersectRectangle.Height == 0) dlibPercentagesRectangle = GetPercentagesRectangle(Stateless.ILocation.Digits, dlibLocationWholePercentages.ToString());
if (dlibPercentagesRectangle is null)
continue; continue;
any = true; percent = GetIntersectPercent(prismRectangle.Value, prismArea, dlibPercentagesRectangle.Value);
if (percent is null || percent < rectangleIntersectMinimum)
continue;
if (!any)
any = true;
break; break;
} }
if (!any) if (!any)
@ -283,31 +329,28 @@ internal abstract class Location
return results; return results;
} }
// private static double GP(OutputResolution outputResolution,Location location, ){
// double result;
// return result;
// }
internal static List<Models.Face> FilterByIntersect(Models.Face[] faces, float rectangleIntersectMinimum, int wholePercentages) internal static List<Models.Face> FilterByIntersect(Models.Face[] faces, float rectangleIntersectMinimum, int wholePercentages)
{ {
List<Models.Face> results = new(); List<Models.Face> results = new();
double? percent; float? percent;
Rectangle checkRectangle; int width, height;
Rectangle? sourceRectangle; int faceLocationWholePercentages;
Rectangle intersectRectangle; RectangleF? facePercentagesRectangle;
RectangleF? sourceRectangle = GetPercentagesRectangle(Stateless.ILocation.Digits, wholePercentages.ToString());
float? sourceArea = sourceRectangle is null ? null : sourceRectangle.Value.Width * sourceRectangle.Value.Height;
foreach (Models.Face face in faces) foreach (Models.Face face in faces)
{ {
if (sourceRectangle is null || sourceArea is null)
continue;
if (face.Location is null || face.OutputResolution is null) if (face.Location is null || face.OutputResolution is null)
continue; continue;
checkRectangle = new(face.Location.Left, face.Location.Top, face.Location.Right - face.Location.Left, face.Location.Bottom - face.Location.Top); (width, height) = OutputResolution.Get(face.OutputResolution);
sourceRectangle = GetRectangle(Stateless.ILocation.Digits, face.OutputResolution, wholePercentages.ToString()); faceLocationWholePercentages = GetWholePercentages(height, face.Location, Stateless.ILocation.Digits, width);
if (sourceRectangle is null) facePercentagesRectangle = GetPercentagesRectangle(Stateless.ILocation.Digits, faceLocationWholePercentages.ToString());
if (facePercentagesRectangle is null)
continue; continue;
intersectRectangle = Rectangle.Intersect(checkRectangle, sourceRectangle.Value); percent = GetIntersectPercent(sourceRectangle.Value, sourceArea.Value, facePercentagesRectangle.Value);
if (intersectRectangle.Width == 0 || intersectRectangle.Height == 0) if (percent is null || percent < rectangleIntersectMinimum)
continue;
percent = (double)intersectRectangle.Width * intersectRectangle.Height / (checkRectangle.Width * checkRectangle.Height);
if (percent < rectangleIntersectMinimum)
continue; continue;
results.Add(face); results.Add(face);
} }

View File

@ -4,6 +4,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using Phares.Shared; using Phares.Shared;
using Serilog; using Serilog;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing;
using System.Reflection; using System.Reflection;
using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Stateless.Methods; using View_by_Distance.Shared.Models.Stateless.Methods;
@ -307,4 +308,74 @@ public partial class UnitTestCalculations
NonThrowTryCatch(); NonThrowTryCatch();
} }
[TestMethod]
public void TestMethodIntersect()
{
float? percent;
float? areaA = null;
RectangleF rectangleA;
RectangleF rectangleB;
rectangleA = new(0, 0, 4, 4);
rectangleB = new(0, 0, 4, 4);
percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
Assert.IsNotNull(percent);
Assert.IsTrue(percent.Value == 1);
rectangleA = new(0, 0, 4, 4);
rectangleB = new(0, 0, 2, 2);
percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
Assert.IsNotNull(percent);
Assert.IsTrue(percent.Value == .25);
rectangleA = new(0, 0, 4, 4);
rectangleB = new(0, 0, 4, 2);
percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
Assert.IsNotNull(percent);
Assert.IsTrue(percent.Value == .5);
rectangleA = new(0, 0, 4, 4);
rectangleB = new(2, 2, 4, 4);
percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
Assert.IsNotNull(percent);
Assert.IsTrue(percent.Value == .25);
rectangleA = new(0, 0, 4, 4);
rectangleB = new(2, 0, 4, 4);
percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
Assert.IsNotNull(percent);
Assert.IsTrue(percent.Value == .5);
rectangleA = new(0, 0, 4, 4);
rectangleB = new(2, 4, 4, 4);
percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
Assert.IsNotNull(percent);
Assert.IsTrue(percent.Value == 0);
rectangleB = new(0, 0, 4, 4);
rectangleA = new(0, 0, 4, 4);
percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
Assert.IsNotNull(percent);
Assert.IsTrue(percent.Value == 1);
rectangleB = new(0, 0, 4, 4);
rectangleA = new(0, 0, 2, 2);
percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
Assert.IsNotNull(percent);
Assert.IsTrue(percent.Value == .25);
rectangleB = new(0, 0, 4, 4);
rectangleA = new(0, 0, 4, 2);
percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
Assert.IsNotNull(percent);
Assert.IsTrue(percent.Value == .5);
rectangleB = new(0, 0, 4, 4);
rectangleA = new(2, 2, 4, 4);
percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
Assert.IsNotNull(percent);
Assert.IsTrue(percent.Value == .25);
rectangleB = new(0, 0, 4, 4);
rectangleA = new(2, 0, 4, 4);
percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
Assert.IsNotNull(percent);
Assert.IsTrue(percent.Value == .5);
rectangleB = new(0, 0, 4, 4);
rectangleA = new(2, 4, 4, 4);
percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
Assert.IsNotNull(percent);
Assert.IsTrue(percent.Value == 0);
NonThrowTryCatch();
}
} }