Skip to content

Getting Started with C++

The Spinnaker C++ API provides full-featured native access to USB3 Vision and GigE Vision cameras with GenICam integration and a QuickSpin convenience layer.

Prerequisites

  • Spinnaker SDK installed (download)
  • C++ compiler (Visual Studio 2015+ on Windows, GCC on Linux, Clang on macOS)
  • A supported Teledyne camera connected via USB3 or GigE

Basic Acquisition Example

The canonical example is located at src/Acquisition/Acquisition.cpp in the SDK. Below is the essential workflow:

#include "Spinnaker.h"
using namespace Spinnaker;

int main()
{
    // Get the system singleton
    SystemPtr system = System::GetInstance();

    // Retrieve camera list
    CameraList camList = system->GetCameras();

    // Get the first camera
    CameraPtr pCam = camList.GetByIndex(0);

    // Initialize (populates GenICam nodemap)
    pCam->Init();

    // Configure acquisition mode to continuous
    pCam->AcquisitionMode.SetValue(AcquisitionMode_Continuous);

    // Begin acquiring images
    pCam->BeginAcquisition();

    // Retrieve and process images
    for (int i = 0; i < 10; i++)
    {
        ImagePtr pImage = pCam->GetNextImage(1000);

        if (!pImage->IsIncomplete())
        {
            // Process image...
            cout << "Image " << i << ": " << pImage->GetWidth()
                 << " x " << pImage->GetHeight() << endl;
        }

        // Release image back to the buffer pool
        pImage->Release();
    }

    // Clean up
    pCam->EndAcquisition();
    pCam->DeInit();
    pCam = nullptr;
    camList.Clear();
    system->ReleaseInstance();

    return 0;
}

Key Concepts

GenICam Nodemap

After calling Init(), access the camera's GenICam nodemap to configure features:

INodeMap& nodeMap = pCam->GetNodeMap();
CEnumerationPtr ptrAcquisitionMode = nodeMap.GetNode("AcquisitionMode");

Always check node availability before access:

if (IsReadable(ptrAcquisitionMode))
{
    // Safe to read
}

QuickSpin

QuickSpin provides direct property access for common parameters:

pCam->ExposureTime.SetValue(10000.0);
double exposure = pCam->ExposureTime.GetValue();

Transport Layer Device Nodemap

Device information is available before Init():

INodeMap& tlNodeMap = pCam->GetTLDeviceNodeMap();
CStringPtr ptrSerial = tlNodeMap.GetNode("DeviceSerialNumber");

Feature Snippets

Hardware Triggering

Enable trigger mode with GPIO Line 0 as the rising-edge source:

cam->TriggerMode.SetValue(TriggerModeEnums::TriggerMode_On);
cam->TriggerSource.SetValue(TriggerSourceEnums::TriggerSource_Line0);
cam->TriggerSelector.SetValue(TriggerSelectorEnums::TriggerSelector_FrameStart);
cam->TriggerActivation.SetValue(TriggerActivationEnums::TriggerActivation_RisingEdge);
CEnumerationPtr triggerMode = nodeMap.GetNode("TriggerMode");
triggerMode->SetIntValue(triggerMode->GetEntryByName("On")->GetValue());

CEnumerationPtr triggerSource = nodeMap.GetNode("TriggerSource");
triggerSource->SetIntValue(triggerSource->GetEntryByName("Line0")->GetValue());

CEnumerationPtr triggerSelector = nodeMap.GetNode("TriggerSelector");
triggerSelector->SetIntValue(triggerSelector->GetEntryByName("FrameStart")->GetValue());

CEnumerationPtr triggerActivation = nodeMap.GetNode("TriggerActivation");
triggerActivation->SetIntValue(triggerActivation->GetEntryByName("RisingEdge")->GetValue());

See also: src/Trigger/Trigger.cpp

Setting Exposure Time

ExposureTime is the duration the electronic shutter stays open. Disable auto-exposure first:

// QuickSpin
cam->ExposureAuto.SetValue(ExposureAutoEnums::ExposureAuto_Off);
cam->ExposureTime.SetValue(20000.0f);  // microseconds (20 ms)

See also: src/Exposure/Exposure.cpp

Setting Black Level

BlackLevel is the GenICam feature that represents the DC offset applied to the video signal (known as Brightness in FlyCapture2):

// QuickSpin
cam->BlackLevelSelector.SetValue(BlackLevelSelectorEnums::BlackLevelSelector_All);
cam->BlackLevel.SetValue(1.5f);  // 1.5%

// GenICam
CEnumerationPtr ptrBlackLevelSelector = nodeMap.GetNode("BlackLevelSelector");
ptrBlackLevelSelector->SetIntValue(
    ptrBlackLevelSelector->GetEntryByName("All")->GetValue());
CFloatPtr ptrBlackLevel = nodeMap.GetNode("BlackLevel");
ptrBlackLevel->SetValue(1.5);

Setting Gain

// QuickSpin
cam->GainAuto.SetValue(GainAutoEnums::GainAuto_Off);
cam->Gain.SetValue(0.0f);  // dB

Setting Gamma

// QuickSpin
cam->GammaEnable.SetValue(true);
cam->Gamma.SetValue(0.8f);

Setting White Balance

// QuickSpin
cam->BalanceWhiteAuto.SetValue(BalanceWhiteAutoEnums::BalanceWhiteAuto_Off);
cam->BalanceRatioSelector.SetValue(BalanceRatioSelectorEnums::BalanceRatioSelector_Red);
cam->BalanceRatio.SetValue(1.5f);

Software Buffers

Control the number of image buffers allocated for acquisition:

// GenICam — TL Stream nodemap
INodeMap& sNodeMap = cam->GetTLStreamNodeMap();
CIntegerPtr ptrBufferCount = sNodeMap.GetNode("StreamDefaultBufferCount");
ptrBufferCount->SetValue(10);

Accessing Raw Bayer Data

Raw pixel data is accessible via GetData(). In 8-bit Bayer modes (e.g., BayerRG8) each byte represents one pixel. The top-left corner is row 0, column 0:

// Assuming 640x480 BayerRG8 — pixel layout is RGGB
ImagePtr pResultImage = cam->GetNextImage();
char* data = (char*)pResultImage->GetData();

// data[0]   = Row 0, Column 0 → red (R)
// data[1]   = Row 0, Column 1 → green (G)
// data[640] = Row 1, Column 0 → green (G)
// data[641] = Row 1, Column 1 → blue (B)

The current pixel format (PixelFormat) and PixelColorFilter indicate the Bayer tile mapping for the connected camera.

Grabbing Images

cam->BeginAcquisition();

ImagePtr pResultImage = cam->GetNextImage(1000);  // 1 s timeout

// Check for incomplete frames
ImageStatus imageStatus = pResultImage->GetImageStatus();
if (pResultImage->IsIncomplete())
{
    // imageStatus gives the specific reason
}

pResultImage->Release();  // always release back to the buffer pool

cam->EndAcquisition();

ImageStatus values: IMAGE_NO_ERROR, IMAGE_CRC_CHECK_FAILED, IMAGE_MISSING_PACKETS, IMAGE_DATA_INCOMPLETE, and others.

Loading and Saving Images

// Save acquired image
pResultImage->Save("image.jpg");

// Load a raw image from disk
int width = 1280, height = 1024;
unsigned char* data = (unsigned char*)malloc(width * height);
FILE* f = fopen("image.raw", "rb");
fread(data, 1, width * height, f);

ImagePtr loadImage = Image::Create(width, height, 0, 0,
                                   PixelFormatEnums::PixelFormat_BayerRG8, data);
loadImage->Convert(PixelFormat_Mono8);
loadImage->Save("image_converted.jpg");

Chunk Data

Chunk data attaches metadata (frame counter, exposure time, etc.) to each image:

// Enable chunk data (QuickSpin)
cam->ChunkSelector.SetValue(ChunkSelectorEnums::ChunkSelector_ExposureTime);
cam->ChunkEnable.SetValue(true);
cam->ChunkModeActive.SetValue(true);

// Retrieve after acquisition
const ChunkData& chunkData = rawImage->GetChunkData();
float64_t exposureTime = chunkData.GetExposureTime();

See also: src/ChunkData/ChunkData.cpp

Event Handling

Spinnaker provides interface events (device arrival/removal) and device events (e.g., exposure end):

// Interface event — camera arrival and removal
class InterfaceEventsHandler : public InterfaceEvent
{
public:
    void OnDeviceArrival()
    {
        std::cout << "A camera arrived" << std::endl;
    }
    void OnDeviceRemoval(uint64_t deviceSerialNumber)
    {
        std::cout << "Camera removed: " << deviceSerialNumber << std::endl;
    }
};

InterfaceEventsHandler handler;
cam->RegisterEvent(handler);
// Device event — exposure end
CEnumerationPtr pEnum = nodeMap.GetNode("EventSelector");
pEnum->SetIntValue(pEnum->GetEntryByName("EventExposureEnd")->GetValue());

CEnumerationPtr pBool = nodeMap.GetNode("EventNotification");
pBool->SetIntValue(1);

class DeviceEventHandler : public DeviceEvent
{
public:
    void OnDeviceEvent(GenICam::gcstring eventName)
    {
        std::cout << "Device event: " << eventName
                  << " ID=" << GetDeviceEventId() << std::endl;
    }
};

DeviceEventHandler devHandler;
cam->RegisterEvent(devHandler);

See also: src/NodeMapCallback/NodeMapCallback.cpp, src/DeviceEvents/DeviceEvents.cpp

Error Handling

try
{
    cam.Init();
}
catch (Spinnaker::Exception& e)
{
    std::cout << "Error: " << e.what() << std::endl;
}

Logging

Spinnaker supports five log levels: Error, Warn, Notice, Info, Debug. Register a logging callback on the system object:

class LogCallback : Spinnaker::LoggingEvent
{
    void OnLogEvent(LoggingEventDataPtr loggingEventDataPtr)
    {
        // handle log event
    }
};

SystemPtr system = System::GetInstance();
LogCallback callBackClass;
system->RegisterLoggingEvent((Spinnaker::LoggingEvent&)callBackClass);
system->SetLoggingEventPriorityLevel(LOG_LEVEL_DEBUG);

Logs are saved to C:\ProgramData\Spinnaker\Logs. See also: src/Logging/Logging.cpp


Design Conventions

Resource Management

The C++ API uses reference-counted smart pointers (SystemPtr, CameraPtr, ImagePtr). Resources are released automatically when the last pointer goes out of scope — no explicit delete is required:

SystemPtr system = System::GetInstance();
CameraList camList = system->GetCameras();
CameraPtr pCam = camList.GetByIndex(0);
pCam->Init();

// ... configure and acquire ...

pCam->DeInit();
camList.Clear();
// system released when 'system' goes out of scope

Acquire → DeInit → Clear order

Always call DeInit() on each camera and Clear() on the camera list before the SystemPtr goes out of scope. Releasing the system while cameras are still initialized results in exception thrown.

QuickSpin

QuickSpin provides direct typed property access on the camera object, avoiding verbose node map lookups. It wraps the same underlying GenICam nodes:

// GenICam node map access (verbose)
INodeMap& nodeMap = pCam->GetNodeMap();
CEnumerationPtr pExposureAuto = nodeMap.GetNode("ExposureAuto");
pExposureAuto->SetIntValue(pExposureAuto->GetEntryByName("Off")->GetValue());

// QuickSpin equivalent (preferred for standard parameters)
pCam->ExposureAuto.SetValue(ExposureAuto_Off);
pCam->ExposureTime.SetValue(5000.0f);  // microseconds

Error Handling

The C++ API throws Spinnaker::Exception on failure. Wrap acquisition and configuration code in try/catch blocks:

try
{
    pCam->BeginAcquisition();
}
catch (Spinnaker::Exception& e)
{
    std::cout << "Error: " << e.what() << std::endl;
}

Quick Reference

System & Discovery

Class / Method Description
System::GetInstance() Obtain the system singleton
System::ReleaseInstance() Release the system singleton
System::GetCameras() Enumerate connected cameras
System::GetLibraryVersion() Query SDK version at runtime

Camera Lifecycle

Class / Method Description
CameraList List of detected cameras
CameraPtr Camera object for configuration and acquisition
Camera::Init() Initialize the camera and populate node map
Camera::DeInit() De-initialize the camera
Camera::BeginAcquisition() Start image acquisition
Camera::EndAcquisition() Stop image acquisition

Image Handling

Class / Method Description
ImagePtr Captured image with pixel data access
Image::IsIncomplete() Check for dropped or incomplete frame
Image::GetData() Access raw pixel buffer
Image::GetWidth() / GetHeight() Image dimensions in pixels
Image::GetPixelFormat() Current pixel format
Image::Release() Return image to acquisition buffer pool
ImageProcessor Image format conversion utility
ImageProcessor::Convert() Convert to a different pixel format

Node Map & Configuration

Class / Method Description
Camera::GetNodeMap() Access GenICam node map (requires Init())
Camera::GetTLDeviceNodeMap() Transport layer device node map (pre-Init())
Camera::GetTLStreamNodeMap() Transport layer stream node map
INodeMap::GetNode(name) Retrieve a node by name
CIntegerPtr Integer node accessor
CFloatPtr Float node accessor
CEnumerationPtr Enumeration node accessor
CBooleanPtr Boolean node accessor

Events & Callbacks

Class Description
ImageEventHandler Base class for image arrival callbacks
DeviceEventHandler Base class for device-level events
LoggingEventHandler Base class for SDK log message callbacks
Camera::RegisterEventHandler() Attach an event handler to a camera
Camera::UnregisterEventHandler() Detach an event handler

Exception Reference

The C++ API signals all errors by throwing Spinnaker::Exception. The exception carries the original error code, a human-readable message, and the source location:

Member Description
what() Human-readable error description
GetError() Numeric error code (spinError)
GetFileName() Source file where the error originated
GetFunctionName() Function name where the error originated
GetLineNumber() Line number where the error originated
GetFullErrorMessage() Concatenated full error details

Common error codes are listed in the C API Error Code Reference.


Known Issues & Limitations

Windows-specific

ImageProcessor GPU acceleration requires DirectX 11. Falls back to CPU silently if unavailable.


Further Reading