forked from amkovkov/GranuSightSoftware2
feat: camera tuning + capturing command + raw image correction
This commit is contained in:
@@ -58,7 +58,11 @@ public class CameraService : IDisposable
|
||||
ImageCaptureFrameBufferCount = 2,
|
||||
ImageCaptureWidth = 4056,
|
||||
ImageCaptureHeight = 3080,
|
||||
CameraHardSettings = null
|
||||
CameraHardSettings = null,
|
||||
DecodeGainR = 1,
|
||||
DecodeGainG = 1,
|
||||
DecodeGainB = 1,
|
||||
DecodeBlackLevel = 256
|
||||
};
|
||||
|
||||
public string CameraId { get; init; } = "";
|
||||
@@ -70,6 +74,10 @@ public class CameraService : IDisposable
|
||||
public int ImageCaptureWidth { get; init; }
|
||||
public int ImageCaptureHeight { get; init; }
|
||||
public IConfigurationSection? CameraHardSettings { get; init; }
|
||||
public double DecodeGainR { get; set; }
|
||||
public double DecodeGainG { get; set; }
|
||||
public double DecodeGainB { get; set; }
|
||||
public int DecodeBlackLevel { get; set; }
|
||||
}
|
||||
|
||||
private bool _disposedValue;
|
||||
@@ -94,6 +102,7 @@ public class CameraService : IDisposable
|
||||
|
||||
public bool IsImageCapturing { get; private set; } = false;
|
||||
public List<FrameBuffer> ViewFinderBufferQueue { get; private set; } = new List<FrameBuffer>();
|
||||
public CameraServiceConfiguration Configuration => _configuration;
|
||||
|
||||
public CameraService(ILogger<CameraService> logger, CameraServiceConfiguration? configuration = null, bool autoInitialize = false)
|
||||
{
|
||||
@@ -298,7 +307,8 @@ public class CameraService : IDisposable
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
int result = _camera.Start();
|
||||
// int result = _camera.Start();
|
||||
int result = _camera.Start(GetSettingsControlList(_cameraHardSettings));
|
||||
if (result < 0)
|
||||
{
|
||||
_logger.LogCritical("Error while camera start {Result}", result);
|
||||
@@ -504,6 +514,7 @@ public class CameraService : IDisposable
|
||||
|
||||
_state |= State.ImageCaptureFrameBuffersMapped;
|
||||
}
|
||||
|
||||
private string GetSettings(int indent = 0)
|
||||
{
|
||||
if (_camera is null)
|
||||
@@ -562,7 +573,60 @@ public class CameraService : IDisposable
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public async Task<OpenCvSharp.Mat?> CaptureImage(CancellationToken cancellationToken, int framesCount = 1)
|
||||
private void ApplyRequestSettings(Request request, Dictionary<string, object> settings)
|
||||
{
|
||||
if (_camera is null)
|
||||
throw new InvalidOperationException("Camera not initialized");
|
||||
|
||||
foreach (var (id, info) in _camera.Controls)
|
||||
{
|
||||
if (!settings.TryGetValue(id.Name, out var parameter))
|
||||
continue;
|
||||
|
||||
ControlValue controlValue;
|
||||
try
|
||||
{
|
||||
controlValue = ControlValueHelper.Convert(parameter, id, info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error while converting value (control name:{}, control type:{}, value type:{}, value:{})", id.Name, id.Type, parameter.GetType(), parameter);
|
||||
continue;
|
||||
}
|
||||
|
||||
request.Controls.Set(id.Id, controlValue);
|
||||
}
|
||||
}
|
||||
private ControlList GetSettingsControlList(Dictionary<string, object> settings)
|
||||
{
|
||||
if (_camera is null)
|
||||
throw new InvalidOperationException("Camera not initialized");
|
||||
|
||||
var controlList = new ControlList();
|
||||
|
||||
foreach (var (id, info) in _camera.Controls)
|
||||
{
|
||||
if (!settings.TryGetValue(id.Name, out var parameter))
|
||||
continue;
|
||||
|
||||
ControlValue controlValue;
|
||||
try
|
||||
{
|
||||
controlValue = ControlValueHelper.Convert(parameter, id, info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error while converting value (control name:{}, control type:{}, value type:{}, value:{})", id.Name, id.Type, parameter.GetType(), parameter);
|
||||
continue;
|
||||
}
|
||||
|
||||
controlList.Set(id.Id, controlValue);
|
||||
}
|
||||
|
||||
return controlList;
|
||||
}
|
||||
|
||||
public async Task<OpenCvSharp.Mat?> CaptureImage(CancellationToken cancellationToken, int framesCount = 1, Dictionary<string, object>? settings = null)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(framesCount, 1, nameof(framesCount));
|
||||
|
||||
@@ -581,6 +645,8 @@ public class CameraService : IDisposable
|
||||
.CreateLinkedTokenSource(_disposeCts.Token, cancellationToken)
|
||||
.Token;
|
||||
|
||||
if (IsImageCapturing)
|
||||
return null;
|
||||
IsImageCapturing = true;
|
||||
|
||||
_logger.LogDebug("Capturing {} frame(s)", framesCount);
|
||||
@@ -609,11 +675,13 @@ public class CameraService : IDisposable
|
||||
foreach (var buffer in buffers)
|
||||
{
|
||||
var request = _camera.CreateRequest(1);
|
||||
ApplySettings(request, _cameraHardSettings);
|
||||
|
||||
var result = request.AddBuffer(_imageCaptureStream, buffer);
|
||||
if (result < 0)
|
||||
throw new Exception("Error while request create");
|
||||
|
||||
if (settings is not null)
|
||||
ApplyRequestSettings(request, settings);
|
||||
requests.Add(request);
|
||||
}
|
||||
_logger.LogDebug("{} request(s) created", requests.Count());
|
||||
@@ -726,7 +794,7 @@ public class CameraService : IDisposable
|
||||
|
||||
try
|
||||
{
|
||||
image = decoder.Decode(checked((int)size.Width), checked((int)size.Height), checked((int)stride), planesData);
|
||||
image = decoder.Decode(checked((int)size.Width), checked((int)size.Height), checked((int)stride), planesData, _configuration.DecodeGainR, _configuration.DecodeGainG, _configuration.DecodeGainB, _configuration.DecodeBlackLevel);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -756,40 +824,6 @@ public class CameraService : IDisposable
|
||||
IsImageCapturing = false;
|
||||
return image;
|
||||
}
|
||||
private void ApplySettings(Request request, Dictionary<string, object> settings)
|
||||
{
|
||||
if (_camera is null)
|
||||
throw new InvalidOperationException("Camera not initialized");
|
||||
|
||||
foreach (var (id, info) in _camera.Controls)
|
||||
{
|
||||
if (!settings.ContainsKey(id.Name))
|
||||
continue;
|
||||
|
||||
var value = settings[id.Name];
|
||||
ControlValue? controlValue;
|
||||
try
|
||||
{
|
||||
if (!id.IsArray)
|
||||
controlValue = ControlValueHelper.ConvertToControlValue(value, id, info);
|
||||
else
|
||||
controlValue = ControlValueHelper.ConvertToControlArray(value, id, info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error while converting value (control name:{}, control type:{}, value type:{}, value:{})", id.Name, id.Type, value.GetType(), value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (controlValue is null)
|
||||
{
|
||||
_logger.LogWarning("Cannot convert to control value (control name:{}, control type:{}, value type:{}, value:{})", id.Name, id.Type, value.GetType(), value);
|
||||
continue;
|
||||
}
|
||||
|
||||
request.Controls.Set(id.Id, controlValue);
|
||||
}
|
||||
}
|
||||
|
||||
public void StartViewFinder()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user