diff --git a/WebcamDemo/App.xaml b/WebcamDemo/App.xaml
new file mode 100644
index 0000000..a029d96
--- /dev/null
+++ b/WebcamDemo/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/WebcamDemo/App.xaml.cs b/WebcamDemo/App.xaml.cs
new file mode 100644
index 0000000..6a5ee7e
--- /dev/null
+++ b/WebcamDemo/App.xaml.cs
@@ -0,0 +1,14 @@
+using System.Configuration;
+using System.Data;
+using System.Windows;
+
+namespace WebcamDemo
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ }
+
+}
diff --git a/WebcamDemo/AssemblyInfo.cs b/WebcamDemo/AssemblyInfo.cs
new file mode 100644
index 0000000..b0ec827
--- /dev/null
+++ b/WebcamDemo/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/WebcamDemo/MainWindow.xaml b/WebcamDemo/MainWindow.xaml
new file mode 100644
index 0000000..18a288a
--- /dev/null
+++ b/WebcamDemo/MainWindow.xaml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/WebcamDemo/MainWindow.xaml.cs b/WebcamDemo/MainWindow.xaml.cs
new file mode 100644
index 0000000..bfe6faf
--- /dev/null
+++ b/WebcamDemo/MainWindow.xaml.cs
@@ -0,0 +1,125 @@
+using Emgu.CV;
+using Emgu.CV.CvEnum;
+using Emgu.CV.Util;
+using SkiaSharp;
+using SkiaSharp.Views.Desktop;
+using System.Windows;
+using System.Windows.Threading;
+using YoloDotNet;
+using YoloDotNet.Enums;
+using YoloDotNet.Extensions;
+using YoloDotNet.Models;
+using YoloDotNet.Test.Common;
+
+namespace WebcamDemo
+{
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ public partial class MainWindow : Window
+ {
+ #region Fields
+
+ private readonly Yolo _yolo = default!;
+ private SKImage _currentFrame = default!;
+ private Dispatcher _dispatcher = default!;
+
+ private bool _runDetection = false;
+
+ private SKRect _rect;
+
+ #endregion
+
+ #region Constants
+
+ const int WEBCAM_WIDTH = 1080;
+ const int WEBCAM_HEIGHT = 608;
+ const int FPS = 30;
+ const string FRAME_FORMAT_EXTENSION = ".png";
+
+ #endregion
+
+ public MainWindow()
+ {
+ InitializeComponent();
+
+ // Instantiate yolo
+ _yolo = new Yolo(new YoloOptions()
+ {
+ OnnxModel = SharedConfig.GetTestModelV11(ModelType.ObjectDetection),
+ ModelType = ModelType.ObjectDetection,
+ Cuda = true,
+ PrimeGpu = false
+ });
+
+ _dispatcher = Dispatcher.CurrentDispatcher;
+
+ _currentFrame = SKImage.FromBitmap(new SKBitmap(WEBCAM_WIDTH, WEBCAM_HEIGHT));
+ _rect = new SKRect(0, 0, WEBCAM_WIDTH, bottom: WEBCAM_HEIGHT);
+
+ // Start webcam on a separate thread
+ Task.Run(() => WebcamAsync());
+ }
+
+ private async Task WebcamAsync()
+ {
+ // Configure webcam
+ using var capture = new VideoCapture(0, VideoCapture.API.DShow);
+ capture.Set(CapProp.FrameCount, FPS);
+ capture.Set(CapProp.FrameWidth, WEBCAM_WIDTH);
+ capture.Set(CapProp.FrameHeight, WEBCAM_HEIGHT);
+
+ using var mat = new Mat();
+ using var buffer = new VectorOfByte();
+
+ while (true)
+ {
+ // Capture current frame from webcam
+ capture.Read(mat);
+
+ // Encode mat to a valid image format and to a buffer
+ CvInvoke.Imencode(FRAME_FORMAT_EXTENSION, mat, buffer);
+
+ // "Rewind" buffer
+ buffer.Position = 0;
+
+ // Read buffer to an SKImage
+ _currentFrame = SKImage.FromEncodedData(buffer);
+
+ // Clean up
+ buffer.Clear();
+
+ if (_runDetection)
+ {
+ // Run inference on frame
+ var results = _yolo.RunObjectDetection(_currentFrame);
+
+ // Draw results
+ _currentFrame = _currentFrame.Draw(results);
+ }
+
+ // Update GUI
+ await _dispatcher.InvokeAsync(() => WebCamFrame.InvalidateVisual());
+ }
+ }
+
+ private void UpdateWebcamFrame(object sender, SKPaintSurfaceEventArgs e)
+ {
+ using var canvas = e.Surface.Canvas;
+ canvas.DrawImage(_currentFrame, _rect);
+ canvas.Flush();
+ }
+
+ private void StartClick(object sender, RoutedEventArgs e)
+ => _runDetection = true;
+
+ private void StopClick(object sender, RoutedEventArgs e)
+ => _runDetection = false;
+
+ private void WindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
+ {
+ _yolo?.Dispose();
+ _currentFrame?.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/WebcamDemo/WebcamDemo.csproj b/WebcamDemo/WebcamDemo.csproj
new file mode 100644
index 0000000..7cba4f2
--- /dev/null
+++ b/WebcamDemo/WebcamDemo.csproj
@@ -0,0 +1,23 @@
+
+
+
+ WinExe
+ net8.0-windows
+ enable
+ enable
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/YoloDotNet.sln b/YoloDotNet.sln
index da84628..5a9a8a5 100644
--- a/YoloDotNet.sln
+++ b/YoloDotNet.sln
@@ -22,6 +22,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{5FF17268-4
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C5DF82EF-FED8-4308-A10F-F34E9B714CCF}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebcamDemo", "WebcamDemo\WebcamDemo.csproj", "{96728CA4-2237-42B2-A251-F701AA146508}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -48,6 +50,10 @@ Global
{086DFB71-ACF4-4856-A73E-F20B9DB8775A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{086DFB71-ACF4-4856-A73E-F20B9DB8775A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{086DFB71-ACF4-4856-A73E-F20B9DB8775A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {96728CA4-2237-42B2-A251-F701AA146508}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {96728CA4-2237-42B2-A251-F701AA146508}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {96728CA4-2237-42B2-A251-F701AA146508}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {96728CA4-2237-42B2-A251-F701AA146508}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -58,6 +64,7 @@ Global
{8DB429FE-35C1-4879-9FF1-9811AFF808C5} = {5FF17268-47B9-4137-B45E-428D17702834}
{6E2C70F1-F107-4C39-817E-CD21AD460B54} = {5FF17268-47B9-4137-B45E-428D17702834}
{086DFB71-ACF4-4856-A73E-F20B9DB8775A} = {5FF17268-47B9-4137-B45E-428D17702834}
+ {96728CA4-2237-42B2-A251-F701AA146508} = {C5DF82EF-FED8-4308-A10F-F34E9B714CCF}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3673E62-2658-4C27-9C6A-A3215F416E05}