Created
April 18, 2025 02:46
-
-
Save AldeRoberge/51393499d1e66d6282c21c5f9f959a6d to your computer and use it in GitHub Desktop.
Captures an image from the webcam and quickly analyzes whether a person is present.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.Extensions.DependencyInjection; | |
using Microsoft.Extensions.Hosting; | |
using Microsoft.Extensions.AI; | |
using OpenCvSharp; | |
using AForge.Video.DirectShow; | |
namespace ADG.Playground.Vision | |
{ | |
internal class VisionResponse | |
{ | |
public bool IsPersonPresent { get; set; } | |
public float Confidence { get; set; } | |
} | |
class Program | |
{ | |
static async Task Main(string[] args) | |
{ | |
// Build host with DI | |
var builder = Host.CreateApplicationBuilder(args); | |
// Register Ollama chat client | |
builder.Services.AddChatClient( | |
new OllamaChatClient( | |
new Uri("http://localhost:11434"), | |
modelId: "gemma3:12b" | |
) | |
); | |
var host = builder.Build(); | |
var chatClient = host.Services.GetRequiredService<IChatClient>(); | |
while (true) | |
{ | |
string imagePath; | |
try | |
{ | |
imagePath = await CaptureImageAsync(); | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine($"Error capturing image: {ex.Message}"); | |
break; | |
} | |
if (string.IsNullOrEmpty(imagePath)) | |
{ | |
Console.WriteLine("No image captured."); | |
break; | |
} | |
// Read image and prepare chat message | |
byte[] imageBytes = await File.ReadAllBytesAsync(imagePath); | |
var chatMessage = new ChatMessage(ChatRole.User, "Analyze this image for person presence.") | |
{ | |
Contents = { new DataContent(imageBytes, "image/png") } | |
}; | |
// Send to AI service and display result | |
var response = await chatClient.GetResponseAsync<VisionResponse>(chatMessage); | |
Console.WriteLine( | |
$"Person present: {response.Result.IsPersonPresent}, " + | |
$"confidence: {response.Result.Confidence:F2}" | |
); | |
} | |
} | |
private static async Task<string> CaptureImageAsync() | |
{ | |
const string assetsFolder = "Assets"; | |
const string fileName = "captured"; | |
string currentDateTimeAsFileName = DateTime.Now.ToString("yyyyMMdd_HHmmss"); | |
string filePath = Path.Combine(assetsFolder, $"{fileName}_{currentDateTimeAsFileName}.png"); | |
Directory.CreateDirectory(assetsFolder); | |
// List available video devices | |
var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice); | |
if (videoDevices.Count == 0) | |
throw new InvalidOperationException("No video devices found."); | |
Console.WriteLine("Available video devices:"); | |
for (int i = 0; i < videoDevices.Count; i++) | |
{ | |
Console.WriteLine($"[{i}] {videoDevices[i].Name}"); | |
} | |
const int deviceIndex = 7; | |
if (deviceIndex < 0 || deviceIndex >= videoDevices.Count) | |
throw new ArgumentOutOfRangeException(nameof(deviceIndex), "Invalid device index."); | |
Console.WriteLine($"Using device: {videoDevices[deviceIndex].Name}"); | |
using var capture = new VideoCapture(deviceIndex); // or use CAP_ANY | |
if (!capture.IsOpened()) | |
throw new InvalidOperationException("Webcam could not be opened."); | |
// Warm up | |
using var temp = new Mat(); | |
for (int i = 0; i < 10; i++) | |
{ | |
capture.Read(temp); | |
await Task.Delay(100); // wait a bit between frames | |
} | |
using var frame = new Mat(); | |
capture.Read(frame); | |
if (frame.Empty()) | |
throw new InvalidOperationException("Captured frame is empty (black)."); | |
Cv2.ImWrite(filePath, frame); | |
return Path.GetFullPath(filePath); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment