diff --git a/.idea/.idea.CrestronOpenCvSharp/.idea/vcs.xml b/.idea/.idea.CrestronOpenCvSharp/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/.idea.CrestronOpenCvSharp/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CrestronOpenCvSharp/.DS_Store b/CrestronOpenCvSharp/.DS_Store
index a6f738b..a6fa8d4 100644
Binary files a/CrestronOpenCvSharp/.DS_Store and b/CrestronOpenCvSharp/.DS_Store differ
diff --git a/CrestronOpenCvSharp/Capture/FacialRecognition.cs b/CrestronOpenCvSharp/Capture/FacialRecognition.cs
index 30eee1e..a7d6e27 100644
--- a/CrestronOpenCvSharp/Capture/FacialRecognition.cs
+++ b/CrestronOpenCvSharp/Capture/FacialRecognition.cs
@@ -1,7 +1,11 @@
+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;
@@ -16,15 +20,22 @@ public class FacialRecognition
private readonly Dictionary _faceImagesDict;
private string? FaceImagePath { get; set; }
+
+ private Contract _contract;
- public FacialRecognition(string? baseDirectory)
+ 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)
+ if (_baseDirectory != null)
+ {
FaceImagePath = Path.Combine(_baseDirectory, "aligned.png");
+ }
// Let's load the default stuff in this dictionary
_faceImagesDict = new Dictionary
@@ -49,7 +60,19 @@ public class FacialRecognition
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!");
@@ -113,4 +136,26 @@ public class FacialRecognition
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;
+ }
+ }
}
\ No newline at end of file
diff --git a/CrestronOpenCvSharp/Capture/MjpegCapture.cs b/CrestronOpenCvSharp/Capture/MjpegCapture.cs
index 63549cf..fb7df18 100644
--- a/CrestronOpenCvSharp/Capture/MjpegCapture.cs
+++ b/CrestronOpenCvSharp/Capture/MjpegCapture.cs
@@ -1,4 +1,7 @@
+using Crestron.SimplSharp;
+using PhotoBooth;
using RandomNameGeneratorLibrary;
+using Timeout = System.Threading.Timeout;
namespace CrestronOpenCvSharp.Capture;
@@ -10,15 +13,19 @@ public class MjpegCapture
private readonly FacialRecognition? _facialRecognition;
private Timer? _timer;
private readonly PersonNameGenerator _personNameGenerator;
+ private Contract _contract;
public bool CaptureRunning { get; private set; }
- public MjpegCapture(string? url, string? directory, FacialRecognition? facialRecognition)
+ private const string BaseUrl = "https://ise2025.local.staal.one/VirtualControl/MA/Rooms/MYFIRSTAI/Html/";
+
+ public MjpegCapture(string? url, string? directory, FacialRecognition? facialRecognition, Contract contract)
{
_mjpegUrl = url;
_directory = Path.Combine(directory!, "captures");
_facialRecognition = facialRecognition;
-
+ _contract = contract;
+
_personNameGenerator = new PersonNameGenerator();
}
@@ -72,7 +79,8 @@ public class MjpegCapture
try
{
CaptureRunning = true;
- var fileName = Path.Combine(_directory!, $"frame_{DateTime.Now:yyyyMMdd_HHmmss}.jpg");
+ var uniqueName = $"frame_{DateTime.Now:yyyyMMdd_HHmmss}.jpg";
+ var fileName = Path.Combine(_directory!, uniqueName);
try
{
HttpResponseMessage response = await _client.GetAsync(_mjpegUrl, HttpCompletionOption.ResponseHeadersRead);
@@ -85,35 +93,36 @@ public class MjpegCapture
}
Console.WriteLine($"Saved frame to {fileName}");
- // TODO Send to image preview window on touchpanel
+ _contract.Main.ImagePreview_Url(string.Format($"{BaseUrl}/captures/{uniqueName}"));
+ Console.WriteLine($"Sending URL {string.Format($"{BaseUrl}/captures/{uniqueName}")}");
if (_facialRecognition!.CheckForFace(fileName))
{
StopCapture();
+ _contract.Main.ImagePreview_Url(string.Empty);
+ Thread.Sleep(1000);
Console.WriteLine("Face detected, stopping capture");
- // TODO Send image to preview window on touchpanel
-
- //Path.Combine(_baseDirectory, "aligned.png"));
-
Console.WriteLine("Comparing captured face against database");
+
var result = await _facialRecognition.CompareFaces();
if (result is not null)
{
Console.WriteLine($"We have found a match! The person in front of the camera is: {result}");
+ _contract.Main.txtFeedback_Indirect($"{result} detected!");
}
else
{
Console.WriteLine("No match was found in our database, let's add this person!");
var randomFullName = _personNameGenerator.GenerateRandomFirstAndLastName();
_facialRecognition.AddPersonToDatabase(randomFullName);
- Thread.Sleep(2000);
- Console.WriteLine("Person added to database, restarting capture");
- StartCapture(2000);
+ Console.WriteLine("Person added to database");
+ _contract.Main.txtFeedback_Indirect($"{randomFullName} added to database");
}
}
else
{
Console.WriteLine("No face detected, carrying on!");
+ _contract.Main.txtFeedback_Indirect($"No face detected!");
}
}
catch (Exception ex)
diff --git a/CrestronOpenCvSharp/ControlSystem.cs b/CrestronOpenCvSharp/ControlSystem.cs
index 978e030..d9af829 100644
--- a/CrestronOpenCvSharp/ControlSystem.cs
+++ b/CrestronOpenCvSharp/ControlSystem.cs
@@ -1,6 +1,8 @@
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
+using Crestron.SimplSharpPro.UI;
using CrestronOpenCvSharp.Capture;
+using PhotoBooth;
using Directory = Crestron.SimplSharp.CrestronIO.Directory;
using Path = Crestron.SimplSharp.CrestronIO.Path;
@@ -11,6 +13,9 @@ public class ControlSystem : CrestronControlSystem
private FacialRecognition? _facialRecognition;
private MjpegCapture? _capture;
private UiHandler? _uiHandler;
+
+ private XpanelForHtml5 _xpanel;
+ private Contract _contract;
// Default snapshot URL of a Bosch camera
private const string Url = "http://192.168.1.221/snap.jpg";
@@ -34,15 +39,31 @@ public class ControlSystem : CrestronControlSystem
{
try
{
- _facialRecognition = new FacialRecognition(_directory);
- _capture = new MjpegCapture(Url, _directory, _facialRecognition);
+ _xpanel = new XpanelForHtml5(0x03, this);
+ _xpanel.Register();
+ _contract = new Contract(_xpanel);
+ _facialRecognition = new FacialRecognition(_directory, _contract);
+ _capture = new MjpegCapture(Url, _directory, _facialRecognition, _contract);
_uiHandler = new UiHandler(_capture);
- _capture.StartCapture(5000);
+ _contract.Main.btnStartCapture_PressEvent += MainOnbtnStartCapture_PressEvent;
+ _contract.Main.btnStopCapture_PressEvent += MainOnbtnStopCapture_PressEvent;
+
+ //_capture.StartCapture(5000);
}
catch (Exception e)
{
ErrorLog.Error("Error in InitializeSystem: {0}", e.Message);
}
}
+
+ private void MainOnbtnStopCapture_PressEvent(object? sender, UIEventArgs uiEventArgs)
+ {
+ _capture?.StopCapture();
+ }
+
+ private void MainOnbtnStartCapture_PressEvent(object? sender, UIEventArgs uiEventArgs)
+ {
+ _capture?.StartCapture(2000);
+ }
}
\ No newline at end of file
diff --git a/CrestronOpenCvSharp/CrestronOpenCvSharp.csproj b/CrestronOpenCvSharp/CrestronOpenCvSharp.csproj
index 16ea2c5..c401ffe 100644
--- a/CrestronOpenCvSharp/CrestronOpenCvSharp.csproj
+++ b/CrestronOpenCvSharp/CrestronOpenCvSharp.csproj
@@ -34,4 +34,22 @@
+
+
+ UI\ComponentMediator.g.cs
+
+
+ UI\Contract.g.cs
+
+
+ UI\IndexedEventArgs.g.cs
+
+
+ UI\Main.g.cs
+
+
+ UI\UIEventArgs.g.cs
+
+
+