Ok, here is the promised example:
const int NumDriverBuffers = 100;
static void Main()
{
var driverPath = Path.Combine(Environment.GetEnvironmentVariable("CVB"), "Drivers", "GenICam.vin");
using (var camera = DriverExtensions.TryOpenWithBufferCount(driverPath, NumDriverBuffers))
{
if (camera == null)
{
Console.WriteLine("Error loading driver: " + driverPath);
return;
}
camera.SetLockModeToOn();
camera.StartAcquisition();
try
{
for (int i = 0; i < 2 * NumDriverBuffers; i++)
{
var image = camera.WaitForNextImage();
// for a real application the tasks should be stored for proper app-exit handling
Task.Run(() =>
{
Parallel.For(0, image.Height, line =>
{
// do something
});
image.Unlock(); // and thus dispose...
});
}
}
finally
{
camera.AbortAcquisition();
}
}
}
And for this you need these helper classes (and the references to iCVCImg.dll and iCVCDriver.dll):
class RingBufferImage : IDisposable
{
private Cvb.Image.IMG _driverImage;
private Cvb.SharedImg _bufferImage;
private int _bufferIndex;
public static RingBufferImage FromCurrent(Cvb.SharedImg driver)
{
if (driver == null)
throw new NullReferenceException(nameof(driver));
return new RingBufferImage(driver, driver.GetCurrentBufferIndex());
}
private RingBufferImage(Cvb.SharedImg driverImage, int bufferIndex)
{
_driverImage = driverImage;
_bufferImage = driverImage.GetBufferImage(bufferIndex);
_bufferIndex = bufferIndex;
}
~RingBufferImage()
{
Dispose(disposing: false);
}
// Simply a readable alias for dispose.
public void Unlock()
{
Dispose();
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_bufferImage?.Dispose();
Cvb.Driver.IRingBuffer.RBUnlock(_driverImage, _bufferIndex);
}
}
public static implicit operator Cvb.Image.IMG(RingBufferImage image)
{
return image._bufferImage;
}
public int Width
{
get { return Cvb.Image.ImageWidth(this); }
}
public int Height
{
get { return Cvb.Image.ImageHeight(this); }
}
}
static class DriverExtensions
{
// Opens a driver with a given number of buffers; null on error.
public static Cvb.SharedImg TryOpenWithBufferCount(string path, int numBuffers)
{
var driver = TryOpen(path);
if (driver == null)
return null;
if (driver.GetBufferCount() == numBuffers)
return driver;
try
{
return driver.CreateWithNewNumberOfBuffers(numBuffers);
}
finally
{
driver.Dispose();
}
}
// Opens a driver; null on error.
public static Cvb.SharedImg TryOpen(string path)
{
Cvb.SharedImg driver;
Cvb.Image.LoadImageFile(path, out driver);
return driver;
}
public static int GetBufferCount(this Cvb.SharedImg driver)
{
if (driver == null)
throw new NullReferenceException(nameof(driver));
if (!Cvb.Driver.IRingBuffer.CanRingBuffer(driver))
throw new InvalidOperationException("Driver image does not support the IRingBuffer interface");
int numBuffers = 0;
Cvb.Image.IMG dummy;
int result = Cvb.Driver.IRingBuffer.RBNumBuffer(driver, Cvb.Driver.IRingBuffer.TRingbufferNumbufferCMD.RINGBUFFER_NUMBUFFER_CMD_GET, ref numBuffers, out dummy);
if (result < 0)
throw new ExternalException("Error getting number of buffers", result);
return numBuffers;
}
public static Cvb.SharedImg CreateWithNewNumberOfBuffers(this Cvb.SharedImg driver, int numBuffers)
{
if (driver == null)
throw new NullReferenceException(nameof(driver));
if (!Cvb.Driver.IRingBuffer.CanRingBuffer(driver))
throw new InvalidOperationException("Driver image does not support the IRingBuffer interface");
Cvb.SharedImg newDriver;
int result = Cvb.Driver.IRingBuffer.RBNumBuffer(driver, Cvb.Driver.IRingBuffer.TRingbufferNumbufferCMD.RINGBUFFER_NUMBUFFER_CMD_SET, ref numBuffers, out newDriver);
if (result < 0)
throw new ExternalException("Error creating new buffer driver image", result);
return newDriver;
}
public static void SetLockModeToOn(this Cvb.SharedImg driver)
{
if (driver == null)
throw new NullReferenceException(nameof(driver));
if (!Cvb.Driver.IRingBuffer.CanRingBuffer(driver))
throw new InvalidOperationException("Driver image does not support the IRingBuffer interface");
var lockModeOn = Cvb.Driver.IRingBuffer.TRingbufferLockmode.RINGBUFFER_LOCKMODE_ON;
int result = Cvb.Driver.IRingBuffer.RBLockMode(driver, Cvb.Driver.IRingBuffer.TRingbufferLockmodeCMD.RINGBUFFER_LOCKMODE_CMD_SET, ref lockModeOn);
if (result < 0)
throw new ExternalException("Error setting lock-mode to: on", result);
}
public static int GetCurrentBufferIndex(this Cvb.SharedImg driver)
{
if (driver == null)
throw new NullReferenceException(nameof(driver));
if (!Cvb.Driver.IRingBuffer.CanRingBuffer(driver))
throw new InvalidOperationException("Driver image does not support the IRingBuffer interface");
int bufferIndex;
int result = Cvb.Driver.IRingBuffer.RBBufferSeq(driver, 0, out bufferIndex);
if (result < 0)
throw new ExternalException("Error getting current buffer index", result);
return bufferIndex;
}
public static Cvb.SharedImg GetBufferImage(this Cvb.SharedImg driver, int bufferIndex)
{
if (driver == null)
throw new NullReferenceException(nameof(driver));
if (!Cvb.Driver.IRingBuffer.CanRingBuffer(driver))
throw new InvalidOperationException("Driver image does not support the IRingBuffer interface");
Cvb.SharedImg bufferImage;
int result = Cvb.Driver.IRingBuffer.RBGetBufferImage(driver, bufferIndex, out bufferImage);
if (result < 0)
throw new ExternalException("Error getting image at buffer index", result);
return bufferImage;
}
public static void StartAcquisition(this Cvb.SharedImg driver)
{
int result = Cvb.Driver.IGrab2.G2Grab(driver);
if (result < 0)
throw new ExternalException("Error starting acquisition", result);
}
public static void AbortAcquisition(this Cvb.SharedImg driver)
{
int result = Cvb.Driver.IGrab2.G2Freeze(driver, kill: true);
if (result < 0)
throw new ExternalException("Error stopping acquisition", result);
}
public static RingBufferImage WaitForNextImage(this Cvb.SharedImg driver)
{
int result = Cvb.Driver.IGrab2.G2Wait(driver);
if (result < 0)
throw new ExternalException("Error waiting for next image", result);
return RingBufferImage.FromCurrent(driver);
}
}