Spinnaker SDK C++
4.3.0.189
 
 

 
Loading...
Searching...
No Matches
ImageRelay.cpp

ImageRelay.cpp shows how to setup relays for forwarding Spinnaker images from client PC to Host PC using the SpinnakerRelay library.

ImageRelay.cpp shows how to setup relays for forwarding Spinnaker images from client PC to Host PC using the SpinnakerRelay library. It relies on information provided in the Enumeration, Acquisition, and ImageEvent examples.

It can also be helpful to familiarize yourself with the ImageEvents example, as image callbacks follow the same general procedure as relayed image events, but with a few less steps.

This example creates a user-defined class, ImageEventHandlerImpl, that inherits from the Spinnaker class, ImageEventHandler. ImageEventHandlerImpl allows the user to define any properties, parameters, and the event itself while ImageEventHandler allows the child class to appropriately interface with Spinnaker Relay class.

In order to run this example, a supported RoCE connection needs to be established. For LR-Link Mellanox based adapters, install the WinOF-2 drivers: https://network.nvidia.com/products/adapter-software/ethernet/windows/winof-2/

Please leave us feedback at: https://www.surveymonkey.com/r/TDYMVAPI More source code examples at: https://github.com/Teledyne-MV/Spinnaker-Examples Need help? Check out our forum at: https://teledynevisionsolutions.zendesk.com/hc/en-us/community/topics

//=============================================================================
// Copyright (c) 2025 FLIR Integrated Imaging Solutions, Inc. All Rights Reserved.
//
// This software is the confidential and proprietary information of FLIR
// Integrated Imaging Solutions, Inc. ("Confidential Information"). You
// shall not disclose such Confidential Information and shall use it only in
// accordance with the terms of the license agreement you entered into
// with FLIR Integrated Imaging Solutions, Inc. (FLIR).
//
// FLIR MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
// SOFTWARE, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE, OR NON-INFRINGEMENT. FLIR SHALL NOT BE LIABLE FOR ANY DAMAGES
// SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
// THIS SOFTWARE OR ITS DERIVATIVES.
//=============================================================================
#include "Spinnaker.h"
#include "SpinnakerRelay.h"
#include <chrono>
#include <iomanip>
#include <iostream>
#include <string>
#include <thread>
using namespace Spinnaker;
using namespace Spinnaker::GenApi;
using namespace Spinnaker::GenICam;
using namespace Spinnaker::Relay;
using namespace std;
// Following parameters can be configured through command-line arguments.
// Use "-h" argument to see detailed usage information.
bool bReceiver = false;
bool bSender = false;
unsigned int senderPort = 8080;
unsigned int receiverPort = 8080;
bool bSourceIPSpecified = false;
unsigned int numImagesToGrab = 100;
bool saveImages = false;
uint64_t timeout = EVENT_TIMEOUT_INFINITE;
{
const std::chrono::system_clock::time_point invalid_time = std::chrono::system_clock::time_point{};
std::chrono::system_clock::time_point startTime;
std::chrono::system_clock::time_point startTimeInstance;
std::chrono::system_clock::time_point instanceFirstEvent;
std::chrono::system_clock::time_point firstEvent;
std::chrono::system_clock::time_point instanceLastEvent;
std::chrono::system_clock::time_point lastEvent;
{
startTime = startTimeInstance = std::chrono::system_clock::now();
}
void RecordImageEvent(std::chrono::system_clock::time_point imageEventTime)
{
firstEvent = firstEvent == invalid_time ? imageEventTime : firstEvent;
lastEvent = instanceLastEvent = imageEventTime;
}
{
startTimeInstance = std::chrono::system_clock::now();
}
};
{
bool isSender;
{
relay = nullptr;
isSender = false;
pCam = nullptr;
timeInfo = nullptr;
}
};
// Supported command-line arguments
const char* argPrintUsage = "-h";
const char* argStartReceiver = "-r";
const char* argStartSender = "-s";
const char* argReceiverIP = "-ri";
const char* argReceiverPort = "-rp";
const char* argSenderIP = "-si";
const char* argSenderPort = "-sp";
const char* argNumImages = "-n";
const char* argSaveImages = "-d";
const char* argTimeout = "-t";
void PrintUsage()
{
cout << "Use '" << argPrintUsage << "' to see list of supported arguments." << endl << endl;
cout << "ImageRelay [options] <ip>" << endl << endl;
cout << "Example Usage:" << endl;
cout << "\tReceiver PC (Receiving Data): ImageRelay.exe " << argStartReceiver << " " << argReceiverIP
<< " <ReceiverIP>" << endl;
cout << "\tSender PC (Sending Data): ImageRelay.exe " << argStartSender << " " << argReceiverIP << " <ReceiverIP>"
<< argSenderIP << " <SenderIP>" << endl
<< endl;
cout << "Options:" << endl;
cout << "\t" << argStartReceiver << "\t"
<< "<Starts as receiver (listen on IP:Port)>" << endl;
cout << "\t" << argStartSender << "\t"
<< "<Starts as sender (connect to receiver IP:Port)>" << endl;
cout << "\t" << argNumImages << "\t"
<< "<Optional. Number of images to transmit (default " << numImagesToGrab << ")>" << endl;
cout << "\t" << argSaveImages << "\t"
<< "<Optional. Saves grabbed images to disk>" << endl;
cout << "\t" << argTimeout << "\t"
<< "<Optional. Connection timeout in ms (default is EVENT_TIMEOUT_INFINITE for waiting indefinitely)>" << endl;
cout << "\t" << argSenderIP << "\t"
<< "<IPv4 Sender Address>" << endl;
cout << "\t" << argSenderPort << "\t"
<< "<IPv4 Sender Port (default " << senderPort << ")>" << endl;
cout << "\t" << argReceiverIP << "\t"
<< "<IPv4 Receiver Address>" << endl;
cout << "\t" << argReceiverPort << "\t"
<< "<IPv4 Receiver Port (default " << receiverPort << ")>" << endl;
}
bool ParseArguments(int argc, char* argv[])
{
cout << "*** PARSING ARGUMENTS ***" << endl << endl;
if (argc == 1)
{
return false;
}
for (int argument = 1; argument < argc; ++argument)
{
std::string arg = argv[argument];
if (arg == argPrintUsage)
{
// Print usage information
return false;
}
if (arg == argStartReceiver)
{
if (argument + 1 <= argc)
{
bReceiver = true;
}
}
if (arg == argStartSender)
{
if (argument + 1 <= argc)
{
bSender = true;
}
}
if (arg == argReceiverIP)
{
if (argument + 1 <= argc)
{
receiverIPAddress = argv[argument + 1];
argument++;
}
}
if (arg == argReceiverPort)
{
if (argument + 1 <= argc)
{
receiverPort = atoi(argv[argument + 1]);
argument++;
}
}
if (arg == argSenderIP)
{
if (argument + 1 <= argc)
{
senderIPAddress = argv[argument + 1];
argument++;
}
}
if (arg == argSenderPort)
{
if (argument + 1 <= argc)
{
senderPort = atoi(argv[argument + 1]);
argument++;
}
}
if (arg == argNumImages)
{
if (argument + 1 <= argc)
{
numImagesToGrab = atoi(argv[argument + 1]);
argument++;
}
}
if (arg == argSaveImages)
{
saveImages = true;
}
if (arg == argTimeout)
{
if (argument + 1 <= argc)
{
timeout = atoi(argv[argument + 1]);
argument++;
}
}
}
if ((bSender && bReceiver) || (!bSender && !bReceiver))
{
cout << "Exactly one of receiver (-r) or sender (-s) must be specified." << endl << endl;
return false;
}
{
cout << "Please provide source IP address with -si <ip address>" << endl;
return false;
}
if (bSender)
{
cout << "Sender IP Address: " << senderIPAddress << endl;
cout << "Sender Port: " << senderPort << endl;
}
cout << "Receiver IP Address: " << receiverIPAddress << endl;
cout << "Receiver Port: " << receiverPort << endl;
// Setup Spinnaker Relay Connection Params
if (bSender)
{
}
return true;
}
void PrintRelayStatistics(const RelayStatistics* stats, TimeInformation* timeInfo, bool printSummary = false)
{
const auto currentTime = std::chrono::system_clock::now();
if (printSummary)
{
const auto totalDuration = currentTime - timeInfo->startTime;
const auto totalDurationInMicroSeconds =
std::chrono::duration_cast<std::chrono::microseconds>(totalDuration).count();
const auto totalDurationInSeconds = static_cast<double>(totalDurationInMicroSeconds) / 1000000;
const auto activeDuration = timeInfo->lastEvent - timeInfo->firstEvent;
const auto activeDurationInMicroSeconds =
std::chrono::duration_cast<std::chrono::microseconds>(activeDuration).count();
const auto activeDurationInSeconds = static_cast<double>(activeDurationInMicroSeconds) / 1000000;
bool dataTransferred = false;
if (stats->totalRecvSuccessCount > 0 || stats->totalRecvDropCount > 0)
{
std::cout << "Transfer Duration (seconds) : " << activeDurationInSeconds << std::endl;
std::cout << "Total Duration (seconds) : " << totalDurationInSeconds << std::endl;
std::cout << "Received images : " << stats->totalRecvSuccessCount << std::endl;
std::cout << "Receive images dropped : " << stats->totalRecvDropCount << std::endl;
std::cout << "Receive image errors : " << stats->totalRecvErrorCount << std::endl;
if (activeDurationInSeconds > 1)
{
double totalRecvFrameRate = stats->totalRecvSuccessCount / activeDurationInSeconds;
double totalRecvDataRate = stats->totalRecvDataCount / activeDurationInSeconds;
std::cout << "Transfer FPS : " << totalRecvFrameRate << std::endl;
std::cout << "Transfer data rate : " << totalRecvDataRate / 1024 / 1024 << " MBps"
<< std::endl;
}
dataTransferred = true;
}
if (stats->totalSendSuccessCount > 0 || stats->totalSendDropCount > 0)
{
std::cout << "Transfer Duration (seconds) : " << activeDurationInSeconds << std::endl;
std::cout << "Total Duration (seconds) : " << totalDurationInSeconds << std::endl;
std::cout << "Sent images : " << stats->totalSendSuccessCount << std::endl;
std::cout << "Send images dropped : " << stats->totalSendDropCount << std::endl;
std::cout << "Send image errors : " << stats->totalSendErrorCount << std::endl;
if (activeDurationInSeconds > 1)
{
double totalSendFrameRate = stats->totalSendSuccessCount / activeDurationInSeconds;
double totalSendDataRate = stats->totalSendDataCount / activeDurationInSeconds;
std::cout << "Transfer FPS : " << totalSendFrameRate << std::endl;
std::cout << "Transfer data rate : " << totalSendDataRate / 1024 / 1024 << " MBps"
<< std::endl;
}
dataTransferred = true;
}
if (!dataTransferred)
{
std::cout << "Duration (seconds) : " << totalDurationInSeconds << std::endl;
std::cout << "No relay data transferred.\n";
}
}
else
{
const auto transferDuration = timeInfo->instanceLastEvent - timeInfo->instanceFirstEvent;
const auto transferDurationInMicroSeconds =
std::chrono::duration_cast<std::chrono::microseconds>(transferDuration).count();
const auto transferDurationInSeconds = static_cast<double>(transferDurationInMicroSeconds) / 1000000;
bool dataTransferred = false;
if (stats->instanceRecvSuccessCount > 0 || stats->instanceRecvDropCount > 0)
{
if (transferDurationInSeconds > 1)
{
double transferRecvFrameRate = stats->instanceRecvSuccessCount / transferDurationInSeconds;
double transferRecvDataRate = stats->instanceRecvDataCount / transferDurationInSeconds;
std::cout << "Transfer FPS: " << std::fixed << std::setprecision(3) << transferRecvFrameRate
<< "; ";
std::cout << "Transfer data Rate: " << std::fixed << std::setprecision(3) << transferRecvDataRate / 1024 / 1024
<< " MBps; ";
}
std::cout << "Received: " << stats->instanceRecvSuccessCount << "; ";
std::cout << "Drops: " << stats->instanceRecvDropCount << "; ";
std::cout << "Errors: " << stats->instanceRecvErrorCount << std::endl;
dataTransferred = true;
}
if (stats->instanceSendSuccessCount > 0 || stats->instanceSendDropCount > 0)
{
if (transferDurationInSeconds > 1)
{
double transferSendFrameRate = stats->instanceSendSuccessCount / transferDurationInSeconds;
double transferSendDataRate = stats->instanceSendDataCount / transferDurationInSeconds;
std::cout << "Transfer FPS: " << std::fixed << std::setprecision(3) << transferSendFrameRate << "; ";
std::cout << "Transfer data Rate: " << std::fixed << std::setprecision(3) << transferSendDataRate / 1024 / 1024
<< " MBps; ";
}
std::cout << "Sent: " << stats->instanceSendSuccessCount << "; ";
std::cout << "Drops: " << stats->instanceSendDropCount << "; ";
std::cout << "Errors: " << stats->instanceSendErrorCount << std::endl;
dataTransferred = true;
}
if (!dataTransferred)
{
std::cout << "No relay data transferred.\n";
}
}
}
// This class defines the properties, parameters, and the event handler itself. Take a
// moment to notice what parts of the class are mandatory, and what have been
// added for demonstration purposes. First, any class used to define image event handlers
// must inherit from ImageEventHandler. Second, the method signature of OnImageEvent()
// must also be consistent. Everything else - including the constructor,
// destructor, properties, body of OnImageEvent(), and other functions - is particular
// to the example.
{
public:
ImageEventHandlerImpl(TimeInformation* timeInformation, unsigned int maxImages, bool saveImagesToDisk = false)
{
// Initialize image counter to 0
m_imageCnt = 0;
// Initialize max image to grab
m_numImages = maxImages;
// Set flag for saving grabbed images locally
m_saveImages = saveImagesToDisk;
// Reference TimeInformation struct
timeInfo = timeInformation;
}
// The constructor retrieves the serial number and initializes the image
// counter to 0.
CameraPtr pCam, TimeInformation* timeInformation, unsigned int maxImages, bool saveImagesToDisk = false)
{
// Retrieve device serial number
INodeMap& nodeMap = pCam->GetTLDeviceNodeMap();
m_deviceSerialNumber = "";
CStringPtr ptrDeviceSerialNumber = nodeMap.GetNode("DeviceSerialNumber");
if (IsReadable(ptrDeviceSerialNumber))
{
m_deviceSerialNumber = ptrDeviceSerialNumber->GetValue();
}
// Initialize image counter to 0
m_imageCnt = 0;
// Initialize max image to grab
m_numImages = maxImages;
// Set flag for saving grabbed images locally
m_saveImages = saveImagesToDisk;
// Reference TimeInformation struct
timeInfo = timeInformation;
// Release reference to camera
pCam = nullptr;
//
// Set default image processor color processing method
//
// *** NOTES ***
// By default, if no specific color processing algorithm is set, the image
// processor will default to NEAREST_NEIGHBOR method.
//
m_processor.SetColorProcessing(SPINNAKER_COLOR_PROCESSING_ALGORITHM_HQ_LINEAR);
}
{
}
// This method defines an image event. In it, the image that triggered the
// event is converted and saved before incrementing the count. Please see
// Acquisition example for more in-depth comments on the acquisition of
// images.
void OnImageEvent(ImagePtr image)
{
const auto imageEventTime = std::chrono::system_clock::now();
// Save a maximum of m_numImages images
if (m_imageCnt < m_numImages)
{
// Check image retrieval status
if (image->IsIncomplete())
{
cout << "Image incomplete with image status " << image->GetImageStatus() << "..." << endl << endl;
}
else
{
// Print image information
// Print the first 10 frames; afterwards, print once for every 200 frames to avoid flooding the
// screen with debug messages.
const uint64_t frameID = image->GetFrameID();
if (frameID < 10 || frameID % 200 == 0)
{
cout << "Grabbed image " << m_imageCnt << ", id = " << frameID << ", width = " << image->GetWidth()
<< ", height = " << image->GetHeight() << endl;
}
if (m_saveImages)
{
// Create a unique filename and save image
ostringstream filename;
filename << "ImageRelay-";
if (m_deviceSerialNumber != "")
{
filename << m_deviceSerialNumber.c_str() << "-";
}
// Save in .si format to retain image metadata
filename << m_imageCnt << ".si";
image->Save(filename.str().c_str());
cout << "Image saved at " << filename.str() << endl << endl;
}
// Increment image counter
m_imageCnt++;
timeInfo->RecordImageEvent(imageEventTime);
}
}
}
// Getter for image counter
{
return m_imageCnt;
}
// Getter for maximum images
{
return m_numImages;
}
// Setter for maximum images
int setMaxImages(unsigned int maxImages)
{
m_numImages = maxImages;
return m_numImages;
}
private:
unsigned int m_numImages = 10;
unsigned int m_imageCnt;
bool m_saveImages = false;
string m_deviceSerialNumber;
ImageProcessor m_processor;
TimeInformation* timeInfo;
};
// This function configures the example to execute image events by preparing and
// registering an image event for specified SpinnakerRelay.
SpinnakerRelay& relay, ImageEventHandlerImpl*& imageEventHandler, TimeInformation* timeInformation, bool saveImagesToDisk)
{
int result = 0;
try
{
//
// Create image event handler
//
imageEventHandler = new ImageEventHandlerImpl(timeInformation, numImagesToGrab, saveImagesToDisk);
//
// Register image event handler
//
// *** LATER ***
// Image event handlers must be unregistered manually. This must be done prior
// to releasing the system and while the image event handlers are still in
// scope.
//
relay.RegisterEventHandler(*imageEventHandler);
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// This function configures the example to execute image events by preparing and
// registering an image event for specified Camera.
CameraPtr pCam, ImageEventHandlerImpl*& imageEventHandler, TimeInformation* timeInformation, bool saveImagesToDisk)
{
int result = 0;
try
{
//
// Create image event handler
//
// *** NOTES ***
// The class has been constructed to accept a camera pointer in order
// to allow the saving of images with the device serial number.
//
imageEventHandler = new ImageEventHandlerImpl(pCam, timeInformation, numImagesToGrab, saveImagesToDisk);
//
// Register image event handler
//
// *** NOTES ***
// Image event handlers are registered to cameras. If there are multiple
// cameras, each camera must have the image event handlers registered to it
// separately. Also, multiple image event handlers may be registered to a
// single camera.
//
// *** LATER ***
// Image event handlers must be unregistered manually. This must be done prior
// to releasing the system and while the image event handlers are still in
// scope.
//
pCam->RegisterEventHandler(*imageEventHandler);
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// This function waits for the appropriate amount of images. Notice that
// whereas most examples actively retrieve images, the acquisition of images is
// handled passively in this example.
int WaitForImages(ImageEventHandlerImpl*& imageEventHandler, SpinnakerRelay& relay)
{
int result = 0;
try
{
//
// Wait for images
//
// *** NOTES ***
// In order to passively capture images using image events and
// automatic polling, the main thread sleeps in increments of 1000 ms
// until the requested number of images have been acquired and saved.
//
const int sleepDuration = 1000; // in milliseconds
bool printConnectingMsg = true;
while (imageEventHandler->getImageCount() < imageEventHandler->getMaxImages())
{
Sleep(sleepDuration);
if (!relay.IsConnected())
{
if (relay.IsConnecting())
{
if (printConnectingMsg)
{
cout << "Relay is connecting. Please wait..." << endl;
printConnectingMsg = false;
}
}
else
{
cout << "Relay is disconnected." << endl;
break;
}
}
else
{
printConnectingMsg = true;
}
}
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// This functions resets the example by unregistering the image event handler.
int ResetImageEvents(SpinnakerRelay& relay, ImageEventHandlerImpl*& imageEventHandler)
{
int result = 0;
try
{
//
// Unregister image event handler
//
// *** NOTES ***
// It is important to unregister all image event handlers from the receivers
// they are registered to.
//
relay.UnregisterEventHandler(*imageEventHandler);
// Delete image event handler (because it is a pointer)
delete imageEventHandler;
cout << "Image events unregistered..." << endl << endl;
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// This functions resets the example by unregistering the image event handler.
int ResetImageEvents(CameraPtr pCam, ImageEventHandlerImpl*& imageEventHandler)
{
int result = 0;
try
{
//
// Unregister image event handler
//
// *** NOTES ***
// It is important to unregister all image event handlers from all cameras
// they are registered to.
//
pCam->UnregisterEventHandler(*imageEventHandler);
// Delete image event handler (because it is a pointer)
delete imageEventHandler;
cout << "Image events unregistered..." << endl << endl;
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// This function prints the device information of the camera from the transport
// layer; please see NodeMapInfo example for more in-depth comments on printing
// device information from the nodemap.
int PrintDeviceInfo(INodeMap& nodeMap)
{
int result = 0;
cout << endl << "*** DEVICE INFORMATION ***" << endl << endl;
try
{
FeatureList_t features;
CCategoryPtr category = nodeMap.GetNode("DeviceInformation");
if (IsReadable(category))
{
category->GetFeatures(features);
FeatureList_t::const_iterator it;
for (it = features.begin(); it != features.end(); ++it)
{
try
{
CNodePtr pfeatureNode = *it;
cout << pfeatureNode->GetName() << " : ";
CValuePtr pValue = (CValuePtr)pfeatureNode;
cout << (IsReadable(pValue) ? pValue->ToString() : "Node not readable");
cout << endl;
}
{
cout << "Node not readable" << endl;
}
}
}
else
{
cout << "Device control information not readable." << endl;
}
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// This function passively waits for images by calling WaitForImages(). Notice that
// this function is much shorter than the AcquireImages() function of other examples.
// This is because most of the code has been moved to the image event's OnImageEvent()
// method.
CameraPtr pCam,
INodeMap& nodeMap,
INodeMap& nodeMapTLDevice,
ImageEventHandlerImpl*& imageEventHandler)
{
int result = 0;
cout << endl << endl << "*** IMAGE ACQUISITION ***" << endl << endl;
try
{
// Set acquisition mode to continuous
CEnumerationPtr ptrAcquisitionMode = nodeMap.GetNode("AcquisitionMode");
if (!IsReadable(ptrAcquisitionMode) || !IsWritable(ptrAcquisitionMode))
{
cout << "Unable to get or set acquisition mode to continuous (node retrieval). Aborting..." << endl << endl;
return -1;
}
CEnumEntryPtr ptrAcquisitionModeContinuous = ptrAcquisitionMode->GetEntryByName("Continuous");
if (!IsReadable(ptrAcquisitionModeContinuous))
{
cout << "Unable to get acquisition mode to continuous (enum entry retrieval). Aborting..." << endl << endl;
return -1;
}
int64_t acquisitionModeContinuous = ptrAcquisitionModeContinuous->GetValue();
ptrAcquisitionMode->SetIntValue(acquisitionModeContinuous);
cout << "Acquisition mode set to continuous..." << endl;
// The following camera settings are recommended for the Adimec CXP Q-21A230x camera, but may not be available
// on other cameras.
// Pixel format BayerGB8
CEnumerationPtr ptrPixelFormat = nodeMap.GetNode("PixelFormat");
// Set to BayerGB8
if (IsReadable(ptrPixelFormat) || IsWritable(ptrPixelFormat))
{
CEnumEntryPtr ptrBayerGB8 = ptrPixelFormat->GetEntryByName("BayerGB8");
if (IsReadable(ptrBayerGB8))
{
int64_t pixelFormatBayerGB8 = ptrBayerGB8->GetValue();
ptrPixelFormat->SetIntValue(pixelFormatBayerGB8);
cout << "PixelFormat set to BayerGB8..." << endl;
}
}
// Execute command to increase framerate to maximum
CCommandPtr ptrAcquisitionMaxFrameRate = nodeMap.GetNode("AcquisitionMaxFrameRate");
if (IsWritable(ptrAcquisitionMaxFrameRate))
{
ptrAcquisitionMaxFrameRate->Execute();
cout << "Acquisition framerate set to maximum" << endl;
}
// Set DeviceTapGeometry to Geometry_1X_2YE
CEnumerationPtr ptrDeviceTapGeometry = nodeMap.GetNode("DeviceTapGeometry");
if (IsReadable(ptrDeviceTapGeometry) || IsWritable(ptrDeviceTapGeometry))
{
CEnumEntryPtr ptrGeometry_1X_2YE = ptrDeviceTapGeometry->GetEntryByName("Geometry_1X_2YE");
if (IsReadable(ptrGeometry_1X_2YE))
{
ptrDeviceTapGeometry->SetIntValue(ptrGeometry_1X_2YE->GetValue());
cout << "DeviceTapGeometry set to Geometry_1X_2YE" << endl;
}
}
// Increase gain
CFloatPtr ptrGain = nodeMap.GetNode("Gain");
if (IsReadable(ptrGain) && IsWritable(ptrGain))
{
double maxGain = ptrGain->GetMax();
ptrGain->SetValue(maxGain);
cout << "Gain set to maximum value: " << ptrGain->GetValue() << endl;
}
// Execute command to calibrate white balance
CCommandPtr ptrWhiteBalanceCalibrate = nodeMap.GetNode("WhiteBalanceCalibrate");
if (IsWritable(ptrWhiteBalanceCalibrate))
{
ptrWhiteBalanceCalibrate->Execute();
cout << "White balance calibrated." << endl;
}
// Execute command to synchronize all camera image info settings to FrameGrabber image settings
//
// *** NOTES ***
// By default, the framegrabber is configured to passthrough camera image to host without further
// processing. Turn off ResyncWithRemoteDeviceAuto and configure image format settings manually
// to enable post processing on the framegrabber.
//
CCommandPtr ptrDeviceResync = nodeMapTLDevice.GetNode("ResyncWithRemoteDevice");
if (IsWritable(ptrDeviceResync))
{
ptrDeviceResync->Execute();
cout << "Device resync executed." << endl;
}
// Begin acquiring images
pCam->BeginAcquisition();
cout << "Acquiring images..." << endl;
// Retrieve images using image event handler
WaitForImages(imageEventHandler, relay);
// End acquisition
pCam->EndAcquisition();
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
DWORD WINAPI PrintStatsThread(LPVOID lpParam)
{
const DWORD sleepDuration = 2000; // in milliseconds
ThreadParameters* threadParams = static_cast<ThreadParameters*>(lpParam);
SpinnakerRelay* relay = threadParams->relay;
bool isSender = threadParams->isSender;
CameraPtr pCam = threadParams->pCam;
TimeInformation* timeInfo = threadParams->timeInfo;
do
{
relay->GetStatistics(&stats);
PrintRelayStatistics(&stats, timeInfo, false);
timeInfo->ResetTimeInstance();
// On sender side, check for any lost frames
if (isSender)
{
const TransportLayerStream& camStreamInfo = pCam->TLStream;
if (IsReadable(camStreamInfo.StreamLostFrameCount))
{
if (camStreamInfo.StreamLostFrameCount.GetValue() > 0)
{
cout << "\tStream Lost Frame Count: " << camStreamInfo.StreamLostFrameCount.ToString() << endl;
}
}
}
Sleep(sleepDuration);
} while (relay->IsConnected() || relay->IsConnecting());
return 0;
}
{
int result = 0;
try
{
int err = 0;
relay.SetNumBuffers(500);
TimeInformation* receiverTime = new TimeInformation();
// Configure image events
ImageEventHandlerImpl* imageEventHandler;
err = ConfigureImageEvents(relay, imageEventHandler, receiverTime, saveImages);
if (err < 0)
{
return err;
}
// Connect to sender
std::cout << "Connecting to the sender...." << std::endl;
relay.Connect();
std::cout << "Sender connected!" << std::endl;
// Create stats thread
DWORD threadId;
ThreadParameters* threadParams = new ThreadParameters;
threadParams->relay = &relay;
threadParams->isSender = false;
threadParams->timeInfo = receiverTime;
HANDLE hStatsThread = CreateThread(nullptr, 0, PrintStatsThread, threadParams, 0, &threadId);
assert(hStatsThread != nullptr);
cout << endl << "*** WAITING FOR RELAYED IMAGES ***" << endl << endl;
// Retrieve images using image event handler
result = result | WaitForImages(imageEventHandler, relay);
cout << endl << "# Grabbed Images: " << imageEventHandler->getImageCount() << endl;
// Reset image events
result = result | ResetImageEvents(relay, imageEventHandler);
// Disconnect from sender
relay.Disconnect();
// Wait for stats thread to finish
WaitForSingleObject(hStatsThread, INFINITE);
CloseHandle(hStatsThread);
delete threadParams;
RelayStatistics receiverStats;
relay.GetStatistics(&receiverStats);
PrintRelayStatistics(&receiverStats, receiverTime, true);
}
catch (const std::exception& e)
{
cout << "Receiver aborted due to an error:" << e.what() << endl;
result = -1;
}
return result;
}
{
int result = 0;
int err = 0;
try
{
// Retrieve TL device nodemap and print device information
INodeMap& nodeMapTLDevice = pCam->GetTLDeviceNodeMap();
result = PrintDeviceInfo(nodeMapTLDevice);
// Setup Spinnaker Relay
relay.SetNumBuffers(20);
TimeInformation* senderTime = new TimeInformation();
// Initialize camera
pCam->Init();
// Retrieve GenICam nodemap
INodeMap& nodeMap = pCam->GetNodeMap();
// Configure image events
ImageEventHandlerImpl* imageEventHandler;
err = ConfigureImageEvents(pCam, imageEventHandler, senderTime, saveImages);
if (err < 0)
{
return err;
}
// Add camera source to be forwarded
relay.AddSource(pCam);
// Connect to receiver
std::cout << "Connecting to the receiver...." << std::endl;
relay.Connect();
std::cout << "Receiver connected!" << std::endl;
// Create stats thread
DWORD threadId;
ThreadParameters* threadParams = new ThreadParameters;
threadParams->relay = &relay;
threadParams->isSender = true;
threadParams->pCam = pCam;
threadParams->timeInfo = senderTime;
HANDLE hStatsThread = CreateThread(nullptr, 0, PrintStatsThread, threadParams, 0, &threadId);
assert(hStatsThread != nullptr);
// Acquire images using the image event handler
result = result | AcquireImages(pCam, relay, nodeMap, nodeMapTLDevice, imageEventHandler);
cout << endl << "# Grabbed Images: " << imageEventHandler->getImageCount() << endl;
// Reset image events
result = result | ResetImageEvents(pCam, imageEventHandler);
// Deinitialize camera
pCam->DeInit();
// Disconnect from receiver
relay.Disconnect();
// Wait for stats thread to finish
WaitForSingleObject(hStatsThread, INFINITE);
CloseHandle(hStatsThread);
threadParams->pCam = nullptr;
delete threadParams;
// Display relay stats
RelayStatistics senderStats;
relay.GetStatistics(&senderStats);
PrintRelayStatistics(&senderStats, senderTime, true);
}
{
cout << "Sender aborted due to an error: " << e.what() << endl;
result = -1;
}
return result;
}
// Example entry point; please see Enumeration example for additional
// comments on the steps in this function.
int main(int argc, char** argv)
{
// Since this application saves images in the current folder
// we must ensure that we have permission to write to this folder.
// If we do not have permission, fail right away.
FILE* tempFile = fopen("test.txt", "w+");
if (tempFile == nullptr)
{
cout << "Failed to create file in current folder. Please check "
"permissions."
<< endl;
cout << "Press Enter to exit..." << endl;
getchar();
return -1;
}
fclose(tempFile);
remove("test.txt");
int result = 0;
// Print application build information
cout << "Application build date: " << __DATE__ << " " << __TIME__ << endl << endl;
// Parse arguments
if (ParseArguments(argc, argv))
{
if (bReceiver)
{
}
else
{
// Retrieve singleton reference to system object
SystemPtr system = System::GetInstance();
// Print out current library version
const LibraryVersion spinnakerLibraryVersion = system->GetLibraryVersion();
cout << "Spinnaker library version: " << spinnakerLibraryVersion.major << "."
<< spinnakerLibraryVersion.minor << "." << spinnakerLibraryVersion.type << "."
<< spinnakerLibraryVersion.build << endl
<< endl;
// Retrieve list of producers and interfaces from the system
ProducerList producerList = system->GetProducers();
unsigned int numProducers = producerList.GetSize();
for (unsigned int i = 0; i < numProducers; i++)
{
cout << "Producer " << i << endl;
ProducerPtr producer = producerList.GetByIndex(i);
cout << " \tFilePath: " << producer->GetProducerFilePath() << endl;
InterfaceList interfaceList = producer->GetInterfaces();
unsigned int numInterfaces = interfaceList.GetSize();
cout << "\tNumber of interfaces detected: " << numInterfaces << endl;
CameraList camList = producer->GetCameras();
unsigned int numCameras = camList.GetSize();
cout << "\tNumber of cameras detected: " << numCameras << endl << endl;
}
// Retrieve list of cameras from the system
CameraList camList = system->GetCameras();
unsigned int numCameras = camList.GetSize();
cout << "Number of cameras detected: " << numCameras << endl << endl;
// Finish if there are no cameras
if (numCameras == 0)
{
// Clear camera list before releasing system
camList.Clear();
// Clear producer list before releasing system
producerList.Clear();
// Release system
system->ReleaseInstance();
cout << "Not enough cameras!" << endl;
cout << "Done! Press Enter to exit..." << endl;
getchar();
return -1;
}
// Create shared pointer to camera
CameraPtr pCam = nullptr;
int result = 0;
// Select camera
pCam = camList.GetByIndex(0);
cout << "Running example with camera index 0" << endl;
RunSender(pCam);
// Release reference to the camera
pCam = nullptr;
// Clear camera list before releasing system
camList.Clear();
// Clear producer list before releasing system
producerList.Clear();
// Release system
system->ReleaseInstance();
}
}
cout << endl << "Done! Press Enter to exit..." << endl;
getchar();
return result;
}
int AcquireImages(CameraPtr pCam, INodeMap &nodeMap, INodeMap &nodeMapTLDevice)
Definition Acquisition.cpp:200
int main(int, char **)
Definition Acquisition.cpp:536
int PrintDeviceInfo(INodeMap &nodeMap)
Definition Acquisition.cpp:442
void PrintUsage()
Definition FileAccess_QuickSpin.cpp:1026
const char * argPrintUsage
Definition GigEVisionPerformance.cpp:64
bool ParseArguments(int argc, char *argv[])
Definition GigEVisionPerformance.cpp:83
const char * argNumImages
Definition GigEVisionPerformance.cpp:56
int WaitForImages(ImageEventHandlerImpl *&imageEventHandler)
Definition ImageEvents.cpp:214
int ResetImageEvents(CameraPtr pCam, ImageEventHandlerImpl *&imageEventHandler)
Definition ImageEvents.cpp:249
int ConfigureImageEvents(CameraPtr pCam, ImageEventHandlerImpl *&imageEventHandler)
Definition ImageEvents.cpp:171
uint64_t timeout
Definition ImageRelay.cpp:70
bool bReceiver
Definition ImageRelay.cpp:60
const char * argTimeout
Definition ImageRelay.cpp:130
gcstring receiverIPAddress
Definition ImageRelay.cpp:63
int RunSender(CameraPtr pCam)
Definition ImageRelay.cpp:1033
ConnectParameters relayConnectParams
Definition ImageRelay.cpp:67
const char * argReceiverPort
Definition ImageRelay.cpp:125
int RunReceiver()
Definition ImageRelay.cpp:963
unsigned int senderPort
Definition ImageRelay.cpp:64
const char * argSenderIP
Definition ImageRelay.cpp:126
bool bSourceIPSpecified
Definition ImageRelay.cpp:66
bool bSender
Definition ImageRelay.cpp:61
DWORD WINAPI PrintStatsThread(LPVOID lpParam)
Definition ImageRelay.cpp:926
gcstring senderIPAddress
Definition ImageRelay.cpp:62
void PrintRelayStatistics(const RelayStatistics *stats, TimeInformation *timeInfo, bool printSummary=false)
Definition ImageRelay.cpp:300
const char * argReceiverIP
Definition ImageRelay.cpp:124
bool saveImages
Definition ImageRelay.cpp:69
const char * argStartSender
Definition ImageRelay.cpp:123
const char * argSenderPort
Definition ImageRelay.cpp:127
unsigned int receiverPort
Definition ImageRelay.cpp:65
unsigned int numImagesToGrab
Definition ImageRelay.cpp:68
const char * argStartReceiver
Definition ImageRelay.cpp:122
const char * argSaveImages
Definition ImageRelay.cpp:129
Definition AcquisitionMultipleCameraRecovery.cpp:57
int getImageCount()
Definition ImageEvents.cpp:151
int getMaxImages()
Definition ImageEvents.cpp:157
void OnImageEvent(ImagePtr image)
Image event callback.
Definition AcquisitionMultipleCameraRecovery.cpp:109
~ImageEventHandlerImpl()
Definition AcquisitionMultipleCameraRecovery.cpp:66
int setMaxImages(unsigned int maxImages)
Definition ImageRelay.cpp:545
Used to hold a list of camera objects.
Definition CameraList.h:42
void Clear()
Clears the list of cameras and destroys their corresponding reference counted objects.
CameraPtr GetByIndex(unsigned int index) const
Returns a pointer to a camera object at the "index".
unsigned int GetSize() const
Returns the size of the camera list.
A reference tracked pointer to a camera object.
Definition CameraPtr.h:44
The Exception object represents an error that is returned from the library.
Definition Exception.h:51
virtual const char * what() const
virtual override for what().
SmartPointer for IFloat interface pointer.
Definition Pointer.h:421
Encapsulates a GenApi pointer dealing with the dynamic_cast automatically.
Definition Pointer.h:75
Definition GCString.h:43
A handler for capturing image arrival events.
Definition ImageEventHandler.h:46
Image post processing class for converting a source image to another pixel format.
Definition ImageProcessor.h:160
A reference tracked pointer to an image object.
Definition ImagePtr.h:46
A list of the available interfaces on the system.
Definition InterfaceList.h:42
unsigned int GetSize() const
Returns the size of the interface list.
A list of the available producers on the system.
Definition ProducerList.h:42
ProducerPtr GetByIndex(unsigned int index) const
Returns a pointer to an Producer object at the "index".
void Clear()
Clears the list of producers and destroys their corresponding objects.
unsigned int GetSize() const
Returns the size of the producer list.
A reference tracked pointer to the producer object.
Definition ProducerPtr.h:44
Spinnaker Relay class that enables forwarding of Spinnaker images from source to destination PC.
Definition SpinnakerRelay.h:42
virtual bool IsConnected()
Returns a boolean value indicating if this relay is connected.
virtual void SetNumBuffers(uint64_t numBuffers)
Sets number of relay buffers.
virtual void Disconnect()
Disconnects a Spinnaker Relay connection.
virtual void SetConnectParameters(const ConnectParameters connectParam)
Sets relay connect parameters.
virtual void GetStatistics(RelayStatistics *statistics)
Returns a RelayStatistics struct containing statistics about the performance of the relay connection:...
virtual void UnregisterEventHandler(EventHandler &eventHandler)
Unregisters an event handler from the receiver.
virtual bool IsConnecting()
Returns a boolean value indicating if the relay is currently attempting to connect.
virtual void RegisterEventHandler(EventHandler &eventHandler)
Registers an image event handler for the receiver.
virtual void AddSource(CameraPtr pCamera)
Adds a camera as a streaming source to the sender.
virtual void Connect()
Initiates a Spinnaker Relay connection.
A reference tracked pointer to a system object.
Definition SystemPtr.h:44
Part of the QuickSpin API to provide access to camera information without having to first initialize ...
Definition TransportLayerStream.h:45
GenApi::IInteger & StreamLostFrameCount
Description: Number of times new data could not be acquired and was lost because there was no free bu...
Definition TransportLayerStream.h:195
bool IsWritable(EAccessMode AccessMode)
Tests if writable.
Definition INode.h:277
bool IsReadable(EAccessMode AccessMode)
Tests if readable.
Definition INode.h:253
interface SPINNAKER_API_ABSTRACT INodeMap
Interface to access the node map.
Definition INodeMap.h:54
@ SPINNAKER_ROLE_RECEIVER
Definition SpinnakerRelayDefs.h:55
@ SPINNAKER_ROLE_SENDER
Definition SpinnakerRelayDefs.h:54
Definition AutoPollController.h:33
Definition GCString.h:31
Definition EventHandler.h:29
Definition BasePtr.h:24
Provides easier access to the current version of Spinnaker.
Definition SpinnakerDefs.h:706
unsigned int minor
Minor version of the library.
Definition SpinnakerDefs.h:711
unsigned int major
Major version of the library.
Definition SpinnakerDefs.h:708
unsigned int type
Version type of the library.
Definition SpinnakerDefs.h:714
unsigned int build
Build number of the library.
Definition SpinnakerDefs.h:717
Connection Parameters.
Definition SpinnakerRelayDefs.h:68
Relay Statistics.
Definition SpinnakerRelayDefs.h:92
uint64_t instanceSendSuccessCount
Definition SpinnakerRelayDefs.h:95
uint64_t totalRecvDataCount
Definition SpinnakerRelayDefs.h:116
uint64_t totalSendDropCount
Definition SpinnakerRelayDefs.h:110
uint64_t totalRecvSuccessCount
Definition SpinnakerRelayDefs.h:113
uint64_t totalRecvErrorCount
Definition SpinnakerRelayDefs.h:114
uint64_t totalSendErrorCount
Definition SpinnakerRelayDefs.h:109
uint64_t instanceSendDropCount
Definition SpinnakerRelayDefs.h:97
uint64_t instanceSendDataCount
Definition SpinnakerRelayDefs.h:98
uint64_t instanceRecvErrorCount
Definition SpinnakerRelayDefs.h:101
uint64_t totalRecvDropCount
Definition SpinnakerRelayDefs.h:115
uint64_t totalSendSuccessCount
Definition SpinnakerRelayDefs.h:108
uint64_t instanceRecvSuccessCount
Definition SpinnakerRelayDefs.h:100
uint64_t instanceRecvDataCount
Definition SpinnakerRelayDefs.h:103
uint64_t totalSendDataCount
Definition SpinnakerRelayDefs.h:111
uint64_t instanceRecvDropCount
Definition SpinnakerRelayDefs.h:102
uint64_t instanceSendErrorCount
Definition SpinnakerRelayDefs.h:96
Definition ImageRelay.cpp:105
TimeInformation * timeInfo
Definition ImageRelay.cpp:109
SpinnakerRelay * relay
Definition ImageRelay.cpp:106
CameraPtr pCam
Definition ImageRelay.cpp:108
bool isSender
Definition ImageRelay.cpp:107
ThreadParameters()
Definition ImageRelay.cpp:111
Definition ImageRelay.cpp:73
void RecordImageEvent(std::chrono::system_clock::time_point imageEventTime)
Definition ImageRelay.cpp:90
const std::chrono::system_clock::time_point invalid_time
Definition ImageRelay.cpp:74
std::chrono::system_clock::time_point instanceLastEvent
Definition ImageRelay.cpp:81
std::chrono::system_clock::time_point instanceFirstEvent
Definition ImageRelay.cpp:79
std::chrono::system_clock::time_point lastEvent
Definition ImageRelay.cpp:82
TimeInformation()
Definition ImageRelay.cpp:84
std::chrono::system_clock::time_point firstEvent
Definition ImageRelay.cpp:80
void ResetTimeInstance()
Definition ImageRelay.cpp:97
std::chrono::system_clock::time_point startTimeInstance
Definition ImageRelay.cpp:77
std::chrono::system_clock::time_point startTime
Definition ImageRelay.cpp:76