Samples#
Device Removal Handling#
C#
/*
Note: Before getting started, Basler recommends reading the Programmer's Guide topic
in the pylon C# API documentation: https://docs.baslerweb.com/pylonapi/net/
This sample program demonstrates how to be informed about the removal of a camera device.
It also shows how to reconnect to a removed device.
Attention:
If you build this sample and run it under a debugger using a GigE camera device, pylon will set the heartbeat
timeout to 5 minutes. This is done to allow debugging and single stepping of the code without
the camera thinking we're hung because we don't send any heartbeats.
Accordingly, it would take 5 minutes for the application to notice the disconnection of a GigE device.
*/
using System;
using System.Diagnostics;
using Basler.Pylon;
namespace DeviceRemovalHandling
{
class DeviceRemovalHandling
{
// Event handler for connection loss, is shown here for demonstration purposes only.
// Note: This event is always called on a separate thread.
static void OnConnectionLost( Object sender, EventArgs e )
{
// For demonstration purposes, print a message.
Console.WriteLine( "OnConnectionLost has been called." );
}
internal static void Main()
{
// Time to wait for the user to disconnect the camera device.
const int cTimeOutMs = 60000;
// The exit code of the sample application.
int exitCode = 0;
try
{
// Create a camera object that selects the first camera device found.
// More constructors are available for selecting a specific camera device.
using (Camera camera = new Camera())
{
// Print the model name of the camera.
Console.WriteLine( "Using camera {0}.", camera.CameraInfo[CameraInfoKey.ModelName] );
// Set the acquisition mode to free running continuous acquisition when the camera is opened.
camera.CameraOpened += Configuration.AcquireContinuous;
// For demonstration purposes, only add an event handler for connection loss.
camera.ConnectionLost += OnConnectionLost;
// Open the connection to the camera device.
camera.Open();
///////////////// Don't single step beyond this line when using GigE cameras (see comments above) ///////////////////////////////
// Before testing the callbacks, we manually set the heartbeat timeout to a short value when using GigE cameras.
// For debug versions, the heartbeat timeout has been set to 5 minutes, so it would take up to 5 minutes
// until device removal is detected.
camera.Parameters[PLTransportLayer.HeartbeatTimeout].TrySetValue( 1000, IntegerValueCorrection.Nearest ); // 1000 ms timeout
// Start the grabbing.
camera.StreamGrabber.Start();
// Start the timeout timer.
Console.WriteLine( "Please disconnect the device. (Timeout {0}s)", cTimeOutMs / 1000.0 );
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
// Grab and display images until timeout.
while (camera.StreamGrabber.IsGrabbing && stopWatch.ElapsedMilliseconds < cTimeOutMs)
{
try
{
// Wait for an image and then retrieve it. A timeout of 10000 ms is used.
IGrabResult grabResult = camera.StreamGrabber.RetrieveResult(10000, TimeoutHandling.ThrowException);
using (grabResult)
{
// Image grabbed successfully?
if (grabResult.GrabSucceeded)
{
// Display the grabbed image.
ImageWindow.DisplayImage( 0, grabResult );
}
}
}
catch (Exception)
{
// An exception occurred. Is it because the camera device has been physically removed?
// Known issue: Wait until the system safely detects a possible removal.
System.Threading.Thread.Sleep( 1000 );
if (!camera.IsConnected)
{
// Yes, the camera device has been physically removed.
Console.WriteLine( "The camera device has been removed. Please reconnect. (Timeout {0}s)", cTimeOutMs / 1000.0 );
// Close the camera object to close underlying resources used for the previous connection.
camera.Close();
// Try to re-establish a connection to the camera device until timeout.
// Reopening the camera triggers the above registered Configuration.AcquireContinuous.
// Therefore, the camera is parameterized correctly again.
camera.Open( cTimeOutMs, TimeoutHandling.ThrowException );
// Due to unplugging the camera, settings have changed, e.g. the heartbeat timeout value for GigE cameras.
// After the camera has been reconnected, all settings must be restored. This can be done in the CameraOpened
// event as shown for the Configuration.AcquireContinuous.
camera.Parameters[PLTransportLayer.HeartbeatTimeout].TrySetValue( 1000, IntegerValueCorrection.Nearest );
// Restart grabbing.
camera.StreamGrabber.Start();
// Restart the timeout timer.
Console.WriteLine( "Camera reconnected. You may disconnect the camera device again (Timeout {0}s)", cTimeOutMs / 1000.0 );
stopWatch.Restart();
}
else
{
throw;
}
}
}
}
}
catch (Exception e)
{
Console.Error.WriteLine( "Exception: {0}", e.Message );
exitCode = 1;
}
finally
{
// Comment the following two lines to disable waiting on exit.
Console.Error.WriteLine( "\nPress enter to exit." );
Console.ReadLine();
}
Environment.Exit( exitCode );
}
}
}
Grab#
C#
/*
Note: Before getting started, Basler recommends reading the Programmer's Guide topic
in the pylon C# API documentation: https://docs.baslerweb.com/pylonapi/net/
This sample illustrates how to grab images and process images asynchronously.
This means that while the application is processing a buffer,
the acquisition of the next buffer is done in parallel.
The sample uses a pool of buffers. The buffers are automatically allocated. Once a buffer is filled
and ready for processing, the buffer is retrieved from the stream grabber as part of a grab
result. The grab result is processed and the buffer is passed back to the stream grabber by
disposing the grab result. The buffer is reused and refilled.
A buffer retrieved from the stream grabber as a grab result is not overwritten in the background
as long as the grab result is not disposed.
*/
using System;
using Basler.Pylon;
namespace Grab
{
class Grab
{
internal static void Main()
{
// The exit code of the sample application.
int exitCode = 0;
try
{
// Create a camera object that selects the first camera device found.
// More constructors are available for selecting a specific camera device.
using (Camera camera = new Camera())
{
// Print the model name of the camera.
Console.WriteLine( "Using camera {0}.", camera.CameraInfo[CameraInfoKey.ModelName] );
// Set the acquisition mode to free running continuous acquisition when the camera is opened.
camera.CameraOpened += Configuration.AcquireContinuous;
// Open the connection to the camera device.
camera.Open();
// The parameter MaxNumBuffer can be used to control the amount of buffers
// allocated for grabbing. The default value of this parameter is 10.
camera.Parameters[PLCameraInstance.MaxNumBuffer].SetValue( 5 );
// Start grabbing.
camera.StreamGrabber.Start();
// Grab a number of images.
for (int i = 0; i < 10; ++i)
{
// Wait for an image and then retrieve it. A timeout of 5000 ms is used.
IGrabResult grabResult = camera.StreamGrabber.RetrieveResult(5000, TimeoutHandling.ThrowException);
using (grabResult)
{
// Image grabbed successfully?
if (grabResult.GrabSucceeded)
{
// Access the image data.
Console.WriteLine( "SizeX: {0}", grabResult.Width );
Console.WriteLine( "SizeY: {0}", grabResult.Height );
byte[] buffer = grabResult.PixelData as byte[];
Console.WriteLine( "Gray value of first pixel: {0}", buffer[0] );
Console.WriteLine( "" );
// Display the grabbed image.
ImageWindow.DisplayImage( 0, grabResult );
}
else
{
Console.WriteLine( "Error: {0} {1}", grabResult.ErrorCode, grabResult.ErrorDescription );
}
}
}
// Stop grabbing.
camera.StreamGrabber.Stop();
// Close the connection to the camera device.
camera.Close();
}
}
catch (Exception e)
{
Console.Error.WriteLine( "Exception: {0}", e.Message );
exitCode = 1;
}
finally
{
// Comment the following two lines to disable waiting on exit.
Console.Error.WriteLine( "\nPress enter to exit." );
Console.ReadLine();
}
Environment.Exit( exitCode );
}
}
}
VB
'This sample illustrates how to grab images and process images asynchronously.
'This means that while the application is processing a buffer,
'the acquisition of the next buffer is done in parallel.
'The sample uses a pool of buffers. The buffers are automatically allocated. Once a buffer is filled
'and ready for processing, the buffer is retrieved from the stream grabber as part of a grab
'result. The grab result is processed and the buffer is passed back to the stream grabber by
'disposing the grab result. The buffer is reused and refilled.
'A buffer retrieved from the stream grabber as a grab result is not overwritten in the background
'as long as the grab result is not disposed.
Imports Basler.Pylon
Module Grab
Public Class Grab
Shared Sub Main()
' The exit code of the sample application.
Dim exitCode As Integer = 0
Try
' Create a camera object that selects the first camera device found.
' More constructors are available for selecting a specific camera device.
Using camera As New Camera()
' Print the model name of the camera.
Console.WriteLine("Using camera {0}.", camera.CameraInfo(CameraInfoKey.ModelName))
' Set the acquisition mode to free running continuous acquisition when the camera is opened.
AddHandler camera.CameraOpened, AddressOf Configuration.AcquireContinuous
' Open the connection to the camera device.
camera.Open()
' The parameter MaxNumBuffer can be used to control the amount of buffers
' allocated for grabbing. The default value of this parameter is 10.
camera.Parameters(PLCameraInstance.MaxNumBuffer).SetValue(5)
' Start grabbing.
camera.StreamGrabber.Start()
' Grab a number of images.
Dim i As Integer = 0
For i = 1 To 10
' Wait for an image and then retrieve it. A timeout of 5000 ms is used.
Dim grabResult As IGrabResult = camera.StreamGrabber.RetrieveResult(5000, TimeoutHandling.ThrowException)
Using grabResult
' Image grabbed successfully?
If grabResult.GrabSucceeded Then
' Access the image data.
Console.WriteLine("SizeX: {0}", grabResult.Width)
Console.WriteLine("SizeY: {0}", grabResult.Height)
Dim buffer As Byte() = TryCast(grabResult.PixelData, Byte())
Console.WriteLine("Gray value of first pixel: {0}", buffer(0))
Console.WriteLine("")
' Display the grabbed image.
ImageWindow.DisplayImage(0, grabResult)
Else
Console.WriteLine("Error: {0} {1}", grabResult.ErrorCode, grabResult.ErrorDescription)
End If
End Using
Next
' Stop grabbing.
camera.StreamGrabber.Stop()
' Close the connection to the camera device.
camera.Close()
End Using
Catch e As Exception
Console.Error.WriteLine("Exception: {0}", e.Message)
exitCode = 1
Finally
' Comment the following two lines to disable waiting on exit.
Console.Error.WriteLine("Press enter to exit.")
Console.ReadLine()
End Try
Environment.Exit(exitCode)
End Sub
End Class
End Module
Grab Using Events for USB or GigE Camera#
C#
/*
Note: Before getting started, Basler recommends reading the Programmer's Guide topic
in the pylon C# API documentation: https://docs.baslerweb.com/pylonapi/net/
Basler USB3 Vision and GigE Vision cameras can send event messages. For example, when a sensor
exposure has finished, the camera can send an Exposure End event to the computer. The event
can reach the computer before the image data for the finished exposure has been
transferred completely. This sample illustrates how to get notified when camera event message data
has been received.
The event messages are retrieved automatically and processed by the Camera classes.
The information contained in event messages is exposed as parameter nodes in the camera node map
and can be accessed like "normal" camera parameters. These nodes are updated
when a camera event is received. You can register camera event handler objects that are
triggered when event data has been received.
The handler object provides access to the changed parameter but not its source (camera).
In this sample, we solve the problem with a derived camera class in combination with a handler object as member.
These mechanisms are demonstrated for the Exposure End event.
The Exposure End event carries the following information:
* EventExposureEndFrameID (USB) / ExposureEndEventFrameID (GigE): Indicates the number of the image frame that has been exposed.
* EventExposureEndTimestamp(USB) / ExposureEndEventTimestamp (GigE): Indicates the moment when the event has been generated.
This sample shows how to register event handlers that indicate the arrival of events
sent by the camera. For demonstration purposes, several different handlers are registered
for the same event.
*/
using System;
using Basler.Pylon;
namespace Grab_CameraEvents
{
class EventCamera : Camera
{
private static Version Sfnc2_0_0 = new Version(2, 0, 0);
private IntegerName exposureEndDataName;
private IntegerName exposureEndFrameID;
private IntegerName exposureEndTimestamp;
// This IntegerName can be used for GigE as well as for USB cameras.
public IntegerName ExposureEndDataName
{
get
{
return this.exposureEndDataName;
}
}
// This IntegerName selects the frame ID and can be used for GigE as well as for USB cameras.
public IntegerName ExposureEndFrameID
{
get
{
return this.exposureEndFrameID;
}
}
// This IntegerName selects the timestamp and can be used for GigE as well as for USB cameras.
public IntegerName ExposureEndTimestamp
{
get
{
return this.exposureEndTimestamp;
}
}
public EventCamera()
: base()
{
}
// Configure camera for event trigger and register exposure end event handler.
public bool Configure()
{
// In this sample, a software trigger is used to demonstrate synchronous processing of the grab results.
// If you want to react to an event as quickly as possible, you have to use Configuration.AcquireContinuous.
CameraOpened += Configuration.SoftwareTrigger;
if (Parameters[PLCameraInstance.GrabCameraEvents].IsWritable)
{
Parameters[PLCameraInstance.GrabCameraEvents].SetValue( true );
}
else
{
throw new Exception( "Can not enable GrabCameraEvents." );
}
if (base.Open( 1000, TimeoutHandling.Return ))
{
//Check if camera supports waiting for trigger ready
if (!base.CanWaitForFrameTriggerReady)
{
throw new Exception( "This sample can only be used with cameras that can be queried whether they are ready to accept the next frame trigger." );
}
// Features, e.g., 'ExposureEnd', are named according to the GenICam Standard Feature Naming Convention (SFNC).
// The SFNC defines a common set of features, their behavior, and the related parameter names.
// This ensures the interoperability of cameras from different camera vendors.
// Current Basler USB ace and all Basler ace 2 cameras models are based on SFNC version 2.0.
// Older Basler GigE cameras are based on previous SFNC versions.
// Accordingly, the behavior of these cameras and some parameters names will be different.
// The SFNC version can be used to handle differences between camera device models.
if (this.GetSfncVersion() < Sfnc2_0_0)
{
// The naming convention for ExposureEnd differs between SFNC 2.0 and previous versions.
exposureEndDataName = PLGigECamera.ExposureEndEventTimestamp;
exposureEndFrameID = PLGigECamera.ExposureEndEventFrameID;
exposureEndTimestamp = PLGigECamera.ExposureEndEventTimestamp;
}
else // For SFNC 2.0 cameras, e.g. USB3 Vision cameras
{
exposureEndDataName = PLUsbCamera.EventExposureEnd;
exposureEndFrameID = PLUsbCamera.EventExposureEndFrameID;
exposureEndTimestamp = PLUsbCamera.EventExposureEndTimestamp;
}
// Check if the device supports events.
if (Parameters[PLCamera.EventSelector].CanSetValue( PLCamera.EventSelector.ExposureEnd ) == false)
{
throw new Exception( "The device doesn't support exposure end event." );
}
// Add a callback function to receive the changed FrameID value.
Parameters[exposureEndDataName].ParameterChanged += OnEventExposureEndData;
// Enable sending of Exposure End events.
// Select the event to receive.
Parameters[PLCamera.EventSelector].SetValue( PLCamera.EventSelector.ExposureEnd );
// Enable it.
Parameters[PLCamera.EventNotification].SetValue( PLCamera.EventNotification.On );
}
return true;
}
// Event handler for exposure end. Only very short processing tasks should be performed by this method.
// Otherwise, the event notification will block the processing of images.
public void OnEventExposureEndData( Object sender, ParameterChangedEventArgs e )
{
if (Parameters[exposureEndFrameID].IsReadable && Parameters[exposureEndTimestamp].IsReadable)
{
Console.WriteLine( "OnEventExposureEndData: Camera: {0} EventArgs {1} FrameID {2} TimeStamp {3}"
, CameraInfo[CameraInfoKey.ModelName]
, e.Parameter.ToString()
, Parameters[exposureEndFrameID].ToString()
, Parameters[exposureEndTimestamp].ToString() );
}
}
}
class Grab_CameraEvent
{
internal static void Main()
{
const int c_countOfImagesToGrab = 10;
int exitCode = 0;
try
{
// Create a camera object and select the first camera device found.
using (EventCamera eventCamera = new EventCamera())
{
// Register the ExposureEnd event with the event handler member.
eventCamera.Configure();
// Register an event handler object with an anonymous method. The object is important if you want to unregister this event.
EventHandler<ParameterChangedEventArgs> handlerTimestamp = (s, e) =>
{
Console.WriteLine("Anonymous method: TimeStamp {0}", e.Parameter.ToString());
};
eventCamera.Parameters[eventCamera.ExposureEndTimestamp].ParameterChanged += handlerTimestamp;
eventCamera.StreamGrabber.Start( c_countOfImagesToGrab );
while (eventCamera.StreamGrabber.IsGrabbing)
{
if (eventCamera.WaitForFrameTriggerReady( 1000, TimeoutHandling.ThrowException ))
{
eventCamera.ExecuteSoftwareTrigger();
}
// Wait for an image and then retrieve it. A timeout of 5000 ms is used.
IGrabResult grabResult = eventCamera.StreamGrabber.RetrieveResult(5000, TimeoutHandling.ThrowException);
using (grabResult)
{
// Image grabbed successfully?
if (grabResult.GrabSucceeded)
{
ImageWindow.DisplayImage( 0, grabResult );
}
else
{
Console.WriteLine( "Error: {0} {1}", grabResult.ErrorCode, grabResult.ErrorDescription );
}
}
}
// If events are not required anymore, you should unregister the event handlers.
eventCamera.Parameters[eventCamera.ExposureEndDataName].ParameterChanged -= eventCamera.OnEventExposureEndData;
eventCamera.Parameters[eventCamera.ExposureEndTimestamp].ParameterChanged -= handlerTimestamp;
}
}
catch (Exception e)
{
Console.Error.WriteLine( "Exception: {0}", e.Message );
exitCode = 1;
}
finally
{
// Comment the following two lines to disable waiting on exit.
Console.Error.WriteLine( "\nPress enter to exit." );
Console.ReadLine();
}
Environment.Exit( exitCode );
}
}
}
Grab Chunk Image#
C#
/*
Note: Before getting started, Basler recommends reading the Programmer's Guide topic
in the pylon C# API documentation: https://docs.baslerweb.com/pylonapi/net/
Basler cameras provide chunk features. This means that the cameras can generate additional information about each image,
e.g. frame counters, time stamps, and CRC checksums. The information is appended to the image data as data "chunks".
This sample illustrates how to enable chunk features, how to grab images, and how to process the appended
data. When the camera is in chunk mode, it transfers data blocks that are partitioned into chunks. The first
chunk is always the image data. When chunk features are enabled, the image data chunk is followed by chunks
containing the information generated by the chunk features.
*/
using System;
using System.Threading;
using Basler.Pylon;
namespace Grab_ChunkImage
{
class Grab_ChunkImage
{
internal static void Main()
{
// The number of images to grab.
const int c_countOfImagesToGrab = 10;
// The exit code of the sample application.
int exitCode = 0;
try
{
// Create a camera object that selects the first camera device found.
// More constructors are available for selecting a specific camera device.
using (Camera camera = new Camera())
{
// Print the model name of the camera.
Console.WriteLine( "Using camera {0}.", camera.CameraInfo[CameraInfoKey.ModelName] );
// Set the acquisition mode to free running continuous acquisition when the camera is opened.
camera.CameraOpened += Configuration.AcquireContinuous;
// Open the connection to the camera device.
camera.Open();
// Enable the chunk mode.
if (!camera.Parameters[PLCamera.ChunkModeActive].TrySetValue( true ))
{
throw new Exception( "The camera doesn't support chunk features" );
}
// Enable time stamp chunks.
camera.Parameters[PLCamera.ChunkSelector].SetValue( PLCamera.ChunkSelector.Timestamp );
camera.Parameters[PLCamera.ChunkEnable].SetValue( true );
// Enable frame counter chunk if possible.
// Applies to cameras based on SFNC 1.x.
if (camera.Parameters[PLCamera.ChunkSelector].TrySetValue( PLCamera.ChunkSelector.Framecounter ))
{
camera.Parameters[PLCamera.ChunkEnable].SetValue( true );
}
// Enable Frame ID chunk if possible.
// Applies to cameras based on SFNC 2.0 or later.
else if (camera.Parameters[PLCamera.ChunkSelector].TrySetValue( PLCamera.ChunkSelector.FrameID ))
{
camera.Parameters[PLCamera.ChunkEnable].SetValue( true );
}
// Enable generic counters if possible (USB camera devices).
else if (camera.Parameters[PLCamera.ChunkSelector].TrySetValue( PLCamera.ChunkSelector.CounterValue ))
{
camera.Parameters[PLCamera.ChunkEnable].SetValue( true );
camera.Parameters[PLCamera.CounterSelector].SetValue( PLCamera.CounterSelector.Counter1 );
camera.Parameters[PLCamera.CounterEventSource].SetValue( PLCamera.CounterEventSource.FrameStart );
}
// Enable CRC checksum chunks.
camera.Parameters[PLCamera.ChunkSelector].SetValue( PLCamera.ChunkSelector.PayloadCRC16 );
camera.Parameters[PLCamera.ChunkEnable].SetValue( true );
// Start grabbing c_countOfImagesToGrab images.
camera.StreamGrabber.Start( c_countOfImagesToGrab );
// camera.StreamGrabber.Stop() is called automatically by the RetrieveResult() method
// when c_countOfImagesToGrab images have been retrieved.
while (camera.StreamGrabber.IsGrabbing)
{
// Wait for an image and then retrieve it. A timeout of 5000 ms is used.
IGrabResult grabResult = camera.StreamGrabber.RetrieveResult(5000, TimeoutHandling.ThrowException);
using (grabResult)
{
// Image grabbed successfully?
if (grabResult.GrabSucceeded)
{
// Display the grabbed image.
ImageWindow.DisplayImage( 0, grabResult );
// Check to see if a buffer containing chunk data has been received.
if (PayloadType.ChunkData != grabResult.PayloadTypeValue)
{
throw new Exception( "Unexpected payload type received." );
}
// Because we have enabled the CRC Checksum feature, we can check
// the integrity of the buffer.
// Note: Enabling the CRC Checksum feature is not a prerequisite for using chunks.
// Chunks can also be handled when the CRC Checksum feature is disabled.
if (grabResult.HasCRC && grabResult.CheckCRC() == false)
{
throw new Exception( "Image was damaged!" );
}
// Access the chunk data attached to the result.
// Before accessing the chunk data, you should check to see
// if the chunk is readable. If it is readable, the buffer
// contains the requested chunk data.
if (grabResult.ChunkData[PLChunkData.ChunkTimestamp].IsReadable)
{
Console.WriteLine( "ChunkData: TimeStamp = {0}", grabResult.ChunkData[PLChunkData.ChunkTimestamp] );
}
else
{
Console.WriteLine( "ChunkData: No TimeStamp" );
}
// Print the frame counter value (SFNC 1.x).
if (grabResult.ChunkData[PLChunkData.ChunkFramecounter].IsReadable)
{
Console.WriteLine( "ChunkData: FrameCounter = {0}", grabResult.ChunkData[PLChunkData.ChunkFramecounter] );
}
// Print the Frame ID value (SFNC 2.0 or later).
else if (grabResult.ChunkData[PLChunkData.ChunkFrameID].IsReadable)
{
Console.WriteLine( "ChunkData: FrameID = {0}", grabResult.ChunkData[PLChunkData.ChunkFrameID] );
}
// Print the generic counter value (USB camera devices).
else if (grabResult.ChunkData[PLChunkData.ChunkCounterSelector].TrySetValue( PLChunkData.ChunkCounterSelector.Counter1 )
&& grabResult.ChunkData[PLChunkData.ChunkCounterValue].IsReadable
)
{
Console.WriteLine( "ChunkData: FrameCounter = {0}", grabResult.ChunkData[PLChunkData.ChunkCounterValue] );
}
Console.WriteLine( "" );
}
else
{
Console.WriteLine( "Error: {0} {1}", grabResult.ErrorCode, grabResult.ErrorDescription );
}
}
}
camera.Parameters[PLCamera.ChunkModeActive].SetValue( false );
}
}
catch (Exception e)
{
Console.Error.WriteLine( "Exception: {0}", e.Message );
exitCode = 1;
}
finally
{
// Comment the following two lines to disable waiting on exit.
Console.Error.WriteLine( "\nPress enter to exit." );
Console.ReadLine();
}
Environment.Exit( exitCode );
}
}
}
Grab Multicast#
C#
/*
Note: Before getting started, Basler recommends reading the Programmer's Guide topic
in the pylon .NET API documentation: https://docs.baslerweb.com/pylonapi/net/
This sample demonstrates how to open a camera in multicast mode
and how to receive a multicast stream.
Two instances of this application must be started simultaneously on different computers.
The first application started on PC A acts as the controlling application and has full access to the GigE camera.
The second instance started on PC B opens the camera in monitor mode.
This instance is not able to control the camera but can receive multicast streams.
To get the sample running, start this application first on PC A in control mode.
After PC A has begun to receive frames, start the second instance of this
application on PC B in monitor mode.
*/
using System;
using Basler.Pylon;
namespace Grab_MultiCast
{
class GrabMultiCast
{
const UInt32 countOfImagesToGrab = 100;
// OnImageGrabbed is used to print the image information like Width, Height etc.
// Can be used to implement other functionality for image grab event.
static void OnImageGrabbed( Object sender, ImageGrabbedEventArgs e )
{
if (e.GrabResult.GrabSucceeded)
{
Console.WriteLine( "SizeX:{0}", e.GrabResult.Width );
Console.WriteLine( "SizeY:{0}", e.GrabResult.Height );
byte[] pixelData = (byte[])e.GrabResult.PixelData;
Console.WriteLine( "Gray value of first pixel:{0}", pixelData[0] );
}
else
{
Console.WriteLine( "Error Code: {0} Error Description: {1}", e.GrabResult.ErrorCode, e.GrabResult.ErrorDescription );
}
}
// This method is called if one or more images have been skipped during
// image acquisition.
static void OnImageSkipped( Object sender, ImageGrabbedEventArgs e )
{
Console.WriteLine( "OnImageSkipped Event" );
Console.WriteLine( "Number Of skipped images {0}", e.GrabResult.SkippedImageCount );
}
internal static void Main()
{
// The exit code of the sample application.
int exitCode = 0;
try
{
// Create a camera object that selects the first camera device found.
// More constructors are available for selecting a specific camera device.
// For multicast only look for GigE cameras here.
using (Camera camera = new Camera( DeviceType.GigE, CameraSelectionStrategy.FirstFound ))
{
// Print the model name of the camera.
Console.WriteLine( "Using camera {0}.", camera.CameraInfo[CameraInfoKey.ModelName] );
String deviceType = camera.CameraInfo[CameraInfoKey.DeviceType];
Console.WriteLine( "==========" );
Console.WriteLine( "{0} Camera", deviceType );
Console.WriteLine( "==========" );
camera.StreamGrabber.ImageGrabbed += OnImageGrabbed;
camera.StreamGrabber.ImageGrabbed += OnImageSkipped;
// Get the Key from the user for selecting the mode
Console.Write( "Start multicast sample in (c)ontrol or in (m)onitor mode? (c/m) " );
ConsoleKeyInfo keyPressed = Console.ReadKey();
switch (keyPressed.KeyChar)
{
// The default configuration must be removed when monitor mode is selected
// because the monitoring application is not allowed to modify any parameter settings.
case 'm':
case 'M':
// Monitor mode selected.
Console.WriteLine( "\nIn Monitor mode" );
// Set MonitorModeActive to true to act as monitor
camera.Parameters[PLCameraInstance.MonitorModeActive].SetValue( true );// Set monitor mode
// Open the camera.
camera.Open();
// Select transmission type. If the camera is already controlled by another application
// and configured for multicast, the active camera configuration can be used
// (IP Address and Port will be set automatically).
camera.Parameters[PLGigEStream.TransmissionType].TrySetValue( PLGigEStream.TransmissionType.UseCameraConfig );
// Alternatively, the stream grabber could be explicitly set to "multicast"...
// In this case, the IP Address and the IP port must also be set.
//
//camera.Parameters[PLGigEStream.TransmissionType].SetValue(PLGigEStream.TransmissionType.Multicast);
//camera.Parameters[PLGigEStream.DestinationAddr].SetValue("239.0.0.1");
//camera.Parameters[PLGigEStream.DestinationPort].SetValue(49152);
if ((camera.Parameters[PLGigEStream.DestinationAddr].GetValue() != "0.0.0.0") &&
(camera.Parameters[PLGigEStream.DestinationPort].GetValue() != 0))
{
camera.StreamGrabber.Start( countOfImagesToGrab );
}
else
{
throw new Exception( "Failed to open stream grabber (monitor mode): The acquisition is not yet started by the controlling application. Start the controlling application before starting the monitor application." );
}
break;
case 'c':
case 'C':
// Controlling mode selected.
Console.WriteLine( "\nIn Control mode" );
// Open the camera.
camera.Open();
// Set transmission type to "multicast"...
// In this case, the IP Address and the IP port must also be set.
camera.Parameters[PLGigEStream.TransmissionType].SetValue( PLGigEStream.TransmissionType.Multicast );
//camera.Parameters[PLGigEStream.DestinationAddr].SetValue("239.0.0.1");
//camera.Parameters[PLGigEStream.DestinationPort].SetValue(49152);
// Maximize the image area of interest (Image AOI).
camera.Parameters[PLGigECamera.OffsetX].TrySetValue( camera.Parameters[PLGigECamera.OffsetX].GetMinimum() );
camera.Parameters[PLGigECamera.OffsetY].TrySetValue( camera.Parameters[PLGigECamera.OffsetY].GetMinimum() );
camera.Parameters[PLGigECamera.Width].SetValue( camera.Parameters[PLGigECamera.Width].GetMaximum() );
camera.Parameters[PLGigECamera.Height].SetValue( camera.Parameters[PLGigECamera.Height].GetMaximum() );
// Set the pixel data format.
camera.Parameters[PLGigECamera.PixelFormat].SetValue( PLGigECamera.PixelFormat.Mono8 );
camera.StreamGrabber.Start();
break;
default:
throw new NotSupportedException( "Invalid mode selected." );
}
IGrabResult grabResult;
// Camera.StopGrabbing() is called automatically by the RetrieveResult() method
// when countOfImagesToGrab images have been retrieved in monitor mode
// or when a key is pressed and the camera object is destroyed.
Console.WriteLine( "Press any key to quit FrameGrabber..." );
while (!Console.KeyAvailable && camera.StreamGrabber.IsGrabbing)
{
grabResult = camera.StreamGrabber.RetrieveResult( 5000, TimeoutHandling.ThrowException );
using (grabResult)
{
// Image grabbed successfully?
if (grabResult.GrabSucceeded)
{
// Display the image
ImageWindow.DisplayImage( 1, grabResult );
// The grab result could now be processed here.
}
else
{
Console.WriteLine( "Error: {0} {1}", grabResult.ErrorCode, grabResult.ErrorDescription );
}
}
}
camera.Close();
}
}
catch (Exception e)
{
// Error handling
Console.Error.WriteLine( "\nException: {0}", e.Message );
exitCode = 1;
}
finally
{
// Comment the following two lines to disable waiting on exit.
Console.Error.WriteLine( "\nPress enter to exit." );
Console.ReadLine();
}
Environment.Exit( exitCode );
}
}
}
Grab Strategies#
C#
/*
Note: Before getting started, Basler recommends reading the Programmer's Guide topic
in the pylon .NET API documentation: https://docs.baslerweb.com/pylonapi/net/
This sample shows the use of the Instant Camera grab strategies.
*/
using System;
using Basler.Pylon;
namespace Grab_Strategies
{
class Grab_Strategies
{
// OnImageGrabbed is used to print the image information like Width, Height etc..
// Can be used to implement other functionality for image grab event.
static void OnImageGrabbed( Object sender, ImageGrabbedEventArgs e )
{
if (e.GrabResult.GrabSucceeded)
{
Console.WriteLine( "SizeX:{0}", e.GrabResult.Width );
Console.WriteLine( "SizeY:{0}", e.GrabResult.Height );
byte[] pixelData = (byte[])e.GrabResult.PixelData;
Console.WriteLine( "Gray value of first pixel:{0}", pixelData[0] );
}
else
{
Console.WriteLine( "Error Code: {0} Error Description: {1}", e.GrabResult.ErrorCode, e.GrabResult.ErrorDescription );
}
}
internal static void Main()
{
// The exit code of the sample application.
int exitCode = 0;
try
{
// Create a camera object that selects the first camera device found.
// More constructors are available for selecting a specific camera device.
using (Camera camera = new Camera())
{
// Camera event processing must be activated first, the default is off.
camera.Parameters[PLCameraInstance.GrabCameraEvents].SetValue( true );
// Change default configuration to enable software triggering.
camera.CameraOpened += Configuration.SoftwareTrigger;
// Register image grabbed event to print frame info
camera.StreamGrabber.ImageGrabbed += OnImageGrabbed;
// Print the model name of the camera.
Console.WriteLine( "Using camera {0}.", camera.CameraInfo[CameraInfoKey.ModelName] );
IGrabResult result;
int nBuffersInQueue = 0;
// Open the connection to the camera device.
camera.Open();
// The MaxNumBuffer parameter can be used to control the count of buffers
// allocated for grabbing. The default value of this parameter is 10.
camera.Parameters[PLStream.MaxNumBuffer].SetValue( 15 );
// Can the camera device be queried whether it is ready to accept the next frame trigger?
if (camera.CanWaitForFrameTriggerReady)
{
Console.WriteLine( "Grab using the GrabStrategy.OneByOne default strategy:" );
// The GrabStrategy.OneByOne strategy is used. The images are processed
// in the order of their arrival.
camera.StreamGrabber.Start( GrabStrategy.OneByOne, GrabLoop.ProvidedByUser );
// In the background, the grab engine thread retrieves the
// image data and queues the buffers into the internal output queue.
// Issue software triggers. For each call, wait up to 1000 ms until the camera is ready for triggering the next image.
for (int i = 0; i < 3; i++)
{
if (camera.WaitForFrameTriggerReady( 1000, TimeoutHandling.ThrowException ))
{
camera.ExecuteSoftwareTrigger();
}
}
// For demonstration purposes, wait for the last image to appear in the output queue.
System.Threading.Thread.Sleep( 3 * 1000 );
// Check that grab results are waiting.
if (camera.StreamGrabber.GrabResultWaitHandle.WaitOne( 0 ))
{
Console.WriteLine( "Grab results wait in the output queue." );
}
// All triggered images are still waiting in the output queue
// and are now retrieved.
// The grabbing continues in the background, e.g. when using hardware trigger mode,
// as long as the grab engine does not run out of buffers.
for (; ; )
{
result = camera.StreamGrabber.RetrieveResult( 0, TimeoutHandling.Return );
if (result != null)
{
using (result)
{
nBuffersInQueue++;
}
}
else
break;
}
Console.WriteLine( "Retrieved {0} grab results from output queue.", nBuffersInQueue );
//Stop the grabbing.
camera.StreamGrabber.Stop();
Console.WriteLine( "Grab using strategy GrabStrategy.LatestImages" );
// The GrabStrategy_LatestImages strategy is used. The images are processed
// in the order of their arrival, but only a number of the images received last
// are kept in the output queue.
// The size of the output queue can be adjusted.
// When using this strategy the OutputQueueSize parameter can be changed during grabbing.
camera.Parameters[PLCameraInstance.OutputQueueSize].SetValue( 2 );
camera.StreamGrabber.Start( GrabStrategy.LatestImages, GrabLoop.ProvidedByUser );
// Execute the software trigger, wait actively until the camera accepts the next frame trigger or until the timeout occurs.
for (int i = 0; i < 3; ++i)
{
if (camera.WaitForFrameTriggerReady( 1000, TimeoutHandling.ThrowException ))
{
camera.ExecuteSoftwareTrigger();
}
}
// Wait for all images.
System.Threading.Thread.Sleep( 3 * 1000 );
// Check whether the grab results are waiting.
if (camera.StreamGrabber.GrabResultWaitHandle.WaitOne( 0 ))
{
Console.WriteLine( "Grab results wait in the output queue." );
}
// Only the images received last are waiting in the internal output queue
// and are now retrieved.
// The grabbing continues in the background, e.g. when using the hardware trigger mode.
nBuffersInQueue = 0;
for (; ; )
{
result = camera.StreamGrabber.RetrieveResult( 0, TimeoutHandling.Return );
if (result != null)
{
using (result)
{
if (result.SkippedImageCount > 0)
{
Console.WriteLine( "Skipped {0} images.", result.SkippedImageCount );
}
nBuffersInQueue++;
}
}
else
break;
}
Console.WriteLine( "Retrieved {0} grab result from output queue.", nBuffersInQueue );
// When setting the output queue size to 1 this strategy is equivalent to the GrabStrategy_LatestImageOnly grab strategy from C++.
camera.Parameters[PLCameraInstance.OutputQueueSize].SetValue( 1 );
// When setting the output queue size to CInstantCamera::MaxNumBuffer this strategy is equivalent to GrabStrategy.OneByOne.
camera.Parameters[PLCameraInstance.OutputQueueSize].SetValue( camera.Parameters[PLStream.MaxNumBuffer].GetValue() );
//Stop the grabbing.
camera.StreamGrabber.Stop();
}
else
{
// See the documentation of Camera.CanWaitForFrameTriggerReady for more information.
Console.WriteLine( "This sample can only be used with cameras that can be queried whether they are ready to accept the next frame trigger." );
}
camera.Close();
}
}
catch (Exception e)
{
// Error handling.
Console.Error.WriteLine( "Exception: {0}", e.Message );
exitCode = 1;
}
finally
{
// Comment the following two lines to disable waiting on exit.
Console.Error.WriteLine( "\nPress enter to exit." );
Console.ReadLine();
}
Environment.Exit( exitCode );
}
}
}
Grab Using Action Command for Multiple GigE Cameras#
C#
/*
Note: Before getting started, Basler recommends reading the Programmer's Guide topic
in the pylon C# API documentation: https://docs.baslerweb.com/pylonapi/net/
This sample shows how to issue a GigE Vision action command to multiple cameras.
By using an action command, multiple cameras can be triggered at the same time
as opposed to software triggering where each camera has to be triggered individually.
To make the execution and configuration of multiple cameras easier, this sample uses the ActionCommandTrigger class.
*/
using System;
using Basler.Pylon;
using System.Collections.Generic;
namespace Grab_UsingActionCommand
{
class Grab_UsingActionCommand
{
/////////////////////////////////////////////////////////////////
// Limits the amount of cameras used for grabbing.
// It is important to manage the available bandwidth when grabbing with multiple
// cameras. This applies, for instance, if two GigE cameras are connected to the
// same network adapter via a switch.
// To avoid potential bandwidth problems, it's possible to optimize the
// transport layer using the pylon Viewer Bandwidth Manager.
const int c_maxCamerasToUse = 2;
internal static void Main()
{
int exitCode = 0;
List<Camera> cameras = new List<Camera>();
try
{
// Ask the camera finder for a list of all GigE camera devices.
// Note that this sample only works with GigE camera devices.
List<ICameraInfo> allDeviceInfos = CameraFinder.Enumerate(DeviceType.GigE);
if (allDeviceInfos.Count == 0)
{
throw new ApplicationException( "No GigE cameras present." );
}
// Open all cameras to fulfill preconditions for Configure(ICamera())
allDeviceInfos.ForEach( cameraInfo => cameras.Add( new Camera( cameraInfo ) ) );
cameras.ForEach( camera => camera.Open() );
// Prepare all cameras for action commands
ActionCommandTrigger actionCommandTrigger = new ActionCommandTrigger();
// Configure all cameras to wait for the action command. If a camera doesn't support action commands, an exception will be thrown.
actionCommandTrigger.Configure( cameras.ToArray() );
// Starts grabbing on all cameras.
// The cameras won't transmit any image data because they are configured to wait for an action command.
cameras.ForEach( camera => camera.StreamGrabber.Start() );
// Now we issue the action command to all devices without any DeviceKey, GroupKey, or GroupMask
// because Configure(ICamera()) had already set these parameters.
actionCommandTrigger.Issue();
// Retrieve images from all cameras.
foreach (Camera camera in cameras)
{
// Camera will return grab results in the order they arrive.
IGrabResult grabResult = camera.StreamGrabber.RetrieveResult(5000, TimeoutHandling.ThrowException);
using (grabResult)
{
// Image grabbed successfully?
if (grabResult.GrabSucceeded)
{
// Print the model name and the IP address of the camera.
Console.WriteLine( "Image grabbed successfully for: {0} ({1})",
camera.CameraInfo.GetValueOrDefault( CameraInfoKey.FriendlyName, null ),
camera.CameraInfo.GetValueOrDefault( CameraInfoKey.DeviceIpAddress, null ) );
}
else
{
// If a buffer hasn't been grabbed completely, the network bandwidth is possibly insufficient for transferring
// multiple images simultaneously. See note above c_maxCamerasToUse.
Console.WriteLine( "Error: {0} {1}", grabResult.ErrorCode, grabResult.ErrorDescription );
}
}
}
// To avoid overtriggering, you should call cameras[0].WaitForFrameTriggerReady
// (see Grab_UsingGrabLoopThread sample for details).
}
catch (Exception e)
{
Console.Error.WriteLine( "Exception: {0}", e.Message );
exitCode = 1;
}
finally
{
// Stop stream grabber and close all cameras.
cameras.ForEach( camera => { camera.StreamGrabber.Stop(); camera.Close(); camera.Dispose(); } );
// Comment the following two lines to disable waiting on exit.
Console.Error.WriteLine( "\nPress enter to exit." );
Console.ReadLine();
}
Environment.Exit( exitCode );
}
}
}
Grab Using Buffer Factory#
C#
/*
Note: Before getting started, Basler recommends reading the Programmer's Guide topic
in the pylon C# API documentation: https://docs.baslerweb.com/pylonapi/net/
This sample demonstrates how to use a user-provided buffer factory.
Using a buffer factory is optional and intended for advanced use cases only.
A buffer factory is only necessary if you want to grab into externally supplied buffers.
*/
using System;
using System.Runtime.InteropServices;
using Basler.Pylon;
namespace Grab_UsingBufferFactory
{
// A user-provided buffer factory.
class MyBufferFactory : IBufferFactory
{
public MyBufferFactory()
{
}
// This function will be called by pylon.NET when it needs to allocate a buffer to store image data.
// The bufferSize parameter specifies the size in bytes of the buffer to allocate. On return you must
// set the output parameters createdPinnedBuffer and createdPinnedObject. Optionally you can set
// bufferUserData. The bufferUserData can later be used to identify the buffer.
// In case the allocation fails you must throw an exception to indicate the failure.
// Note: This function may be called from different threads.
public void AllocateBuffer( long bufferSize, ref object createdPinnedObject, ref IntPtr createdPinnedBuffer, ref object bufferUserData )
{
// Allocate buffer for pixel data.
// If you already have a buffer allocated by your image processing library you can use this instead.
// In this case you must modify the delete code (see below) accordingly.
long elementSize = sizeof( ushort );
long arraySize = (bufferSize + (elementSize - 1)) / elementSize; //Round up if size does not align
// The pinned object will receive the actual allocated object (in our case the array).
// This information can be retrieved from a grab result by calling
// grabResult.PixelData;
createdPinnedObject = new ushort[(int)(arraySize)]; // ATTENTION: in .NET array indexes are always int!!!
// The pinned buffer will receive the pointer to the pinned memory location
// that will be used for image data aquisition internally.
GCHandle handle = GCHandle.Alloc( createdPinnedObject, GCHandleType.Pinned );
createdPinnedBuffer = handle.AddrOfPinnedObject();
// Here we store the GCHandle in the buffer user data to be able to free the
// buffer in FreeBuffer.
bufferUserData = handle;
Console.WriteLine( "Created buffer {0}.", createdPinnedBuffer );
}
// Frees a buffer allocated by a previous call to AllocateBuffer.
// Warning: This method can be called by different threads.
public void FreeBuffer( object createdPinnedObject, IntPtr createdPinnedBuffer, object bufferUserData )
{
if (null == bufferUserData)
{
return;
}
// We used the buffer user data to store the buffer handle.
// Now we use this buffer handle to free/unpin.
GCHandle handle = (GCHandle)bufferUserData;
if (null == handle)
{
return;
}
Console.WriteLine( "Freed buffer {0}.", handle.AddrOfPinnedObject() );
handle.Free();
}
}
class Grab_UsingBufferFactory
{
internal static void Main()
{
// The exit code of the sample application.
int exitCode = 0;
try
{
// Create a camera object that selects the first camera device found.
// More constructors are available for selecting a specific camera device.
using (Camera camera = new Camera())
{
// Print the model name of the camera.
Console.WriteLine( "Using camera {0}.", camera.CameraInfo[CameraInfoKey.ModelName] );
// Set the acquisition mode to free running continuous acquisition when the camera is opened.
camera.CameraOpened += Configuration.AcquireContinuous;
// Open the connection to the camera device.
camera.Open();
// Set buffer factory before starting the stream grabber because allocation
// happens there.
MyBufferFactory myFactory = new MyBufferFactory();
camera.StreamGrabber.BufferFactory = myFactory;
// Start grabbing.
camera.StreamGrabber.Start();
// Grab a number of images.
for (int i = 0; i < 10; ++i)
{
// Wait for an image and then retrieve it. A timeout of 5000 ms is used.
IGrabResult grabResult = camera.StreamGrabber.RetrieveResult(5000, TimeoutHandling.ThrowException);
using (grabResult)
{
// Image grabbed successfully?
if (grabResult.GrabSucceeded)
{
// Access the image data.
Console.WriteLine( "SizeX: {0}", grabResult.Width );
Console.WriteLine( "SizeY: {0}", grabResult.Height );
// Normally we would have a byte array in the pixel data.
// However we are using the buffer factory here which allocates
// ushort arrays.
ushort[] buffer = grabResult.PixelData as ushort[];
Console.WriteLine( "First value of pixel data: {0}", buffer[0] );
Console.WriteLine( "" );
// Display the grabbed image.
ImageWindow.DisplayImage( 0, grabResult );
}
else
{
Console.WriteLine( "Error: {0} {1}", grabResult.ErrorCode, grabResult.ErrorDescription );
}
}
}
// Stop grabbing.
camera.StreamGrabber.Stop();
// Close the connection to the camera device.
camera.Close();
}
}
catch (Exception e)
{
Console.Error.WriteLine( "Exception: {0}", e.Message );
exitCode = 1;
}
finally
{
// Comment the following two lines to disable waiting on exit.
Console.Error.WriteLine( "\nPress enter to exit." );
Console.ReadLine();
}
Environment.Exit( exitCode );
}
}
}
Grab Using Exposure End Event#
C#
/*
Note: Before getting started, Basler recommends reading the Programmer's Guide topic
in the pylon .NET API documentation: https://docs.baslerweb.com/pylonapi/net/
This sample shows how to use the Exposure End event to speed up image acquisition.
For example, when a sensor exposure is finished, the camera can send an Exposure End event to the computer.
The computer can receive the event before the image data of the finished exposure has been transferred completely.
This avoids unnecessary delays, e.g., when an image object moves before the related image data transfer is complete.
Note: This sample shows how to match incoming images using the PLCamera.EventExposureEndFrameID and the GrabResult.BlockID values. For ace 2 camera models, PLCamera.EventExposureEndFrameID and the GrabResult.BlockID don't contain matching values. The GrabResult.BlockID equivalent is the chunk value represented by PLCamera.ChunkSelector.FrameID. Please see the Grab_ChunkImage sample for more information about how to determine the correct chunk value to use instead of GrabResult.BlockID.
*/
using System;
using System.Collections.Generic;
using Basler.Pylon;
using System.Diagnostics;
namespace Grab_UsingExposureEndEvent
{
// Used for logging received events without outputting the information on the screen
// because outputting will change the timing.
// This class is used for demonstration purposes only.
internal class LogItem
{
private string eventType;
private long frameNumber;
private double time;
public string EventType
{
get
{
return this.eventType;
}
}
public long FrameNumber
{
get
{
return this.frameNumber;
}
}
public double Time
{
get
{
return time;
}
}
//Stores the values inside private variables.
public LogItem( string type, long frameNr )
{
eventType = type;
frameNumber = frameNr;
time = Stopwatch.GetTimestamp();
}
};
class Grab_UsingExposureEndEvent
{
private static Version sfnc2_0_0 = new Version(2, 0, 0);
private static long nextExpectedFrameNumberImage;
private static long nextExpectedFrameNumberExposureEnd;
private static long nextFrameNumberForMove;
private static bool gevCounterRules;
private static string eventNotificationOn;
private static IntegerName exposureEndEventFrameId;
// Number of images to be grabbed.
public static long countOfImagesToGrab = 50;
// Create list of log items.
public static List<LogItem> logItems = new List<LogItem>();
private static void Configure( Camera camera )
{
// Camera event processing must be enabled first. The default is off.
// The camera must be closed to do this.
if (camera.Parameters[PLCameraInstance.GrabCameraEvents].IsWritable)
{
camera.Parameters[PLCameraInstance.GrabCameraEvents].SetValue( true );
}
else
{
throw new Exception( "Can't enable GrabCameraEvents." );
}
// Open the camera to configure parameters.
camera.Open();
// Check whether the device supports events.
if (!camera.Parameters[PLCamera.EventSelector].IsWritable)
{
throw new Exception( "The device doesn't support events." );
}
// GigE cameras don't use frame ID 0.
gevCounterRules = camera.CameraInfo[CameraInfoKey.TLType] == TLType.GigE;
if (camera.GetSfncVersion() < sfnc2_0_0)
{
// On older cameras, frame IDs start at 1.
nextExpectedFrameNumberImage = 1;
nextExpectedFrameNumberExposureEnd = 1;
nextFrameNumberForMove = 1;
// The naming of the Exposure End event differs between SFNC 2.0 and previous versions.
exposureEndEventFrameId = PLCamera.ExposureEndEventFrameID;
eventNotificationOn = PLCamera.EventNotification.GenICamEvent;
// Add an event handler that notifies you when an Exposure End event is received.
// On older cameras, the parameter is called "ExposureEndEventData".
camera.Parameters["ExposureEndEventData"].ParameterChanged += delegate ( Object sender, ParameterChangedEventArgs e )
{
OnCameraEventExposureEndData( sender, e, camera );
};
}
else
{
// On current cameras (using SFNC 2.0, e.g., USB3 Vision cameras),
// frame IDs start at 0.
nextExpectedFrameNumberImage = 0;
nextExpectedFrameNumberExposureEnd = 0;
nextFrameNumberForMove = 0;
// The naming of the Exposure End event differs between SFNC 2.0 and previous versions.
exposureEndEventFrameId = PLCamera.EventExposureEndFrameID;
eventNotificationOn = PLCamera.EventNotification.On;
// Add an event handler that notifies you when an Exposure End event is received.
// On current cameras, the parameter is called "EventExposureEndData".
camera.Parameters["EventExposureEndData"].ParameterChanged += delegate ( Object sender, ParameterChangedEventArgs e )
{
OnCameraEventExposureEndData( sender, e, camera );
};
}
// Event handler for images received.
camera.StreamGrabber.ImageGrabbed += OnImageGrabbed;
// The network packet signaling an event on a GigE camera device may get lost in the network.
// The following commented parameters can be used to control the handling of lost events.
//camera.Parameters[ParametersPLGigEEventGrabber.Timeout]
//camera.Parameters[PLGigEEventGrabber.RetryCount]
// Enable the sending of Exposure End events.
// Select the event to be received.
camera.Parameters[PLCamera.EventSelector].SetValue( PLCamera.EventSelector.ExposureEnd );
camera.Parameters[PLCamera.EventNotification].SetValue( eventNotificationOn );
}
private static void Disable( Camera camera )
{
// Disable the sending of Exposure End events.
camera.Parameters[PLCamera.EventSelector].SetValue( PLCamera.EventSelector.ExposureEnd );
camera.Parameters[PLCamera.EventNotification].SetValue( PLCamera.EventNotification.Off );
}
private static long GetIncrementedFrameNumber( long frameNr )
{
frameNr++;
// GigE cameras use a 16 bit value and will wrap around earlier.
// They skip the value of 0 and continue with 1
if (gevCounterRules && unchecked((UInt16)frameNr) == 0)
{
frameNr = 1;
}
return frameNr;
}
private static void MoveImagedItemOrSensorHead()
{
// The imaged item or the sensor head can be moved now...
// The camera may not be ready yet for a trigger at this point because the sensor is still being read out.
// See the documentation of the CInstantCamera::WaitForFrameTriggerReady() method for more information.
logItems.Add( new LogItem( "Move", nextFrameNumberForMove ) );
nextFrameNumberForMove = GetIncrementedFrameNumber( nextFrameNumberForMove );
}
private static void OnCameraEventExposureEndData( Object sender, ParameterChangedEventArgs e, Camera camera )
{
// An image has been received. The block ID is equal to the frame number on GigE camera devices.
long frameNumber = 0;
if (camera.Parameters[exposureEndEventFrameId].IsReadable)
{
frameNumber = camera.Parameters[exposureEndEventFrameId].GetValue();
}
logItems.Add( new LogItem( "ExposureEndEvent", frameNumber ) );
if (GetIncrementedFrameNumber( frameNumber ) != nextExpectedFrameNumberExposureEnd)
{
// Check whether the imaged item or the sensor head can be moved.
// This will be the case if the Exposure End event has been lost or if the Exposure End event is received later than the image.
if (frameNumber == nextFrameNumberForMove)
{
MoveImagedItemOrSensorHead();
}
// Check for missing events.
if (frameNumber != nextExpectedFrameNumberExposureEnd)
{
logItems.Add( new LogItem( "An Exposure End event has been lost. Expected frame number is " + nextExpectedFrameNumberExposureEnd + " but got frame number " + frameNumber, frameNumber ) );
// Resync.
nextExpectedFrameNumberExposureEnd = frameNumber;
}
nextExpectedFrameNumberExposureEnd = GetIncrementedFrameNumber( nextExpectedFrameNumberExposureEnd );
}
}
// This handler is called when an image has been received.
private static void OnImageGrabbed( Object sender, ImageGrabbedEventArgs e )
{
// Read frame number from grab result.
long frameNumber = e.GrabResult.BlockID;
logItems.Add( new LogItem( "Image Received", frameNumber ) );
if (frameNumber == nextFrameNumberForMove)
{
MoveImagedItemOrSensorHead();
}
// Check for missing images.
if (frameNumber != nextExpectedFrameNumberImage)
{
logItems.Add( new LogItem( "An image has been lost. Expected frame number is " + nextExpectedFrameNumberExposureEnd + " but got frame number " + frameNumber, frameNumber ) );
// Resync.
nextExpectedFrameNumberImage = frameNumber;
}
nextExpectedFrameNumberImage = GetIncrementedFrameNumber( nextExpectedFrameNumberImage );
}
// This will print all the log items to console.
private static void PrintLog()
{
Console.WriteLine( "Warning. The time values printed may not be correct on older computer hardware." );
Console.WriteLine( "Time [ms] Event Frame Number" );
Console.WriteLine( "---------- ---------------- --------------" );
var ticks = new List<double>();
foreach (LogItem item in logItems)
{
ticks.Add( item.Time );
}
int i = 0;
foreach (LogItem item in logItems)
{
double time_ms = 0;
if (i > 0)
{
double newTicks = ticks[i];
double oldTicks = ticks[i - 1];
time_ms = (((newTicks - oldTicks)) * 1000 / Stopwatch.Frequency);
}
i++;
// {0,10:0.0000} Formatting the size of time_ms to 10 spaces and precision of 4.
Console.WriteLine( String.Format( "{0,10:0.0000}", time_ms ) + " {0,18} {1}", item.EventType, item.FrameNumber );
}
}
internal static void Main()
{
// The exit code of the sample application.
int exitCode = 0;
try
{
// Create a camera object that selects the first camera device found.
// More constructors are available for selecting a specific camera device.
using (Camera camera = new Camera())
{
// Print the model name of the camera.
Console.WriteLine( "Using camera {0}.", camera.CameraInfo[CameraInfoKey.ModelName] );
if (camera.CameraInfo[CameraInfoKey.ModelName].StartsWith( "a2A" ))
{
Console.WriteLine( "Note: This sample may not work as expected when used with ace 2 cameras." );
Console.WriteLine( " Please see note at the beginnging of the sample for details." );
}
// Configure the camera.
Configure( camera );
// Start grabbing of countOfImagesToGrab images.
// The camera device is operated in a default configuration that
// sets up free-running continuous acquisition.
camera.StreamGrabber.Start( countOfImagesToGrab );
IGrabResult result;
while (camera.StreamGrabber.IsGrabbing)
{
// Retrieve grab results and notify the camera event and image event handlers.
result = camera.StreamGrabber.RetrieveResult( 5000, TimeoutHandling.ThrowException );
using (result)
{
// Nothing to do here with the grab result. The grab results are handled by the registered event handlers.
}
}
// Disable events.
Disable( camera );
// Print the recorded log showing the timing of events and images.
PrintLog();
// Close the camera.
camera.Close();
}
}
catch (Exception e)
{
// Error handling.
Console.Error.WriteLine( "Exception: {0}", e.Message );
exitCode = 1;
}
finally
{
// Comment the following two lines to disable waiting on exit.
Console.Error.WriteLine( "\nPress enter to exit." );
Console.ReadLine();
}
Environment.Exit( exitCode );
}
}
}
Grab Using Grab Loop Thread#
C#
/*
Note: Before getting started, Basler recommends reading the Programmer's Guide topic
in the pylon C# API documentation: https://docs.baslerweb.com/pylonapi/net/
This sample illustrates how to grab and process images using the grab loop thread
provided by the Instant Camera class.
*/
using System;
using System.Threading;
using Basler.Pylon;
namespace Grab_UsingGrabLoopThread
{
class Grab_UsingGrabLoopThread
{
// Example of an image event handler.
static void OnImageGrabbed( Object sender, ImageGrabbedEventArgs e )
{
// The grab result is automatically disposed when the event call back returns.
// The grab result can be cloned using IGrabResult.Clone if you want to keep a copy of it (not shown in this sample).
IGrabResult grabResult = e.GrabResult;
// Image grabbed successfully?
if (grabResult.GrabSucceeded)
{
// Access the image data.
Console.WriteLine( "SizeX: {0}", grabResult.Width );
Console.WriteLine( "SizeY: {0}", grabResult.Height );
byte[] buffer = grabResult.PixelData as byte[];
Console.WriteLine( "Gray value of first pixel: {0}", buffer[0] );
Console.WriteLine( "" );
// Display the grabbed image.
ImageWindow.DisplayImage( 0, grabResult );
ImagePersistence.Save( ImageFileFormat.Bmp, "test.bmp", grabResult );
}
else
{
Console.WriteLine( "Error: {0} {1}", grabResult.ErrorCode, grabResult.ErrorDescription );
}
}
internal static void Main()
{
// The exit code of the sample application.
int exitCode = 0;
try
{
// Create a camera object that selects the first camera device found.
// More constructors are available for selecting a specific camera device.
using (Camera camera = new Camera( CameraSelectionStrategy.FirstFound ))
{
// Print the model name of the camera.
Console.WriteLine( "Using camera {0}.", camera.CameraInfo[CameraInfoKey.ModelName] );
// Set the acquisition mode to software triggered continuous acquisition when the camera is opened.
camera.CameraOpened += Configuration.SoftwareTrigger;
//Open the connection to the camera device.
camera.Open();
//Check if camera supports waiting for trigger ready
if (camera.CanWaitForFrameTriggerReady)
{
// Set a handler for processing the images.
camera.StreamGrabber.ImageGrabbed += OnImageGrabbed;
// Start grabbing using the grab loop thread. This is done by setting the grabLoopType parameter
// to GrabLoop.ProvidedByStreamGrabber. The grab results are delivered to the image event handler OnImageGrabbed.
// The default grab strategy (GrabStrategy_OneByOne) is used.
camera.StreamGrabber.Start( GrabStrategy.OneByOne, GrabLoop.ProvidedByStreamGrabber );
// Wait for user input to trigger the camera or exit the loop.
// Software triggering is used to trigger the camera device.
Char key;
do
{
Console.WriteLine( "Press 't' to trigger the camera or 'e' to exit." );
key = Console.ReadKey( true ).KeyChar;
if ((key == 't' || key == 'T'))
{
// Execute the software trigger. Wait up to 1000 ms until the camera is ready for trigger.
if (camera.WaitForFrameTriggerReady( 1000, TimeoutHandling.ThrowException ))
{
camera.ExecuteSoftwareTrigger();
}
}
}
while ((key != 'e') && (key != 'E'));
// Stop grabbing.
camera.StreamGrabber.Stop();
}
else
{
Console.WriteLine( "This sample can only be used with cameras that can be queried whether they are ready to accept the next frame trigger." );
}
// Close the connection to the camera device.
camera.Close();
}
}
catch (Exception e)
{
Console.Error.WriteLine( "Exception: {0}", e.Message );
exitCode = 1;
}
finally
{
// Comment the following two lines to disable waiting on exit.
Console.Error.WriteLine( "\nPress enter to exit." );
Console.ReadLine();
}
Environment.Exit( exitCode );
}
}
}
Grab Using Sequencer#
C#
/*
Note: Before getting started, Basler recommends reading the Programmer's Guide topic
in the pylon .NET API documentation: https://docs.baslerweb.com/pylonapi/net/
This sample shows how to grab images using the sequencer feature of a camera.
Three sequence sets are used for image acquisition. Each sequence set
uses a different image height.
*/
using System;
using Basler.Pylon;
namespace Grab_UsingSequencer
{
class Grab_UsingSequencer
{
private static Version sfnc2_0_0 = new Version(2, 0, 0);
// Number of images to be grabbed.
private static UInt32 countOfImagesToGrab = 10;
// OnImageGrabbed is used to print the image information like Width, Height etc..
// Can be used to implement other functionality for image grab event.
private static void OnImageGrabbed( Object sender, ImageGrabbedEventArgs e )
{
if (e.GrabResult.GrabSucceeded)
{
Console.WriteLine( "SizeX:{0}", e.GrabResult.Width );
Console.WriteLine( "SizeY:{0}", e.GrabResult.Height );
byte[] pixelData = (byte[])e.GrabResult.PixelData;
Console.WriteLine( "Gray value of first pixel:{0}", pixelData[0] );
}
else
{
Console.WriteLine( "Error Code: {0} Error Description: {1}", e.GrabResult.ErrorCode, e.GrabResult.ErrorDescription );
}
}
internal static void Main()
{
// The exit code of the sample application.
int exitCode = 0;
try
{
// Create a camera object selecting the first camera device found.
// More constructors are available for selecting a specific camera device.
using (Camera camera = new Camera())
{
// Change default configuration to enable software triggering.
camera.CameraOpened += Configuration.SoftwareTrigger;
// Open the camera.
camera.Open();
// Register image grabbed event to print frame info
camera.StreamGrabber.ImageGrabbed += OnImageGrabbed;
// DeviceVendorName, DeviceModelName, and DeviceFirmwareVersion are string parameters.
Console.WriteLine( "Camera Device Information" );
Console.WriteLine( "=========================" );
Console.WriteLine( "Vendor : {0}", camera.Parameters[PLCamera.DeviceVendorName].GetValue() );
Console.WriteLine( "Model : {0}", camera.Parameters[PLCamera.DeviceModelName].GetValue() );
Console.WriteLine( "Firmware version : {0}", camera.Parameters[PLCamera.DeviceFirmwareVersion].GetValue() );
Console.WriteLine( "" );
Console.WriteLine( "Camera Device Settings" );
Console.WriteLine( "======================" );
// Can the camera device be queried whether it is ready to accept the next frame trigger?
if (camera.CanWaitForFrameTriggerReady)
{
// bool for testing if sequencer is available or not
bool sequencerAvailable = false;
if (camera.GetSfncVersion() < sfnc2_0_0) // Handling for older cameras
{
if (camera.Parameters[PLCamera.SequenceEnable].IsWritable)
{
sequencerAvailable = true; //Sequencer is available that is why it is true.
// Disable the sequencer before changing parameters.
// The parameters under control of the sequencer are locked
// when the sequencer is enabled. For a list of parameters
// controlled by the sequencer, see the Basler Product Documentation or the camera user's manual.
camera.Parameters[PLCamera.SequenceEnable].SetValue( false );
camera.Parameters[PLCamera.SequenceConfigurationMode].TrySetValue(PLCamera.SequenceConfigurationMode.Off);
// Maximize the image area of interest (Image AOI).
camera.Parameters[PLCamera.OffsetX].TrySetValue( camera.Parameters[PLCamera.OffsetX].GetMinimum() );
camera.Parameters[PLCamera.OffsetY].TrySetValue( camera.Parameters[PLCamera.OffsetY].GetMinimum() );
camera.Parameters[PLCamera.Width].SetValue( camera.Parameters[PLCamera.Width].GetMaximum() );
camera.Parameters[PLCamera.Height].SetValue( camera.Parameters[PLCamera.Height].GetMaximum() );
// Set the pixel data format.
// This parameter may be locked when the sequencer is enabled.
camera.Parameters[PLCamera.PixelFormat].SetValue( PLCamera.PixelFormat.Mono8 );
// Set up sequence sets.
// Turn configuration mode on
camera.Parameters[PLCamera.SequenceConfigurationMode].TrySetValue(PLCamera.SequenceConfigurationMode.On);
// Configure how the sequence will advance.
// 'Auto' refers to the auto sequence advance mode.
// The advance from one sequence set to the next will occur automatically with each image acquired.
// After the end of the sequence set cycle was reached a new sequence set cycle will start.
camera.Parameters[PLCamera.SequenceAdvanceMode].SetValue( PLCamera.SequenceAdvanceMode.Auto );
// Our sequence sets relate to three steps (0..2).
// In each step we will increase the height of the Image AOI by one increment.
camera.Parameters[PLCamera.SequenceSetTotalNumber].SetValue( 3 );
long increments = (camera.Parameters[PLCamera.Height].GetMaximum() - camera.Parameters[PLCamera.Height].GetMinimum()) / camera.Parameters[PLCamera.Height].GetIncrement();
// Set the parameters for step 0; quarter height image.
camera.Parameters[PLCamera.SequenceSetIndex].SetValue( 0 );
camera.Parameters[PLCamera.Height].SetValue( camera.Parameters[PLCamera.Height].GetIncrement() * (increments / 4) + camera.Parameters[PLCamera.Height].GetMinimum() );
camera.Parameters[PLCamera.SequenceSetStore].Execute();
// Set the parameters for step 1; half height image.
camera.Parameters[PLCamera.SequenceSetIndex].SetValue( 1 );
camera.Parameters[PLCamera.Height].SetValue( camera.Parameters[PLCamera.Height].GetIncrement() * (increments / 2) + camera.Parameters[PLCamera.Height].GetMinimum() );
camera.Parameters[PLCamera.SequenceSetStore].Execute();
// Set the parameters for step 2; full height image.
camera.Parameters[PLCamera.SequenceSetIndex].SetValue( 2 );
camera.Parameters[PLCamera.Height].SetValue( camera.Parameters[PLCamera.Height].GetIncrement() * (increments) + camera.Parameters[PLCamera.Height].GetMinimum() );
camera.Parameters[PLCamera.SequenceSetStore].Execute();
// Finish configuration
if (camera.Parameters[PLCamera.SequenceConfigurationMode].IsWritable)
{
camera.Parameters[PLCamera.SequenceConfigurationMode].SetValue( PLCamera.SequenceConfigurationMode.Off );
}
// Enable the sequencer feature.
// From here on you cannot change the sequencer settings anymore.
camera.Parameters[PLCamera.SequenceEnable].SetValue( true );
// Start the grabbing of countOfImagesToGrab images.
camera.StreamGrabber.Start( countOfImagesToGrab );
}
else
{
sequencerAvailable = false; // Sequencer not available
}
}
else // Handling for newer cameras (using SFNC 2.0, e.g. USB3 Vision cameras)
{
if (camera.Parameters[PLCamera.SequencerMode].IsWritable)
{
sequencerAvailable = true;
// Disable the sequencer before changing parameters.
// The parameters under control of the sequencer are locked
// when the sequencer is enabled. For a list of parameters
// controlled by the sequencer, see the Basler Product Documentation or the camera user's manual.
camera.Parameters[PLCamera.SequencerMode].SetValue( PLCamera.SequencerMode.Off );
camera.Parameters[PLCamera.SequenceConfigurationMode].TrySetValue(PLCamera.SequenceConfigurationMode.Off);
// Maximize the image area of interest (Image AOI).
camera.Parameters[PLCamera.OffsetX].TrySetValue( camera.Parameters[PLCamera.OffsetX].GetMinimum() );
camera.Parameters[PLCamera.OffsetY].TrySetValue( camera.Parameters[PLCamera.OffsetY].GetMinimum() );
camera.Parameters[PLCamera.Width].SetValue( camera.Parameters[PLCamera.Width].GetMaximum() );
camera.Parameters[PLCamera.Height].SetValue( camera.Parameters[PLCamera.Height].GetMaximum() );
// Set the pixel data format.
// This parameter may be locked when the sequencer is enabled.
camera.Parameters[PLCamera.PixelFormat].SetValue( PLCamera.PixelFormat.Mono8 );
// Turn configuration mode on if available.
// Not supported by all cameras.
camera.Parameters[PLCamera.SequencerConfigurationMode].TrySetValue( PLCamera.SequencerConfigurationMode.On );
// Configure how the sequence will advance.
// The sequence sets relate to three steps (0..2).
// In each step, the height of the Image AOI is doubled.
long increments = (camera.Parameters[PLCamera.Height].GetMaximum() - camera.Parameters[PLCamera.Height].GetMinimum()) / camera.Parameters[PLCamera.Height].GetIncrement();
long initialSet = camera.Parameters[PLCamera.SequencerSetSelector].GetMinimum();
long incSet = camera.Parameters[PLCamera.SequencerSetSelector].GetIncrement();
long curSet = initialSet;
// Set the parameters for step 0; quarter height image.
camera.Parameters[PLCamera.SequencerSetSelector].SetValue( initialSet );
{
// valid for all sets
// reset on software signal 1;
camera.Parameters[PLCamera.SequencerPathSelector].SetValue( 0 );
camera.Parameters[PLCamera.SequencerSetNext].SetValue( initialSet );
camera.Parameters[PLCamera.SequencerTriggerSource].SetValue( PLCamera.SequencerTriggerSource.SoftwareSignal1 );
// advance on Frame Start or Exposure Start( depends on camera family )
camera.Parameters[PLCamera.SequencerPathSelector].SetValue( 1 );
camera.Parameters[PLCamera.SequencerTriggerSource].SetValue( new[] { "FrameStart", "ExposureStart" } );
}
camera.Parameters[PLCamera.SequencerSetNext].SetValue( curSet + incSet );
// Set the parameters for step 0; quarter height image.
camera.Parameters[PLCamera.Height].SetValue( camera.Parameters[PLCamera.Height].GetIncrement() * (increments / 4) + camera.Parameters[PLCamera.Height].GetMinimum() );
camera.Parameters[PLCamera.SequencerSetSave].Execute();
// Set the parameters for step 1; half height image.
curSet += incSet;
camera.Parameters[PLCamera.SequencerSetSelector].SetValue( curSet );
// advance on Frame Start to next set
camera.Parameters[PLCamera.SequencerSetNext].SetValue( curSet + incSet );
camera.Parameters[PLCamera.Height].SetValue( camera.Parameters[PLCamera.Height].GetIncrement() * (increments / 2) + camera.Parameters[PLCamera.Height].GetMinimum() );
camera.Parameters[PLCamera.SequencerSetSave].Execute();
// Set the parameters for step 2; full height image.
curSet += incSet;
camera.Parameters[PLCamera.SequencerSetSelector].SetValue( curSet );
// advance on Frame End to initial set,
camera.Parameters[PLCamera.SequencerSetNext].SetValue( initialSet ); // terminates sequence definition
// full height
camera.Parameters[PLCamera.Height].SetValue( camera.Parameters[PLCamera.Height].GetIncrement() * increments + camera.Parameters[PLCamera.Height].GetMinimum() );
camera.Parameters[PLCamera.SequencerSetSave].Execute();
// Enable the sequencer feature.
// From here on you cannot change the sequencer settings anymore.
camera.Parameters[PLCamera.SequencerConfigurationMode].SetValue( PLCamera.SequencerConfigurationMode.Off );
camera.Parameters[PLCamera.SequencerMode].SetValue( PLCamera.SequencerMode.On );
// Start the grabbing of countOfImagesToGrab images.
camera.StreamGrabber.Start( countOfImagesToGrab );
}
else
{
sequencerAvailable = false; // Sequencer not available
}
}
if (sequencerAvailable)
{
IGrabResult result;
// Camera.StopGrabbing() is called automatically by the RetrieveResult() method
// when countOfImagesToGrab images have been retrieved.
while (camera.StreamGrabber.IsGrabbing)
{
// Execute the software trigger. Wait up to 1000 ms for the camera to be ready for trigger.
if (camera.WaitForFrameTriggerReady( 1000, TimeoutHandling.ThrowException ))
{
camera.ExecuteSoftwareTrigger();
// Wait for an image and then retrieve it. A timeout of 5000 ms is used.
result = camera.StreamGrabber.RetrieveResult( 5000, TimeoutHandling.ThrowException );
using (result)
{
// Image grabbed successfully?
if (result.GrabSucceeded)
{
// Display the grabbed image.
ImageWindow.DisplayImage( 1, result );
}
else
{
Console.WriteLine( "Error code:{0} Error description:{1}", result.ErrorCode, result.ErrorDescription );
}
}
}
// Wait for user input.
Console.WriteLine( "Press enter to continue." );
Console.ReadLine();
}
// Disable the sequencer.
if (camera.GetSfncVersion() < sfnc2_0_0) // Handling for older cameras
{
camera.Parameters[PLCamera.SequenceEnable].SetValue( false );
}
else // Handling for newer cameras (using SFNC 2.0, e.g. USB3 Vision cameras)
{
camera.Parameters[PLCamera.SequencerMode].SetValue( PLCamera.SequencerMode.Off );
}
camera.Parameters[PLCamera.SequenceConfigurationMode].TrySetValue(PLCamera.SequenceConfigurationMode.Off);
}
else
{
Console.WriteLine( "The sequencer feature is not available for this camera." );
}
}
else
{
Console.WriteLine( "This sample can only be used with cameras that can be queried whether they are ready to accept the next frame trigger." );
}
// Close the camera.
camera.Close();
}
}
catch (Exception e)
{
// Error handling.
Console.Error.WriteLine( "Exception: {0}", e.Message );
exitCode = 1;
}
// Comment the following two lines to disable waiting on exit.
Console.Error.WriteLine( "\nPress enter to exit." );
Console.ReadLine();
Environment.Exit( exitCode );
}
}
}
Parameterize Camera#
C#
/*
Note: Before getting started, Basler recommends reading the Programmer's Guide topic
in the pylon C# API documentation: https://docs.baslerweb.com/pylonapi/net/
For camera configuration and for accessing other parameters, the pylon API
uses the technologies defined by the GenICam standard hosted by the
European Machine Vision Association (EMVA). The GenICam specification
(http://www.GenICam.org) defines a format for camera description files.
These files describe the configuration interface of GenICam compliant cameras.
The description files are written in XML (eXtensible Markup Language) and
describe camera registers, their interdependencies, and all other
information needed to access high-level features. This includes features such as Gain,
Exposure Time, or Pixel Format. The features are accessed by means of low level
register read and write operations.
The elements of a camera description file are represented as parameter objects.
For example, a parameter object can represent a single camera
register, a camera parameter such as Gain, or a set of available parameter
values.
*/
using System;
using Basler.Pylon;
namespace ParameterizeCamera
{
class ParameterizeCamera
{
static Version sfnc2_0_0 = new Version(2, 0, 0);
internal static void Main()
{
// The exit code of the sample application.
int exitCode = 0;
try
{
// Create a camera object that selects the first camera device found.
// More constructors are available for selecting a specific camera device.
using (Camera camera = new Camera())
{
/*************************************************************************
* Accessing camera parameters *
*************************************************************************/
// Before accessing camera device parameters, the camera must be opened.
camera.Open();
// Parameters are accessed using parameter lists. Parameter lists contain a set of parameter names
// analogous to enumerations of a programming language. Here, the parameter list PLCamera is used.
// PLCamera contains a list of parameter names of all camera device types. Additional device-specific
// parameter lists are available, e.g. PLUsbCamera for USB camera devices.
// DeviceVendorName, DeviceModelName, and DeviceFirmwareVersion are string parameters.
Console.WriteLine( "Camera Device Information" );
Console.WriteLine( "=========================" );
Console.WriteLine( "Vendor : {0}", camera.Parameters[PLCamera.DeviceVendorName].GetValue() );
Console.WriteLine( "Model : {0}", camera.Parameters[PLCamera.DeviceModelName].GetValue() );
Console.WriteLine( "Firmware version : {0}", camera.Parameters[PLCamera.DeviceFirmwareVersion].GetValue() );
Console.WriteLine( "" );
Console.WriteLine( "Camera Device Settings" );
Console.WriteLine( "======================" );
// Setting the AOI. OffsetX, OffsetY, Width, and Height are integer parameters.
// On some cameras, the offsets are read-only. If they are writable, set the offsets to min.
if(camera.Parameters[PLCamera.OffsetX].TrySetToMinimum())
{
Console.WriteLine( "OffsetX : {0}", camera.Parameters[PLCamera.OffsetX].GetValue() );
}
if(camera.Parameters[PLCamera.OffsetY].TrySetToMinimum())
{
Console.WriteLine( "OffsetY : {0}", camera.Parameters[PLCamera.OffsetY].GetValue() );
}
// Some parameters have restrictions. You can use GetIncrement/GetMinimum/GetMaximum to make sure you set a valid value.
// Here, we let pylon correct the value if needed.
camera.Parameters[PLCamera.Width].SetValue( 202, IntegerValueCorrection.Nearest );
camera.Parameters[PLCamera.Height].SetValue( 101, IntegerValueCorrection.Nearest );
Console.WriteLine( "Width : {0}", camera.Parameters[PLCamera.Width].GetValue() );
Console.WriteLine( "Height : {0}", camera.Parameters[PLCamera.Height].GetValue() );
// Set an enum parameter.
string oldPixelFormat = camera.Parameters[PLCamera.PixelFormat].GetValue(); // Remember the current pixel format.
Console.WriteLine( "Old PixelFormat : {0} ({1})", camera.Parameters[PLCamera.PixelFormat].GetValue(), oldPixelFormat );
// Set pixel format to Mono8 if available.
if (camera.Parameters[PLCamera.PixelFormat].TrySetValue( PLCamera.PixelFormat.Mono8 ))
{
Console.WriteLine( "New PixelFormat : {0} ({1})", camera.Parameters[PLCamera.PixelFormat].GetValue(), oldPixelFormat );
}
// Some camera models may have auto functions enabled. To set the gain value to a specific value,
// the Gain Auto function must be disabled first (if gain auto is available).
camera.Parameters[PLCamera.GainAuto].TrySetValue( PLCamera.GainAuto.Off ); // Set GainAuto to Off if it is writable.
// Features, e.g. 'Gain', are named according to the GenICam Standard Feature Naming Convention (SFNC).
// The SFNC defines a common set of features, their behavior, and the related parameter names.
// This ensures the interoperability of cameras from different camera vendors.
// Current Basler USB ace and all Basler ace 2 cameras models are based on SFNC version 2.0.
// Older Basler GigE cameras are based on previous SFNC versions.
// Accordingly, the behavior of these cameras and some parameters names will be different.
// The SFNC version can be used to handle differences between camera device models.
if (camera.GetSfncVersion() < sfnc2_0_0) // Handling for older cameras
{
// In previous SFNC versions, GainRaw is an integer parameter.
camera.Parameters[PLCamera.GainRaw].TrySetValuePercentOfRange( 50 );
// GammaEnable is a boolean parameter.
camera.Parameters[PLCamera.GammaEnable].TrySetValue( true );
}
else // Handling for newer cameras (using SFNC 2.0, e.g. USB3 Vision cameras)
{
// In SFNC 2.0, Gain is a float parameter.
camera.Parameters[PLUsbCamera.Gain].TrySetValuePercentOfRange( 50 );
// For USB cameras, Gamma is always enabled.
}
/*************************************************************************
* Parameter access status *
*************************************************************************/
// Each parameter is either readable or writable or both.
// Depending on the camera's state, a parameter may temporarily not be readable or writable.
// For example, a parameter related to external triggering may not be available when the camera is in free run mode.
// Additionally, parameters can be read-only by default.
Console.WriteLine( "OffsetX readable : {0}", camera.Parameters[PLCamera.OffsetX].IsReadable );
Console.WriteLine( "TriggerSoftware writable: {0}", camera.Parameters[PLCamera.TriggerSoftware].IsWritable );
/*************************************************************************
* Empty parameters *
*************************************************************************/
// Camera models have different parameter sets available. For example, GammaEnable is not part of USB camera device
// parameters. If a requested parameter does not exist, an empty parameter object will be returned to simplify handling.
// Therefore, an additional existence check is not necessary.
// An empty parameter is never readable or writable.
Console.WriteLine( "GammaEnable writable : {0}", camera.Parameters[PLCamera.GammaEnable].IsWritable );
Console.WriteLine( "GammaEnable readable : {0}", camera.Parameters[PLCamera.GammaEnable].IsReadable );
Console.WriteLine( "GammaEnable empty : {0}", camera.Parameters[PLCamera.GammaEnable].IsEmpty );
/*************************************************************************
* Try or GetValueOrDefault methods *
*************************************************************************/
// Several parameters provide Try or GetValueOrDefault methods. These methods are provided because
// a parameter may not always be available, either because the camera device model does not support the parameter
// or because the parameter is temporarily disabled (due to other parameter settings).
camera.Parameters[PLCamera.GammaEnable].TrySetValue( true ); // If the GammaEnable parameter is writable, enable it.
// Toggle CenterX to change the availability of OffsetX.
// If CenterX is readable, get the value. Otherwise, return false.
bool centerXValue = camera.Parameters[PLCamera.CenterX].GetValueOrDefault(false);
Console.WriteLine( "CenterX : {0}", centerXValue );
Console.WriteLine( "OffsetX writable : {0}", camera.Parameters[PLCamera.OffsetX].IsWritable );
camera.Parameters[PLCamera.CenterX].TrySetValue( !centerXValue ); // Toggle CenterX if CenterX is writable.
Console.WriteLine( "CenterX : {0}", camera.Parameters[PLCamera.CenterX].GetValueOrDefault( false ) );
Console.WriteLine( "OffsetX writable : {0}", camera.Parameters[PLCamera.OffsetX].IsWritable );
camera.Parameters[PLCamera.CenterX].TrySetValue( centerXValue ); // Restore the value of CenterX if CenterX is writable.
// Important: The Try and the GetValueOrDefault methods are usually related to the access status (IsWritable or IsReadable) of a parameter.
// For more information, check the summary of the methods.
// There are additional methods available that provide support for setting valid values.
// Set the width and correct the value to the nearest valid increment.
camera.Parameters[PLCamera.Width].SetValue( 202, IntegerValueCorrection.Nearest );
// Set the width and correct the value to the nearest valid increment if the width parameter is readable and writable.
camera.Parameters[PLCamera.Width].TrySetValue( 202, IntegerValueCorrection.Nearest );
// One of the following pixel formats should be available:
string[] pixelFormats = new string[]
{
PLCamera.PixelFormat.BayerBG8,
PLCamera.PixelFormat.BayerRG8,
PLCamera.PixelFormat.BayerGR8,
PLCamera.PixelFormat.BayerGB8,
PLCamera.PixelFormat.Mono8
};
camera.Parameters[PLCamera.PixelFormat].SetValue( pixelFormats ); //Set the first valid pixel format in the list.
camera.Parameters[PLCamera.PixelFormat].TrySetValue( pixelFormats ); //Set the first valid pixel format in the list if PixelFormat is writable.
Console.WriteLine( "New PixelFormat : {0}", camera.Parameters[PLCamera.PixelFormat].GetValue() );
/*************************************************************************
* Optional: Accessing camera parameters without using a parameter list *
*************************************************************************/
// Accessing parameters without using a parameter list can be necessary in rare cases,
// e.g. if you want to set newly added camera parameters that are not added to a parameter list yet.
// It is recommended to use parameter lists if possible to avoid using the wrong parameter type and
// to avoid spelling errors.
// When accessing parameters, the name and the type must usually be known beforehand.
// The following syntax can be used to access any camera device parameter.
// Adjust the parameter name ("BrandNewFeature") and the parameter type (IntegerName, EnumName, FloatName, etc.)
// according to the parameter that you want to access.
camera.Parameters[(IntegerName)"BrandNewFeature"].TrySetToMaximum(); // TrySetToMaximum is called for demonstration purposes only.
// This is another alternative to access a parameter without using a parameter list
// shown for completeness only
IIntegerParameter brandNewFeature = camera.Parameters["BrandNewFeature"] as IIntegerParameter;
// brandNewFeature will be null if it is not present because it cannot be casted to IIntegerParameter
if (brandNewFeature != null)
{
brandNewFeature.TrySetToMaximum();
}
// Enumeration values are plain strings.
// Similar to the example above, the pixel format is set to Mono8, this time without using a parameter list.
if (camera.Parameters[(EnumName)"PixelFormat"].TrySetValue( "Mono8" ))
{
Console.WriteLine( "New PixelFormat : {0}", camera.Parameters[(EnumName)"PixelFormat"].GetValue() );
}
// Restore the old pixel format.
camera.Parameters[PLCamera.PixelFormat].SetValue( oldPixelFormat );
// Close the camera.
camera.Close();
}
}
catch (Exception e)
{
Console.Error.WriteLine( "Exception: {0}", e.Message );
exitCode = 1;
}
// Comment the following two lines to disable waiting on exit.
Console.Error.WriteLine( "\nPress enter to exit." );
Console.ReadLine();
Environment.Exit( exitCode );
}
}
}
VB
'For camera configuration and for accessing other parameters, the pylon API
'uses the technologies defined by the GenICam standard hosted by the
'European Machine Vision Association (EMVA). The GenICam specification
'(http://www.GenICam.org) defines a format for camera description files.
'These files describe the configuration interface of GenICam compliant cameras.
'The description files are written in XML (eXtensible Markup Language) and
'describe camera registers, their interdependencies, and all other
'information needed to access high-level features. This includes features such as Gain,
'Exposure Time, or Pixel Format. The features are accessed by means of low level
'register read and write operations.
'The elements of a camera description file are represented as parameter objects.
'For example, a parameter object can represent a single camera
'register, a camera parameter such as Gain, or a set of available parameter
'values.
Imports Basler.Pylon
Public Class ParameterizeCamera
Shared Sfnc2_0_0 As New Version(2, 0, 0)
Shared Sub Main()
' The exit code of the sample application.
Dim exitCode As Integer = 0
Try
' Create a camera object that selects the first camera device found.
' More constructors are available for selecting a specific camera device.
Using camera As New Camera()
'************************************************************************
'* Accessing camera parameters *
'************************************************************************
' Before accessing camera device parameters the camera must be opened.
camera.Open()
' Parameters are accessed using parameter lists. Parameter lists contain a set of parameter names
' analogous to enumerations of a programming language. Here the parameter list PLCamera is used.
' PLCamera contains a list of parameter names of all camera device types. Additional device-specific
' parameter lists are available, e.g. PLUsbCamera for USB camera devices.
' DeviceVendorName, DeviceModelName, and DeviceFirmwareVersion are string parameters.
Console.WriteLine("Camera Device Information")
Console.WriteLine("=========================")
Console.WriteLine("Vendor : {0}", camera.Parameters(PLCamera.DeviceVendorName).GetValue())
Console.WriteLine("Model : {0}", camera.Parameters(PLCamera.DeviceModelName).GetValue())
Console.WriteLine("Firmware version : {0}", camera.Parameters(PLCamera.DeviceFirmwareVersion).GetValue())
Console.WriteLine("")
Console.WriteLine("Camera Device Settings")
Console.WriteLine("======================")
' Setting the AOI. OffsetX, OffsetY, Width, and Height are integer parameters.
' On some cameras, the offsets are read-only. If they are writable, set the offsets to min.
camera.Parameters(PLCamera.OffsetX).TrySetToMinimum()
camera.Parameters(PLCamera.OffsetY).TrySetToMinimum()
' Some parameters have restrictions. You can use GetIncrement/GetMinimum/GetMaximum to make sure you set a valid value.
' Here, we let pylon correct the value if needed.
camera.Parameters(PLCamera.Width).SetValue(202, IntegerValueCorrection.Nearest)
camera.Parameters(PLCamera.Height).SetValue(101, IntegerValueCorrection.Nearest)
If camera.Parameters(PLCamera.OffsetX).IsReadable Then
Console.WriteLine("OffsetX : {0}", camera.Parameters(PLCamera.OffsetX).GetValue())
End If
If camera.Parameters(PLCamera.OffsetY).IsReadable Then
Console.WriteLine("OffsetY : {0}", camera.Parameters(PLCamera.OffsetY).GetValue())
End If
Console.WriteLine("Width : {0}", camera.Parameters(PLCamera.Width).GetValue())
Console.WriteLine("Height : {0}", camera.Parameters(PLCamera.Height).GetValue())
' Set an enum parameter.
Dim oldPixelFormat As String = camera.Parameters(PLCamera.PixelFormat).GetValue()
' Remember the current pixel format.
Console.WriteLine("Old PixelFormat : {0} ({1})", camera.Parameters(PLCamera.PixelFormat).GetValue(), oldPixelFormat)
' Set pixel format to Mono8 if available.
If camera.Parameters(PLCamera.PixelFormat).TrySetValue(PLCamera.PixelFormat.Mono8) Then
Console.WriteLine("New PixelFormat : {0} ({1})", camera.Parameters(PLCamera.PixelFormat).GetValue(), oldPixelFormat)
End If
' Some camera models may have auto functions enabled. To set the gain value to a specific value,
' the Gain Auto function must be disabled first (if gain auto is available).
camera.Parameters(PLCamera.GainAuto).TrySetValue(PLCamera.GainAuto.Off) ' Set GainAuto to Off if it is writable.
' Features, e.g. 'Gain', are named according to the GenICam Standard Feature Naming Convention (SFNC).
' The SFNC defines a common set of features, their behavior, and the related parameter names.
' This ensures the interoperability of cameras from different camera vendors.
' Cameras compliant with the USB3 Vision standard are based on the SFNC version 2.0.
' Current Basler USB ace and all Basler ace 2 cameras models are based on SFNC version 2.0.
' Older Basler GigE cameras are based on previous SFNC versions.
' The SFNC version can be used to handle differences between camera device models.
If camera.GetSfncVersion() < Sfnc2_0_0 Then
' In previous SFNC versions, GainRaw is an integer parameter.
camera.Parameters(PLCamera.GainRaw).TrySetValuePercentOfRange(50)
' GammaEnable is a boolean parameter.
camera.Parameters(PLCamera.GammaEnable).TrySetValue(True)
Else
' For SFNC 2.0 cameras, e.g. USB3 Vision cameras
' In SFNC 2.0, Gain is a float parameter.
' For USB cameras, Gamma is always enabled.
camera.Parameters(PLUsbCamera.Gain).TrySetValuePercentOfRange(50)
End If
'************************************************************************
'* Parameter access status *
'************************************************************************
' Each parameter is either readable or writable or both.
' Depending on the camera's state, a parameter may temporarily not be readable or writable.
' For example, a parameter related to external triggering may not be available when the camera is in free run mode.
' Additionally, parameters can be read-only by default.
Console.WriteLine("OffsetX readable : {0}", camera.Parameters(PLCamera.OffsetX).IsReadable)
Console.WriteLine("TriggerSoftware writable: {0}", camera.Parameters(PLCamera.TriggerSoftware).IsWritable)
'************************************************************************
'* Empty parameters *
'************************************************************************
' Camera models have different parameter sets available. For example, GammaEnable is not part of USB camera device
' parameters. If a requested parameter does not exist, an empty parameter object will be returned to simplify handling.
' Therefore, an additional existence check is not necessary.
' An empty parameter is never readable or writable.
Console.WriteLine("GammaEnable writable : {0}", camera.Parameters(PLCamera.GammaEnable).IsWritable)
Console.WriteLine("GammaEnable readable : {0}", camera.Parameters(PLCamera.GammaEnable).IsReadable)
Console.WriteLine("GammaEnable empty : {0}", camera.Parameters(PLCamera.GammaEnable).IsEmpty)
'************************************************************************
'* Try or GetValueOrDefaultmethods *
'************************************************************************
' Several parameters provide Try or GetValueOrDefault methods. These methods are provided because
' a parameter may not always be available, either because the camera device model does not support the parameter
' or because the parameter is temporarily disabled (due to other parameter settings).
' If the GammaEnable parameter is writable, enable it.
camera.Parameters(PLCamera.GammaEnable).TrySetValue(True)
' Toggle CenterX to change the availability of OffsetX.
' If CenterX is readable, get the value. Otherwise, return false.
Dim centerXValue As Boolean = camera.Parameters(PLCamera.CenterX).GetValueOrDefault(False)
Console.WriteLine("CenterX : {0}", centerXValue)
Console.WriteLine("OffsetX writable : {0}", camera.Parameters(PLCamera.OffsetX).IsWritable)
' Toggle CenterX if CenterX is writable.
camera.Parameters(PLCamera.CenterX).TrySetValue(Not centerXValue)
Console.WriteLine("CenterX : {0}", camera.Parameters(PLCamera.CenterX).GetValueOrDefault(False))
Console.WriteLine("OffsetX writable : {0}", camera.Parameters(PLCamera.OffsetX).IsWritable)
' Restore the value of CenterX if CenterX is writable.
camera.Parameters(PLCamera.CenterX).TrySetValue(centerXValue)
' Important: The Try and the GetValueOrDefault methods are usually related to the access status (IsWritable or IsReadable) of a parameter.
' For more information, check the summary of the methods.
' There are additional methods available that provide support for setting valid values.
' Set the width and correct the value to the nearest valid increment.
camera.Parameters(PLCamera.Width).SetValue(202, IntegerValueCorrection.Nearest)
' Set the width and correct the value to the nearest valid increment if width is readable and writable
camera.Parameters(PLCamera.Width).TrySetValue(202, IntegerValueCorrection.Nearest)
' One of the following pixel formats should be available:
Dim pixelFormats As String() = New String() {PLCamera.PixelFormat.BayerBG8, PLCamera.PixelFormat.BayerRG8, PLCamera.PixelFormat.BayerGR8, PLCamera.PixelFormat.BayerGB8, PLCamera.PixelFormat.Mono8}
'Set the first valid pixel format in the list.
camera.Parameters(PLCamera.PixelFormat).SetValue(pixelFormats)
'Set the first valid pixel format in the list if PixelFormat is writable.
camera.Parameters(PLCamera.PixelFormat).TrySetValue(pixelFormats)
Console.WriteLine("New PixelFormat : {0}", camera.Parameters(PLCamera.PixelFormat).GetValue())
'************************************************************************
'* Optional: Accessing camera parameters without using a parameter list *
'************************************************************************
' Accessing parameters without using a parameter list can be necessary in rare cases,
' e.g. if you want to set newly added camera parameters that are not added to a parameter list yet.
' It is recommended to use parameter lists if possible to avoid using the wrong parameter type and
' to avoid spelling errors.
' When accessing parameters, the name and the type must usually be known beforehand.
' The following syntax can be used to access any camera device parameter.
' Adjust the parameter name ("BrandNewFeature") and the parameter type (IntegerName, EnumName, FloatName, etc.)
' according to the parameter that you want to access.
camera.Parameters(CType("BrandNewFeature", IntegerName)).TrySetToMaximum()
' This is another alternative to access a parameter without using a parameter list
' shown for completeness only
Dim brandNewFeature As IIntegerParameter = TryCast(camera.Parameters("BrandNewFeature"), IIntegerParameter)
' brandNewFeature will be Nothing if it is not present because it cannot be casted to IIntegerParameter
If brandNewFeature IsNot Nothing Then
brandNewFeature.TrySetToMaximum()
End If
' TrySetToMaximum is called for demonstration purposes only.
' Enumeration values are plain strings.
' Similar to the example above, the pixel format is set to Mono8, this time without using a parameter list.
If camera.Parameters(CType("PixelFormat", EnumName)).TrySetValue("Mono8") Then
Console.WriteLine("New PixelFormat : {0}", camera.Parameters(CType("PixelFormat", EnumName)).GetValue())
End If
' Restore the old pixel format.
camera.Parameters(PLCamera.PixelFormat).SetValue(oldPixelFormat)
' Close the camera.
camera.Close()
End Using
Catch e As Exception
Console.[Error].WriteLine("Exception: {0}", e.Message)
exitCode = 1
End Try
' Comment the following two lines to disable waiting on exit.
Console.[Error].WriteLine(vbLf & "Press enter to exit.")
Console.ReadLine()
Environment.[Exit](exitCode)
End Sub
End Class
Parameterize Camera Autofunction#
C#
/*
Note: Before getting started, Basler recommends reading the Programmer's Guide topic
in the pylon .NET API documentation: https://docs.baslerweb.com/pylonapi/net/
This sample illustrates how to use the Auto Functions feature of Basler cameras.
Features, like 'Gain', are named according to the Standard Feature Naming Convention (SFNC).
The SFNC defines a common set of features, their behavior, and the related parameter names.
This ensures the interoperability of cameras from different camera vendors.
Current Basler USB ace and all Basler ace 2 cameras models are based on SFNC version 2.0.
Older Basler GigE cameras are based on previous SFNC versions.
Accordingly, the behavior of these cameras and some parameters names will be different.
*/
using System;
using System.Collections.Generic;
using Basler.Pylon;
namespace ParameterizeCamera_AutoFunctions
{
class ParameterizeCamera_AutoFunctions
{
private static Version sfnc2_0_0 = new Version(2, 0, 0);
private static EnumName regionSelector;
private static IntegerName regionSelectorWidth, regionSelectorHeight, regionSelectorOffsetX, regionSelectorOffsetY;
private static String regionSelecto