Skip to main content

Cameras, Preview and Image Settings in C# (AR51.Net)

List the AR 51 cameras with their calibration values, stream a live JPEG preview, read and change their image settings, and tune them automatically. Cameras are spread over several camera servers; ar51.Cameras covers all of them.

List the cameras​

foreach (CameraInfo camera in await ar51.Cameras.GetCamerasAsync())
Console.WriteLine($"{camera.Name}: {camera.Width}x{camera.Height} @ {camera.FrameRate} fps, " +
$"{(camera.IsConnected ? "connected" : "offline")}");

Each CameraInfo has the camera's id (its serial number), name, driver type, connection state, the camera server it's plugged into, image size and frame rate, and its calibration — or null when the camera isn't calibrated. A camera server that doesn't answer in time is left out.

Calibration values​

Calibration follows the OpenCV convention: focal lengths (Fx, Fy) and principal point (Cx, Cy) in pixels, lens distortion in the order k1, k2, p1, p2, k3, and WorldToCamera, which maps an AR 51 world point into the camera's space.

SpaceUnitsAxes
AR 51 worldmetersleft-handed: X right, Y up, Z forward
Camera spacemetersX right, Y down, Z forward (OpenCV)

To project a world point to a pixel (before distortion):

Vector3 p = Vector3.Transform(worldPoint, calibration.WorldToCamera);
float u = calibration.Fx * p.X / p.Z + calibration.Cx;
float v = calibration.Fy * p.Y / p.Z + calibration.Cy;

The camera's own position in the world is the translation of the inverse matrix:

Matrix4x4.Invert(calibration.WorldToCamera, out Matrix4x4 cameraToWorld);
Console.WriteLine($"camera at {cameraToWorld.Translation} m");

Live preview​

StreamPreviewAsync streams a camera's video as JPEG images. Ending the await foreach loop stops the preview.

var options = new PreviewOptions { FitWidth = 640, FitHeight = 480, FrameRate = 5 };
await foreach (CameraFrame frame in ar51.Cameras.StreamPreviewAsync(camera.Id, options))
{
// frame.Jpeg holds one JPEG image; show it or save it.
}

The image is shrunk to fit inside FitWidth × FitHeight, keeping the camera's aspect ratio — never enlarged. null values use the camera's own size and frame rate; JpegQuality defaults to 70.

Many previews at once

Each preview costs network bandwidth. Open one stream per camera and share it between every view that shows that camera, and stream only the cameras on screen. For a wall of camera tiles, request small images at a low frame rate. The web dashboard sample does all three.

Image settings​

Settings affect every app using the system

Settings are saved on the server and apply to every app connected to the AR 51 system. Excluding a camera from tracking, or changing its exposure during a live session, changes tracking for everyone.

Read a camera's settings, change values with with, and send them back. Only the values that differ are sent, and the server saves them, so they survive a restart. The API doesn't report valid ranges, so keep each setting within the camera's range: a value outside it is clamped by the camera to the nearest limit, and current servers report the value you sent rather than the one the camera uses.

CameraSettings settings = await ar51.Cameras.GetSettingsAsync(camera.Id);
await ar51.Cameras.SetSettingsAsync(camera.Id, settings with { ExposureMicroseconds = 4000, Gain = 2 });
SettingWhat it does
ExposureMicrosecondsExposure time, in microseconds
Gain, Gamma, Contrast, SaturationOverall gain, gamma correction, contrast, color saturation
GainRed, GainGreen, GainBlueColor balance
Rotate180Turn the image upside down, for a camera mounted upside down
ExcludedFromTrackingLeave the camera out of tracking, for example while it's faulty

Auto-tune​

Auto-tune adjusts each camera's color balance (GainRed, GainGreen, GainBlue) using the camera's own one-shot white balance — for every camera you include (all of them by default), for every app using the system. It takes about two seconds. If you may want the old values back, save them first with GetSettingsAsync; read the new values afterwards the same way. Follow it with events:

ar51.Cameras.AutoTuneProgressChanged += (_, e) => Console.WriteLine($"auto-tune {e.Status.Progress:P0}");
ar51.Cameras.AutoTuneEnded += (_, e) => Console.WriteLine($"auto-tune {e.Outcome}");
await ar51.Cameras.StartAutoTuneAsync(); // all cameras; pass AutoTuneOptions to choose some

It ends as Completed, Failed (see each camera's error) or Cancelled.

Current AR 51 servers

Current servers don't report auto-tune progress, so AR51.Net estimates it: AutoTuneStarted at once, AutoTuneProgressChanged over about two seconds, then AutoTuneEnded with Completed. While it estimates, AutoTuneStatus.IsEstimated is true. Current servers also can't cancel an auto-tune: CancelAutoTuneAsync doesn't throw, and the auto-tune finishes as Completed. An auto-tune started by another app isn't seen. When a server reports real progress, AR51.Net uses it instead, with no change to your code.

Complete sample​

List the cameras with their calibration, save one preview image of the first camera, and print its settings.

Program.cs
// List the cameras with their calibration, save one preview image of the first camera, and show its settings.
using AR51.Net;
using System.Numerics;

await using IAR51Client ar51 = AR51Client.Create();
await ar51.StartAsync();

IReadOnlyList<CameraInfo> cameras = await ar51.Cameras.GetCamerasAsync();
foreach (CameraInfo camera in cameras)
{
Console.WriteLine($"{camera.Name} ({camera.Type}) {camera.Width}x{camera.Height} @ {camera.FrameRate} fps, " +
$"{(camera.IsConnected ? "connected" : "offline")}, on {camera.ServerHost}");
if (camera.Calibration is { } calibration)
{
Matrix4x4.Invert(calibration.WorldToCamera, out Matrix4x4 cameraToWorld);
Console.WriteLine($" fx {calibration.Fx:F1} px, position {cameraToWorld.Translation} m");
}
}

if (cameras.Count == 0) return;
CameraInfo first = cameras[0];

// A small preview that fits a 640 x 480 box, keeping the camera's aspect ratio. Ending the loop stops the preview.
await foreach (CameraFrame frame in ar51.Cameras.StreamPreviewAsync(first.Id, new PreviewOptions { FitWidth = 640, FitHeight = 480, FrameRate = 5 }))
{
var file = $"{first.Id}.jpg";
await File.WriteAllBytesAsync(file, frame.Jpeg.ToArray());
Console.WriteLine($"Saved {file}: {frame.Width}x{frame.Height}, camera at {frame.CameraFps:F0} fps");
break;
}

CameraSettings settings = await ar51.Cameras.GetSettingsAsync(first.Id);
Console.WriteLine($"Settings of {first.Name}: {settings}");
// To change a setting: await ar51.Cameras.SetSettingsAsync(first.Id, settings with { Gain = 2 });

View this sample on Bitbucket — clone the samples repository to run it.

Reference​

ICameraClient · CameraInfo · CameraCalibration · PreviewOptions · CameraSettings

Was this page helpful?