Table of Contents

YOLO image recognition + drawing (.NET LTS)

This sample is the image-based equivalent of the CmdTest.Net sample flow:

  • load an image from disk
  • load a YOLO ONNX model via AddYoloModelDetectionRecognitionOption
  • run recognition using Recognizer
  • draw detections onto the image via AddYoloModelDetectionDrawingOptions
  • save the resulting image

Prerequisites and packages

Applies to CapCognition SDK 2.2.x and .NET 10 on Windows x64, Linux x64, or Linux ARM64 (Raspberry Pi OS 64-bit). See platform requirements and licensing.

Place input.jpg and your YOLO object-detection ONNX export yolo-model.onnx in the working directory. The module supports YOLO 5, 8, 26, and 26 e2e variants. The export must have the input/output layout and class metadata expected by the SDK; an arbitrary ONNX model is not sufficient. Check model loading before deploying a custom export.

dotnet add package CapCognition.Net
dotnet add package CapCognition.Net.YoloModelDetection
dotnet add package Microsoft.Extensions.Logging.Console
dotnet add package Microsoft.Extensions.Logging.Debug

Use compatible 2.2.x SDK packages. Replace Program.cs with the example and run dotnet run. Expected output: a detection count and input_yolo_result.png beside the input. Zero detections is valid for an image without matching objects. Call YoloModelDetection.Use() without an argument for trial mode, or pass a production license.

Example code

using CapCognition.Net;
using CapCognition.Net.Core.Processing.Common;
using CapCognition.Net.YoloModelDetection.Common;
using CapCognition.Net.YoloModelDetection.Processor;
using Microsoft.Extensions.Logging;
using SkiaSharp;

// Input image + YOLO model
const string imagePath = @"input.jpg";
const string modelPath = @"yolo-model.onnx";

using var loggerFactory = LoggerFactory.Create(builder =>
{
    builder.SetMinimumLevel(LogLevel.Information);
    builder.AddConsole();
    builder.AddDebug();
});

// Initialize CapCognition once at program start
CapCognition.Net.Core.CapCognition.Initialize(
    loggerFactory,
    [
        YoloModelDetection.Use(/* Add your license code here */),
    ]);

CapCognition.Net.Core.CapCognition.EnableImageProcessingLogs = true;

// YOLO recognition options
using var modelStreamInfo = new YoloModelDetectionRecognitionOptions.ModelStreamInfo(
    new FileStream(modelPath, FileMode.Open, FileAccess.Read),
    streamName: Path.GetFileNameWithoutExtension(modelPath));

var recognitionOptions = new RecognitionOptionBuilder()
    .AddYoloModelDetectionRecognitionOption()
        .UseFittedImageForRecognition()
        .UseModel(modelStreamInfo)
        .ConfigureOption(opt =>
        {
            // Optional: control model caching behavior
            //opt.ClearModelCacheFolder();
            if (!opt.CreateAndLoadModel())
            {
                throw new InvalidOperationException("Could not load the YOLO model; check the export and metadata.");
            }
        })
        .Done()
    .Build();

try
{
    // Drawing options (draw bounding boxes)
    var drawingOptions = new ResultDrawingOptionsBuilder()
        .AddYoloModelDetectionDrawingOptions()
            .DisplayObjectSurroundingBox()
            .Done()
        .Build();

    using var bitmap = SKBitmap.Decode(imagePath);
    if (bitmap == null)
    {
        Console.WriteLine($"Could not load image: {imagePath}");
        return;
    }

    using var recognizer = new Recognizer();

    var prepared = recognizer.PrepareProcessorsAsync(bitmap.Width, bitmap.Height, recognitionOptions)
        .GetAwaiter().GetResult();
    if (!prepared)
    {
        Console.WriteLine("Failed to prepare YOLO processor");
        return;
    }

    // Pass drawing options so detections are drawn onto the bitmap.
    // disableBitmapDisposal keeps the bitmap alive after processing.
    var result = recognizer.ProcessImageAsync(bitmap, drawingOptions, disableBitmapDisposal: true)
        .GetAwaiter().GetResult();

    if (result == null)
    {
        Console.WriteLine("Recognition failed");
        return;
    }

    Console.WriteLine($"Detected {result.Results.Count} object(s)");

    var outputDir = Path.GetDirectoryName(Path.GetFullPath(imagePath))!;
    var outputPath = Path.Combine(
        outputDir,
        Path.GetFileNameWithoutExtension(imagePath) + "_yolo_result.png");

    using var encoded = bitmap.Encode(SKEncodedImageFormat.Png, 90);
    File.WriteAllBytes(outputPath, encoded.ToArray());

    Console.WriteLine($"Wrote result image: {outputPath}");
}
finally
{
    recognitionOptions.Dispose();
}

Step-by-step explanation

  1. Input files

    • imagePath points to the input image.
    • modelPath points to your YOLO ONNX model.
    • With relative paths like "input.jpg", the files are resolved relative to the current working directory of your app.
  2. Logging (optional, but recommended)

    • A LoggerFactory is created so the SDK can emit diagnostic messages (console + debug output).
  3. Initialize CapCognition (once per process)

    • CapCognition.Initialize(...) must be called once at program startup.
    • You pass the license codes for the modules you want to use (here: YoloModelDetection).
  4. (Optional) enable image processing logs

    • CapCognition.EnableImageProcessingLogs = true can help during setup/debugging.
  5. Image-only processing

    • This sample loads a bitmap directly and does not initialize video capture or download RTSP codecs.
  6. Create YOLO recognition options

    • A ModelStreamInfo is created from the ONNX file.
    • AddYoloModelDetectionRecognitionOption() configures the YOLO processor.
    • UseFittedImageForRecognition() typically gives good results for object detection.
    • CreateAndLoadModel() ensures the model is loaded before processing starts.
    • ClearModelCacheFolder() is optional; useful if you want to force a clean reload while iterating.
  7. Create drawing options

    • AddYoloModelDetectionDrawingOptions() controls how detections are rendered.
    • DisplayObjectSurroundingBox() draws bounding boxes on the output image.
  8. Load the image

    • SKBitmap.Decode(imagePath) loads the bitmap into memory.
    • If loading fails, the program exits early.
  9. Prepare processors

    • PrepareProcessorsAsync(width, height, recognitionOptions) pre-allocates internal resources for the given image size.
    • This should be called before the first ProcessImageAsync(...).
  10. Run recognition + draw results

    • ProcessImageAsync(bitmap, drawingOptions, disableBitmapDisposal: true) runs detection.
    • Because you pass drawingOptions, the SDK draws the detection overlays directly onto bitmap.
    • disableBitmapDisposal: true ensures the bitmap stays usable after processing.
  11. Save the result image

    • The sample writes *_yolo_result.png next to the input image (resolved via Path.GetFullPath(imagePath) so relative paths work reliably).
  12. Cleanup

    • recognitionOptions.Dispose() releases resources associated with the configured processors/models.