using Crestron.SimplSharp; using FaceAiSharp; using FaceAiSharp.Extensions; using PhotoBooth; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Drawing.Processing; using SixLabors.ImageSharp.Processing; namespace CrestronOpenCvSharp.Capture; public class FacialRecognition { private readonly IFaceDetectorWithLandmarks _detector; private readonly IFaceEmbeddingsGenerator _recognizer; private readonly string? _baseDirectory; private Image? _image; private float[]? _referenceEmbeddings; private readonly Dictionary _faceImagesDict; private string? FaceImagePath { get; set; } private Contract _contract; private const string BaseUrl = "https://ise2025.local.staal.one/VirtualControl/MA/Rooms/MYFIRSTAI/Html/"; public FacialRecognition(string? baseDirectory, Contract contract) { _baseDirectory = baseDirectory; _contract = contract; _detector = FaceAiSharpBundleFactory.CreateFaceDetectorWithLandmarks(); _recognizer = FaceAiSharpBundleFactory.CreateFaceEmbeddingsGenerator(); if (_baseDirectory != null) { FaceImagePath = Path.Combine(_baseDirectory, "aligned.png"); } // Let's load the default stuff in this dictionary _faceImagesDict = new Dictionary { { "Yuri Staal", "https://ise2025.local.staal.one/VirtualControl/MA/Rooms/MYFIRSTAI/Html/yuri.jpg" }, { "Toine C. Leerentveld", "https://ise2025.local.staal.one/VirtualControl/MA/Rooms/MYFIRSTAI/Html/toine.jpg" }, { "Oliver Hall", "https://ise2025.local.staal.one/VirtualControl/MA/Rooms/MYFIRSTAI/Html/oliver.jpg" } }; } public bool CheckForFace(string imageFilePath) { try { // Load the photo var photo = File.ReadAllBytes(imageFilePath); // Convert it _image = Image.Load(photo); // Detect faces in this photo var faces = _detector.DetectFaces(_image); if (faces.Count != 0) { foreach (var face in faces) { var box = face.Box; _image.Mutate(ctx => ctx.DrawPolygon(Color.Red, 2, new PointF(box.Left, box.Top), new PointF(box.Right, box.Top), new PointF(box.Right, box.Bottom), new PointF(box.Left, box.Bottom))); } var fileName = GenerateUniqueFilename(); _image.Save(Path.Combine(_baseDirectory!, fileName!)); _contract.Main.ImagePreview_Url(string.Format($"{BaseUrl}{fileName!}")); Console.WriteLine($"Sending URL {string.Format($"{BaseUrl}{fileName!}")}"); _recognizer.AlignFaceUsingLandmarks(_image, faces.First().Landmarks!); _referenceEmbeddings = _recognizer.GenerateEmbedding(_image); _image.Save(FaceImagePath!); Console.WriteLine("Aligned faces!"); } else { Console.WriteLine("No faces were found!"); } // Return true or false return faces.Any(); } catch (Exception e) { Console.WriteLine($"Exception detecting faces: {e.Message}"); throw; } } public async Task CompareFaces() { foreach (var (name, value) in _faceImagesDict) { var faceImage = await LoadImageAsync(value); var detectedFace = _detector.DetectFaces(faceImage).FirstOrDefault(); // Generate embedding for the detected face _recognizer.AlignFaceUsingLandmarks(faceImage, detectedFace.Landmarks!); var faceEmbedding = _recognizer.GenerateEmbedding(faceImage); // Compare embeddings var similarity = _referenceEmbeddings?.Dot(faceEmbedding); Console.WriteLine($"Similarity with {name}: {similarity}"); if (similarity >= 0.42) { //Console.WriteLine("Assessment: Both pictures show the same person."); return name; } } return null; } public void AddPersonToDatabase(string name) { var shortName = name.Replace(" ", ""); // Copy the aligned image to a new image if (_baseDirectory != null) { var newFile = Path.Combine(_baseDirectory, $"{shortName}.jpg"); Console.WriteLine($"Saved new image to {newFile}"); File.Copy(FaceImagePath!, newFile, overwrite: true); } _faceImagesDict.Add(name, $"https://ise2025.local.staal.one/VirtualControl/MA/Rooms/MYFIRSTAI/Html/{shortName}.jpg"); Console.WriteLine($"Added new image to dictionary"); } private async Task> LoadImageAsync(string path) { using var hc = new HttpClient(); var imageBytes = await hc.GetByteArrayAsync(path); return Image.Load(imageBytes); } /// /// Generate a unique filename for the floor plan /// /// A dynamic string with a randomized number appended to "image" private string? GenerateUniqueFilename() { try { // We are generating random numbers to append to the filename // We do this to force an update of the image in the browser var rnd = new Random(); var num = rnd.Next(); var fileName = $"image{num}.jpg"; return fileName; } catch (Exception exception) { ErrorLog.Exception($"Exception in GenerateUniqueFilename()", exception); return null; } } }