messed around with it some more
This commit is contained in:
parent
1f7b9770c9
commit
ff7fdd8e45
6 changed files with 115 additions and 16 deletions
6
.idea/.idea.CrestronOpenCvSharp/.idea/vcs.xml
generated
Normal file
6
.idea/.idea.CrestronOpenCvSharp/.idea/vcs.xml
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
BIN
CrestronOpenCvSharp/.DS_Store
vendored
BIN
CrestronOpenCvSharp/.DS_Store
vendored
Binary file not shown.
|
|
@ -1,7 +1,11 @@
|
||||||
|
using Crestron.SimplSharp;
|
||||||
using FaceAiSharp;
|
using FaceAiSharp;
|
||||||
using FaceAiSharp.Extensions;
|
using FaceAiSharp.Extensions;
|
||||||
|
using PhotoBooth;
|
||||||
using SixLabors.ImageSharp;
|
using SixLabors.ImageSharp;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
|
using SixLabors.ImageSharp.Drawing.Processing;
|
||||||
|
using SixLabors.ImageSharp.Processing;
|
||||||
|
|
||||||
namespace CrestronOpenCvSharp.Capture;
|
namespace CrestronOpenCvSharp.Capture;
|
||||||
|
|
||||||
|
|
@ -16,15 +20,22 @@ public class FacialRecognition
|
||||||
|
|
||||||
private readonly Dictionary<string, string> _faceImagesDict;
|
private readonly Dictionary<string, string> _faceImagesDict;
|
||||||
private string? FaceImagePath { get; set; }
|
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;
|
_baseDirectory = baseDirectory;
|
||||||
|
_contract = contract;
|
||||||
_detector = FaceAiSharpBundleFactory.CreateFaceDetectorWithLandmarks();
|
_detector = FaceAiSharpBundleFactory.CreateFaceDetectorWithLandmarks();
|
||||||
_recognizer = FaceAiSharpBundleFactory.CreateFaceEmbeddingsGenerator();
|
_recognizer = FaceAiSharpBundleFactory.CreateFaceEmbeddingsGenerator();
|
||||||
|
|
||||||
if (_baseDirectory != null)
|
if (_baseDirectory != null)
|
||||||
|
{
|
||||||
FaceImagePath = Path.Combine(_baseDirectory, "aligned.png");
|
FaceImagePath = Path.Combine(_baseDirectory, "aligned.png");
|
||||||
|
}
|
||||||
|
|
||||||
// Let's load the default stuff in this dictionary
|
// Let's load the default stuff in this dictionary
|
||||||
_faceImagesDict = new Dictionary<string, string>
|
_faceImagesDict = new Dictionary<string, string>
|
||||||
|
|
@ -49,7 +60,19 @@ public class FacialRecognition
|
||||||
|
|
||||||
if (faces.Count != 0)
|
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!);
|
_recognizer.AlignFaceUsingLandmarks(_image, faces.First().Landmarks!);
|
||||||
|
|
||||||
_referenceEmbeddings = _recognizer.GenerateEmbedding(_image);
|
_referenceEmbeddings = _recognizer.GenerateEmbedding(_image);
|
||||||
_image.Save(FaceImagePath!);
|
_image.Save(FaceImagePath!);
|
||||||
Console.WriteLine("Aligned faces!");
|
Console.WriteLine("Aligned faces!");
|
||||||
|
|
@ -113,4 +136,26 @@ public class FacialRecognition
|
||||||
var imageBytes = await hc.GetByteArrayAsync(path);
|
var imageBytes = await hc.GetByteArrayAsync(path);
|
||||||
return Image.Load<Rgb24>(imageBytes);
|
return Image.Load<Rgb24>(imageBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generate a unique filename for the floor plan
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A dynamic string with a randomized number appended to "image"</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
|
using Crestron.SimplSharp;
|
||||||
|
using PhotoBooth;
|
||||||
using RandomNameGeneratorLibrary;
|
using RandomNameGeneratorLibrary;
|
||||||
|
using Timeout = System.Threading.Timeout;
|
||||||
|
|
||||||
namespace CrestronOpenCvSharp.Capture;
|
namespace CrestronOpenCvSharp.Capture;
|
||||||
|
|
||||||
|
|
@ -10,15 +13,19 @@ public class MjpegCapture
|
||||||
private readonly FacialRecognition? _facialRecognition;
|
private readonly FacialRecognition? _facialRecognition;
|
||||||
private Timer? _timer;
|
private Timer? _timer;
|
||||||
private readonly PersonNameGenerator _personNameGenerator;
|
private readonly PersonNameGenerator _personNameGenerator;
|
||||||
|
private Contract _contract;
|
||||||
|
|
||||||
public bool CaptureRunning { get; private set; }
|
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;
|
_mjpegUrl = url;
|
||||||
_directory = Path.Combine(directory!, "captures");
|
_directory = Path.Combine(directory!, "captures");
|
||||||
_facialRecognition = facialRecognition;
|
_facialRecognition = facialRecognition;
|
||||||
|
_contract = contract;
|
||||||
|
|
||||||
_personNameGenerator = new PersonNameGenerator();
|
_personNameGenerator = new PersonNameGenerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,7 +79,8 @@ public class MjpegCapture
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
CaptureRunning = true;
|
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
|
try
|
||||||
{
|
{
|
||||||
HttpResponseMessage response = await _client.GetAsync(_mjpegUrl, HttpCompletionOption.ResponseHeadersRead);
|
HttpResponseMessage response = await _client.GetAsync(_mjpegUrl, HttpCompletionOption.ResponseHeadersRead);
|
||||||
|
|
@ -85,35 +93,36 @@ public class MjpegCapture
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine($"Saved frame to {fileName}");
|
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))
|
if (_facialRecognition!.CheckForFace(fileName))
|
||||||
{
|
{
|
||||||
StopCapture();
|
StopCapture();
|
||||||
|
_contract.Main.ImagePreview_Url(string.Empty);
|
||||||
|
Thread.Sleep(1000);
|
||||||
Console.WriteLine("Face detected, stopping capture");
|
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");
|
Console.WriteLine("Comparing captured face against database");
|
||||||
|
|
||||||
var result = await _facialRecognition.CompareFaces();
|
var result = await _facialRecognition.CompareFaces();
|
||||||
if (result is not null)
|
if (result is not null)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"We have found a match! The person in front of the camera is: {result}");
|
Console.WriteLine($"We have found a match! The person in front of the camera is: {result}");
|
||||||
|
_contract.Main.txtFeedback_Indirect($"{result} detected!");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine("No match was found in our database, let's add this person!");
|
Console.WriteLine("No match was found in our database, let's add this person!");
|
||||||
var randomFullName = _personNameGenerator.GenerateRandomFirstAndLastName();
|
var randomFullName = _personNameGenerator.GenerateRandomFirstAndLastName();
|
||||||
_facialRecognition.AddPersonToDatabase(randomFullName);
|
_facialRecognition.AddPersonToDatabase(randomFullName);
|
||||||
Thread.Sleep(2000);
|
Console.WriteLine("Person added to database");
|
||||||
Console.WriteLine("Person added to database, restarting capture");
|
_contract.Main.txtFeedback_Indirect($"{randomFullName} added to database");
|
||||||
StartCapture(2000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine("No face detected, carrying on!");
|
Console.WriteLine("No face detected, carrying on!");
|
||||||
|
_contract.Main.txtFeedback_Indirect($"No face detected!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharpPro;
|
using Crestron.SimplSharpPro;
|
||||||
|
using Crestron.SimplSharpPro.UI;
|
||||||
using CrestronOpenCvSharp.Capture;
|
using CrestronOpenCvSharp.Capture;
|
||||||
|
using PhotoBooth;
|
||||||
using Directory = Crestron.SimplSharp.CrestronIO.Directory;
|
using Directory = Crestron.SimplSharp.CrestronIO.Directory;
|
||||||
using Path = Crestron.SimplSharp.CrestronIO.Path;
|
using Path = Crestron.SimplSharp.CrestronIO.Path;
|
||||||
|
|
||||||
|
|
@ -11,6 +13,9 @@ public class ControlSystem : CrestronControlSystem
|
||||||
private FacialRecognition? _facialRecognition;
|
private FacialRecognition? _facialRecognition;
|
||||||
private MjpegCapture? _capture;
|
private MjpegCapture? _capture;
|
||||||
private UiHandler? _uiHandler;
|
private UiHandler? _uiHandler;
|
||||||
|
|
||||||
|
private XpanelForHtml5 _xpanel;
|
||||||
|
private Contract _contract;
|
||||||
|
|
||||||
// Default snapshot URL of a Bosch camera
|
// Default snapshot URL of a Bosch camera
|
||||||
private const string Url = "http://192.168.1.221/snap.jpg";
|
private const string Url = "http://192.168.1.221/snap.jpg";
|
||||||
|
|
@ -34,15 +39,31 @@ public class ControlSystem : CrestronControlSystem
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_facialRecognition = new FacialRecognition(_directory);
|
_xpanel = new XpanelForHtml5(0x03, this);
|
||||||
_capture = new MjpegCapture(Url, _directory, _facialRecognition);
|
_xpanel.Register();
|
||||||
|
_contract = new Contract(_xpanel);
|
||||||
|
_facialRecognition = new FacialRecognition(_directory, _contract);
|
||||||
|
_capture = new MjpegCapture(Url, _directory, _facialRecognition, _contract);
|
||||||
_uiHandler = new UiHandler(_capture);
|
_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)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ErrorLog.Error("Error in InitializeSystem: {0}", e.Message);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -34,4 +34,22 @@
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="..\..\..\Documents\Crestron\Crestron Construct\Solutions\PhotoBooth\PhotoBooth\output\contract\programming\SIMPLSharp\ContractSupport\ComponentMediator.g.cs">
|
||||||
|
<Link>UI\ComponentMediator.g.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\..\..\Documents\Crestron\Crestron Construct\Solutions\PhotoBooth\PhotoBooth\output\contract\programming\SIMPLSharp\ContractSupport\Contract.g.cs">
|
||||||
|
<Link>UI\Contract.g.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\..\..\Documents\Crestron\Crestron Construct\Solutions\PhotoBooth\PhotoBooth\output\contract\programming\SIMPLSharp\ContractSupport\IndexedEventArgs.g.cs">
|
||||||
|
<Link>UI\IndexedEventArgs.g.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\..\..\Documents\Crestron\Crestron Construct\Solutions\PhotoBooth\PhotoBooth\output\contract\programming\SIMPLSharp\ContractSupport\Main.g.cs">
|
||||||
|
<Link>UI\Main.g.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\..\..\Documents\Crestron\Crestron Construct\Solutions\PhotoBooth\PhotoBooth\output\contract\programming\SIMPLSharp\ContractSupport\UIEventArgs.g.cs">
|
||||||
|
<Link>UI\UIEventArgs.g.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue