Spinnaker SDK C++
4.3.0.189
 
 

 
Loading...
Searching...
No Matches
StereoAcquisition.cpp

StereoAcquisition.cpp shows how to acquire image sets from a stereo camera.

StereoAcquisition.cpp shows how to acquire image sets from a stereo camera. The image sets are then saved to file and/or used to compute 3D point cloud and saved as a PLY (Polygon File Format) file.

This example touches on the preparation and cleanup of a camera just before and just after the acquisition of images. Image retrieval and conversion, grabbing image data, and saving images are all covered as well.

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 non-disclosure or 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.
//=============================================================================
//=============================================================================
// System Includes
//=============================================================================
#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <sstream>
#include <filesystem>
//=============================================================================
// Examples Includes
//=============================================================================
#include "PointCloud.h"
#include "Spinnaker.h"
#include "SpinStereoHelper.h"
#include "StereoParameters.h"
#include "Getopt.h"
using namespace Spinnaker;
using namespace Spinnaker::GenApi;
using namespace Spinnaker::GenICam;
using namespace SpinStereo;
using namespace std;
bool ProcessArgs(int argc, char* argv[], StereoAcquisitionParams& params)
{
string executionPath = string(argv[0]);
size_t found = executionPath.find_last_of("/\\");
string programName = executionPath.substr(found + 1);
int iOpt;
const char* currentParamPosition;
bool bBadArgs = false;
// If no arguments run with default parameters.
if (argc == 1)
{
params.doEnablePointCloudOutput = true;
return true;
}
const char* paramMatchPattern = "n:ABCDEFGh?";
while ((iOpt = GetOption(argc, argv, paramMatchPattern, &currentParamPosition)) != 0)
{
switch (iOpt)
{
//
// Options
//
case 'n':
#ifdef _MSC_VER
if (sscanf_s(currentParamPosition, "%d", &params.numImageSets) != 1)
#else
if (sscanf(currentParamPosition, "%d", &params.numImageSets) != 1)
#endif
{
bBadArgs = true;
}
else
{
if (params.numImageSets <= 0)
{
cout << "The numImageSets argument must be a number greater than 0." << endl;
bBadArgs = true;
}
}
break;
case 'A':
break;
case 'B':
break;
case 'C':
break;
case 'D':
break;
case 'E':
break;
case 'F':
params.doEnablePointCloudOutput = true;
break;
case 'G':
break;
case '?':
case 'h':
default:
cerr << "Invalid option provided: " << currentParamPosition << endl;
DisplayHelp(programName, params);
return false;
}
}
if (bBadArgs)
{
cout << "Invalid arguments" << endl;
DisplayHelp(programName, params);
return false;
}
{
{
cout << "Need to have disparity Image (-E) for point cloud generation" << endl << endl;
DisplayHelp(programName, params);
return false;
}
{
cout << "Need to have Rectified Sensor1 Image (-C) for point cloud generation" << endl << endl;
DisplayHelp(programName, params);
return false;
}
}
{
cout << "Need to enable at least one image (-A/-B/-C/-D/-E)" << endl << endl;
DisplayHelp(programName, params);
return false;
}
return true;
}
void DisplayHelp(const string& pszProgramName, const StereoAcquisitionParams& params)
{
cout << "Usage: ";
cout << pszProgramName << " [OPTIONS]" << endl << endl;
cout << "OPTIONS" << endl
<< endl
<< " -n NUM_FRAMES Number frames" << endl
<< " Default is " << params.numImageSets << endl
<< " -A DO_ENABLE_RAW_SENSOR1_TRANSMIT doEnableRawSensor1Transmit" << endl
<< " Default is " << params.doEnableRawSensor1Transmit << endl
<< " -B DO_ENABLE_RAW_SENSOR2_TRANSMIT doEnableRawSensor2Transmit" << endl
<< " Default is " << params.doEnableRawSensor2Transmit << endl
<< " -C DO_ENABLE_RECT_SENSOR1_TRANSMIT doEnableRectSensor1Transmit" << endl
<< " Default is " << params.doEnableRectSensor1Transmit << endl
<< " -D DO_ENABLE_RECT_SENSOR2_TRANSMIT doEnableRectSensor2Transmit" << endl
<< " Default is " << params.doEnableRectSensor2Transmit << endl
<< " -E DO_ENABLE_DISPARITY_TRANSMIT doEnableDisparityTransmit" << endl
<< " Default is " << params.doEnableDisparityTransmit << endl
<< " -F DO_ENABLE_POINTCLOUD_OUTPUT doEnablePointCloudOutput" << endl
<< " Default is " << params.doEnablePointCloudOutput << endl
<< " -G DO_ENABLE_POST_PROCESSING doEnableDisparityPostProcessing" << endl
<< " Default is " << params.doEnableDisparityPostProcessing << endl
<< "EXAMPLE" << endl
<< endl
<< " " << pszProgramName << " -n " << params.numImageSets << " -A "
<< " -B "
<< " -C "
<< " -D "
<< " -E "
<< " -F " << endl
<< endl;
}
// This function configures the camera to add chunk data to each image. It does
// this by enabling each type of chunk data after enabling chunk data mode.
// When chunk data mode is turned on, the data is made available in both the nodemap
// and each image.
bool ConfigureChunkData(INodeMap& nodeMap)
{
bool result = true;
cout << endl << endl << "*** CONFIGURING CHUNK DATA ***" << endl << endl;
try
{
//
// Activate chunk mode
//
// *** NOTES ***
// Once enabled, chunk data will be available at the end of the payload
// of every image captured until it is disabled. Chunk data can also be
// retrieved from the nodemap.
//
CBooleanPtr ptrChunkModeActive = nodeMap.GetNode("ChunkModeActive");
if (!IsWritable(ptrChunkModeActive))
{
cout << "Unable to activate chunk mode. Aborting..." << endl << endl;
return false;
}
ptrChunkModeActive->SetValue(true);
cout << "Chunk mode activated..." << endl;
//
// Enable all types of chunk data
//
// *** NOTES ***
// Enabling chunk data requires working with nodes: "ChunkSelector"
// is an enumeration selector node and "ChunkEnable" is a boolean. It
// requires retrieving the selector node (which is of enumeration node
// type), selecting the entry of the chunk data to be enabled, retrieving
// the corresponding boolean, and setting it to true.
//
// In this example, all chunk data is enabled, so these steps are
// performed in a loop. Once this is complete, chunk mode still needs to
// be activated.
//
NodeList_t entries;
// Retrieve the selector node
CEnumerationPtr ptrChunkSelector = nodeMap.GetNode("ChunkSelector");
if (!IsReadable(ptrChunkSelector))
{
cout << "Unable to retrieve chunk selector. Aborting..." << endl << endl;
return false;
}
// Retrieve entries
ptrChunkSelector->GetEntries(entries);
cout << "Enabling entries..." << endl;
for (size_t i = 0; i < entries.size(); i++)
{
// Select entry to be enabled
CEnumEntryPtr ptrChunkSelectorEntry = entries.at(i);
// Go to next node if problem occurs
if (!IsReadable(ptrChunkSelectorEntry))
{
continue;
}
ptrChunkSelector->SetIntValue(ptrChunkSelectorEntry->GetValue());
cout << "\t" << ptrChunkSelectorEntry->GetSymbolic() << ": ";
// Retrieve corresponding boolean
CBooleanPtr ptrChunkEnable = nodeMap.GetNode("ChunkEnable");
// Enable the boolean, thus enabling the corresponding chunk data
if (!IsAvailable(ptrChunkEnable))
{
cout << "not available" << endl;
result = false;
}
else if (ptrChunkEnable->GetValue())
{
cout << "enabled" << endl;
}
else if (IsWritable(ptrChunkEnable))
{
ptrChunkEnable->SetValue(true);
cout << "enabled" << endl;
}
else
{
cout << "not writable" << endl;
result = false;
}
}
}
{
cout << "Error: " << e.what() << endl;
result = false;
}
return result;
}
// This function disables each type of chunk data before disabling chunk data mode.
bool DisableChunkData(INodeMap& nodeMap)
{
bool result = true;
try
{
NodeList_t entries;
// Retrieve the selector node
CEnumerationPtr ptrChunkSelector = nodeMap.GetNode("ChunkSelector");
if (!IsReadable(ptrChunkSelector))
{
cout << "Unable to retrieve chunk selector. Aborting..." << endl << endl;
return false;
}
// Retrieve entries
ptrChunkSelector->GetEntries(entries);
cout << "Disabling entries..." << endl;
for (size_t i = 0; i < entries.size(); i++)
{
// Select entry to be disabled
CEnumEntryPtr ptrChunkSelectorEntry = entries.at(i);
// Go to next node if problem occurs
if (!IsReadable(ptrChunkSelectorEntry))
{
continue;
}
ptrChunkSelector->SetIntValue(ptrChunkSelectorEntry->GetValue());
cout << "\t" << ptrChunkSelectorEntry->GetSymbolic() << ": ";
// Retrieve corresponding boolean
CBooleanPtr ptrChunkEnable = nodeMap.GetNode("ChunkEnable");
// Disable the boolean, thus disabling the corresponding chunk data
if (!IsAvailable(ptrChunkEnable))
{
cout << "not available" << endl;
result = false;
}
else if (!ptrChunkEnable->GetValue())
{
cout << "disabled" << endl;
}
else if (IsWritable(ptrChunkEnable))
{
ptrChunkEnable->SetValue(false);
cout << "disabled" << endl;
}
else
{
cout << "not writable" << endl;
}
}
cout << endl;
// Deactivate ChunkMode
CBooleanPtr ptrChunkModeActive = nodeMap.GetNode("ChunkModeActive");
if (!IsWritable(ptrChunkModeActive))
{
cout << "Unable to deactivate chunk mode. Aborting..." << endl << endl;
return false;
}
ptrChunkModeActive->SetValue(false);
cout << "Chunk mode deactivated..." << endl;
}
{
cout << "Error: " << e.what() << endl;
result = false;
}
return result;
}
// This function displays a select amount of chunk data from the image. Unlike
// accessing chunk data via the nodemap, there is no way to loop through all
// available data.
{
bool result = true;
cout << "Printing chunk data from image..." << endl;
try
{
//
// Retrieve chunk data from image
//
// *** NOTES ***
// When retrieving chunk data from an image, the data is stored in a
// a ChunkData object and accessed with getter functions.
//
ChunkData chunkData = pImage->GetChunkData();
//
// Retrieve exposure time; exposure time recorded in microseconds
//
// *** NOTES ***
// Floating point numbers are returned as a float64_t. This can safely
// and easily be statically cast to a double.
//
double exposureTime = static_cast<double>(chunkData.GetExposureTime());
std::cout << "\tExposure time: " << exposureTime << endl;
//
// Retrieve frame ID
//
// *** NOTES ***
// Integers are returned as an int64_t. As this is the typical integer
// data type used in the Spinnaker SDK, there is no need to cast it.
//
int64_t frameID = chunkData.GetFrameID();
cout << "\tFrame ID: " << frameID << endl;
// The following are stereo-specific chunk data attributes
// Retrieve stereo height; stereo height recorded in pixels
int64_t stereoHeight = chunkData.GetStereoHeight();
cout << "\tStereoHeight: " << stereoHeight << endl;
// Retrieve stereo width; stereo width recorded in pixels
int64_t stereoWidth = chunkData.GetStereoWidth();
cout << "\tStereoWidth: " << stereoWidth << endl;
// Retrieve Scan3dCordinateOffset; Scan3dCordinateOffset recorded in pixels
float64_t scan3dCoordinateOffset = chunkData.GetScan3dCoordinateOffset();
cout << "\tScan3dCoordinateOffset: " << scan3dCoordinateOffset << endl;
// Retrieve Scan3dBaseline; Scan3dBaseline recorded in meters
float64_t scan3dBaseline = chunkData.GetScan3dBaseline();
cout << "\tScan3dBaseline: " << scan3dBaseline << endl;
// Retrieve Scan3dFocalLength; Scan3dFocalLength recorded in pixels
float64_t scan3dFocalLength = chunkData.GetScan3dFocalLength();
cout << "\tScan3dFocalLength: " << scan3dFocalLength << endl;
// Retrieve MinZ; MinZ recorded in meters
float64_t minZ = chunkData.GetMinZ();
cout << "\tMinZ: " << minZ << endl;
// Retrieve MaxZ; MaxZ recorded in meters
float64_t maxZ = chunkData.GetMaxZ();
cout << "\tMaxZ: " << maxZ << endl;
// Retrieve Scan3dPrincipalPointU; Scan3dPrincipalPointU recorded in pixels
float64_t scan3dPrincipalPointU = chunkData.GetScan3dPrincipalPointU();
cout << "\tScan3dPrincipalPointU: " << scan3dPrincipalPointU << endl;
// Retrieve Scan3dPrincipalPointV; Scan3dPrincipalPointV recorded in pixels
float64_t scan3dPrincipalPointV = chunkData.GetScan3dPrincipalPointV();
cout << "\tScan3dPrincipalPointV: " << scan3dPrincipalPointV << endl;
// Retrieve SmallPenalty; SmallPenalty recorded in pixels
int64_t smallPenalty = chunkData.GetSmallPenalty();
cout << "\tSmallPenalty: " << smallPenalty << endl;
// Retrieve LargePenalty; LargePenalty recorded in pixels
int64_t largePenalty = chunkData.GetLargePenalty();
cout << "\tLargePenalty: " << largePenalty << endl;
// Retrieve UniquenessRatio; UniquenessRatio recorded in pixels
int64_t uniquenessRatio = chunkData.GetUniquenessRatio();
cout << "\tUniquenessRatio: " << uniquenessRatio << endl;
}
{
cout << "Error: " << e.what() << endl;
result = false;
}
return result;
}
const StereoParameters& stereoParameters,
ImageList& imageList,
int counter,
string prefix = "")
{
PointCloudParameters pointCloudParameters = PointCloudParameters();
pointCloudParameters.decimationFactor = 1;
pointCloudParameters.ROIImageLeft = 0;
pointCloudParameters.ROIImageTop = 0;
pointCloudParameters.ROIImageRight = static_cast<unsigned int>(
imageList.GetByPayloadType(SPINNAKER_IMAGE_PAYLOAD_TYPE_DISPARITY_SENSOR1)->GetWidth());
pointCloudParameters.ROIImageBottom = static_cast<unsigned int>(
imageList.GetByPayloadType(SPINNAKER_IMAGE_PAYLOAD_TYPE_DISPARITY_SENSOR1)->GetHeight());
StereoCameraParameters stereoCameraParameters = StereoCameraParameters();
stereoCameraParameters.coordinateOffset = stereoParameters.scan3dCoordinateOffset;
stereoCameraParameters.baseline = stereoParameters.scan3dBaseline;
stereoCameraParameters.focalLength = stereoParameters.scan3dFocalLength;
stereoCameraParameters.principalPointU = stereoParameters.scan3dPrincipalPointU;
stereoCameraParameters.principalPointV = stereoParameters.scan3dPrincipalPointV;
stereoCameraParameters.disparityScaleFactor = stereoParameters.scan3dCoordinateScale;
stereoCameraParameters.invalidDataFlag = stereoParameters.scan3dInvalidDataFlag;
stereoCameraParameters.invalidDataValue = stereoParameters.scan3dInvalidDataValue;
imageList.GetByPayloadType(SPINNAKER_IMAGE_PAYLOAD_TYPE_DISPARITY_SENSOR1),
imageList.GetByPayloadType(SPINNAKER_IMAGE_PAYLOAD_TYPE_RECTIFIED_SENSOR1),
pointCloudParameters,
stereoCameraParameters);
stringstream strstr("");
strstr << prefix;
strstr << "PointCloud_" << counter << ".ply";
cout << "Save point cloud to file: " << strstr.str() << endl;
pointCloud.SavePointCloudAsPly(strstr.str().c_str());
return true;
}
const StreamTransmitFlags& streamTransmitFlags,
ImageList& imageList,
int counter,
const string prefix = "")
{
cout << "Save images to files." << endl;
stringstream strstr;
if (streamTransmitFlags.rawSensor1TransmitEnabled)
{
strstr.str("");
strstr << prefix;
strstr << "RawSensor1_" << counter << ".png";
string rawSensor1Filename = strstr.str();
cout << "Save raw Sensor1 image to file: " << rawSensor1Filename << endl;
imageList.GetByPayloadType(SPINNAKER_IMAGE_PAYLOAD_TYPE_RAW_SENSOR1)->Save(rawSensor1Filename.c_str());
}
if (streamTransmitFlags.rawSensor2TransmitEnabled)
{
strstr.str("");
strstr << prefix;
strstr << "RawSensor2_" << counter << ".png";
string rawSensor2Filename = strstr.str();
cout << "Save raw Sensor2 image to file: " << rawSensor2Filename << endl;
imageList.GetByPayloadType(SPINNAKER_IMAGE_PAYLOAD_TYPE_RAW_SENSOR2)->Save(rawSensor2Filename.c_str());
}
if (streamTransmitFlags.rectSensor1TransmitEnabled)
{
strstr.str("");
strstr << prefix;
strstr << "RectSensor1_" << counter << ".png";
string rectSensor1Filename = strstr.str();
cout << "Save rectified sensor1 image to file: " << rectSensor1Filename << endl;
imageList.GetByPayloadType(SPINNAKER_IMAGE_PAYLOAD_TYPE_RECTIFIED_SENSOR1)->Save(rectSensor1Filename.c_str());
}
if (streamTransmitFlags.rectSensor2TransmitEnabled)
{
strstr.str("");
strstr << prefix;
strstr << "RectSensor2_" << counter << ".png";
string rectSensor2Filename = strstr.str();
cout << "Save rectified sensor2 image to file: " << rectSensor2Filename << endl;
imageList.GetByPayloadType(SPINNAKER_IMAGE_PAYLOAD_TYPE_RECTIFIED_SENSOR2)->Save(rectSensor2Filename.c_str());
}
if (streamTransmitFlags.disparityTransmitEnabled)
{
strstr.str("");
strstr << prefix;
strstr << "Disparity_" << counter << ".pgm";
string disparityFilename = strstr.str();
cout << "Save disparity image to file: " << disparityFilename << endl;
imageList.GetByPayloadType(SPINNAKER_IMAGE_PAYLOAD_TYPE_DISPARITY_SENSOR1)->Save(disparityFilename.c_str());
}
return true;
}
{
// NOTE:
//
// Camera firmware will report the current bandwidth required by the camera in the 'DeviceLinkCurrentThroughput'
// node. When 'DeviceLinkThroughputLimit' node is set by the user, firmware will automatically increase packet
// delay to fulfill the requested throughput. Therefore, once camera is configured for the desired
// framerate/image size/etc, set 'DeviceLinkCurrentThroughput' node value into 'DeviceLinkThroughputLimit' node,
// and packet size will be automatically set by the camera.
INodeMap& nodeMap = pCam->GetNodeMap();
// Set Stream Channel Packet Size to the max possible on its interface
CIntegerPtr ptrPacketSize = nodeMap.GetNode("GevSCPSPacketSize");
if (!IsReadable(ptrPacketSize) || !IsWritable(ptrPacketSize))
{
cout << "Unable to read or write packet size. Aborting..." << endl;
return false;
}
unsigned int maxGevSCPSPacketSize = static_cast<unsigned int>(ptrPacketSize->GetMax());
const unsigned int maxPacketSize =
pCam->DiscoverMaxPacketSize() > maxGevSCPSPacketSize ? maxGevSCPSPacketSize : pCam->DiscoverMaxPacketSize();
ptrPacketSize->SetValue(maxPacketSize);
cout << "PacketSize set to: " << ptrPacketSize->GetValue() << endl;
CIntegerPtr ptrCurrentThroughput = nodeMap.GetNode("DeviceLinkCurrentThroughput");
CIntegerPtr ptrThroughputLimit = nodeMap.GetNode("DeviceLinkThroughputLimit");
if (!IsReadable(ptrCurrentThroughput))
{
cout << "Unable to read node DeviceLinkCurrentThroughput. Aborting..." << endl << endl;
return false;
}
if (!IsReadable(ptrThroughputLimit) || !IsWritable(ptrThroughputLimit))
{
cout << "Unable to read or write to node DeviceLinkThroughputLimit. Aborting..." << endl;
return false;
}
cout << "Current camera throughput: " << ptrCurrentThroughput->GetValue() << endl;
// If the 'DeviceLinkCurrentThroughput' value is lower than the minimum, set the lowest possible value allowed
// by the 'DeviceLinkCurrentThroughput' node
if (ptrThroughputLimit->GetMin() > ptrCurrentThroughput->GetValue())
{
cout << "DeviceLinkCurrentThroughput node minimum of: " << ptrThroughputLimit->GetMin()
<< " is higher than current throughput we desire to set (" << ptrCurrentThroughput->GetValue() << ")"
<< endl;
ptrThroughputLimit->SetValue(ptrThroughputLimit->GetMin());
}
else
{
// Set 'DeviceLinkCurrentThroughput' value into 'DeviceLinkThroughputLimit' node so that the
// camera will adjust inter-packet delay automatically
ptrThroughputLimit->SetValue(ptrCurrentThroughput->GetValue());
}
cout << "DeviceLinkThroughputLimit set to: " << ptrThroughputLimit->GetValue() << endl << endl;
return true;
}
bool AcquireImages(CameraPtr pCam, StereoParameters& stereoParameters, unsigned int numImageSets)
{
bool result = true;
cout << endl << endl << "*** IMAGE ACQUISITION ***" << endl << endl;
try
{
// Begin acquiring images
pCam->BeginAcquisition();
cout << endl << "Acquiring " << numImageSets << " image sets." << endl;
gcstring serialNumber = pCam->TLDevice.DeviceSerialNumber.GetValue();
uint64_t timeoutInMilliSecs = 2000;
for (unsigned int counter = 0; counter < numImageSets; counter++)
{
try
{
cout << endl << "Acquiring stereo image set: " << counter << endl;
//
// Retrieve next received set of stereo images
//
// *** NOTES ***
// GetNextImageSync() captures an image from each stream and returns a synchronized
// image set in an ImageList object based on the frame ID. The ImageList object is
// simply a generic container for one or more ImagePtr objects.
//
// For a set of stereo images, the ImageList object could contain up to five different
// image payload type images (Raw Sensor1, Raw Sensor2, Rectified Sensor1, Rectified Sensor2 and
// Disparity Sensor1). The five images that are returned in the ImageList are guaranteed
// to be synchronized in timestamp and Frame ID.
//
// This function cannot be invoked if GetNextImage is being invoked already.
// Results will be indeterministic and could lead to missing or lost of images.
//
// *** LATER ***
// Once the image list is saved and/or no longer needed, the image list must be
// released in order to keep the image buffer from filling up.
ImageList imageList;
imageList = pCam->GetNextImageSync(timeoutInMilliSecs);
if (!SpinStereo::ValidateImageList(stereoParameters.streamTransmitFlags, imageList))
{
cout << "Failed to get next image set." << endl;
continue;
}
// Chunk Data is only available from the last Image in the ImageList for multi-stream cameras
ImagePtr img = imageList.GetByIndex(imageList.GetSize() - 1);
if (stereoParameters.postProcessDisparity)
{
{
ImagePtr pDisparity =
imageList.GetByPayloadType(SPINNAKER_IMAGE_PAYLOAD_TYPE_DISPARITY_SENSOR1);
{
StereoCameraParameters stereoCameraParameters = StereoCameraParameters();
stereoCameraParameters.coordinateOffset = stereoParameters.scan3dCoordinateOffset;
stereoCameraParameters.baseline = stereoParameters.scan3dBaseline;
stereoCameraParameters.focalLength = stereoParameters.scan3dFocalLength;
stereoCameraParameters.principalPointU = stereoParameters.scan3dPrincipalPointU;
stereoCameraParameters.principalPointV = stereoParameters.scan3dPrincipalPointV;
stereoCameraParameters.disparityScaleFactor = stereoParameters.scan3dCoordinateScale;
stereoCameraParameters.invalidDataFlag = stereoParameters.scan3dInvalidDataFlag;
stereoCameraParameters.invalidDataValue = stereoParameters.scan3dInvalidDataValue;
stereoCameraParameters.totalDisparity = stereoParameters.totalDisparity;
//
// Post process disparity image to fill holes and reduce noise
//
// *** NOTES ***
// Disparity processing method apply different combinations of algorithms such as
// weighted interpolation, joint bilateral filtering, domain transfer, and speckle
// filtering to refine the disparity map. Each method offers a unique
// trade-off between accuracy, density, and performance.
//
cout << "Post-process disparity image..." << endl;
ImagePtr pRectifiedImage =
imageList.GetByPayloadType(SPINNAKER_IMAGE_PAYLOAD_TYPE_RECTIFIED_SENSOR1);
ImageUtilityStereo::ProcessDisparityFromImage(
pDisparity,
pRectifiedImage,
SPINNAKER_DISPARITY_PROCESSING_METHOD_HIGH_PERFORMANCE,
stereoCameraParameters);
}
}
else
{
cout << "Skipping disparity post processing as disparity components are disabled" << endl;
}
}
stringstream ss("");
ss << "StereoAcquisition_" << serialNumber << "_";
if (!SaveImagesToFile(stereoParameters.streamTransmitFlags, imageList, counter, ss.str()))
{
cerr << "Failed to save images." << endl;
result = false;
break;
}
if (stereoParameters.doComputePointCloud)
{
{
// only do if both streams are enabled
if (!Compute3DPointCloudAndSave(stereoParameters, imageList, counter, ss.str()))
{
cerr << "Failed to compute the 3D point cloud." << endl;
result = false;
break;
}
}
else
{
cout << "Skipping compute 3D point cloud as rectified sensor1 or disparity sensor1 components "
"are disabled"
<< endl;
}
}
}
{
cout << "Error: " << e.what() << endl;
result = false;
}
}
//
// End acquisition
//
// *** NOTES ***
// Ending acquisition appropriately helps ensure that devices clean up
// properly and do not need to be power-cycled to maintain integrity.
//
pCam->EndAcquisition();
}
{
cout << "Error: " << e.what() << endl;
result = false;
}
return result;
}
// This function acts as the body of the example; please see NodeMapInfo example
// for more in-depth comments on setting up cameras.
bool RunSingleCamera(CameraPtr pCam, StereoParameters& stereoParameters, int numImageSets)
{
bool result = true;
try
{
// Retrieve TL device nodemap and print device information
INodeMap& nodeMapTLDevice = pCam->GetTLDeviceNodeMap();
result = PrintDeviceInfo(nodeMapTLDevice);
// Initialize camera
pCam->Init();
// Retrieve GenICam nodemap
INodeMap& nodeMap = pCam->GetNodeMap();
// Check to make sure camera supports stereo vision
cout << endl << "Checking camera stereo support..." << endl;
if (!ImageUtilityStereo::IsStereoCamera(pCam))
{
cout << "Device serial number " << pCam->TLDevice.DeviceSerialNumber.GetValue()
<< " is not a valid BX camera. Skipping..." << endl;
return true;
}
// Configure heartbeat for GEV camera
#ifdef _DEBUG
result &= DisableGVCPHeartbeat(pCam);
#else
result &= ResetGVCPHeartbeat(pCam);
#endif
// Camera Stereo Parameters can be configured while camera is acquiring images, but
// enabling/disabling stream components is only possible before camera begins image acquisition
cout << endl << "Configuring camera..." << endl;
result &= SpinStereo::ConfigureAcquisition(pCam, stereoParameters.streamTransmitFlags);
cout << endl << "Configuring chunk data..." << endl;
result &= ConfigureChunkData(nodeMap);
cout << endl << "Configuring device link throughput..." << endl;
result &= SetDeviceLinkThroughput(pCam);
cout << endl << "Configuring stereo processing..." << endl;
result &= SpinStereo::ConfigureStereoProcessing(nodeMap, stereoParameters);
cout << endl << "*** STEREO PARAMETERS *** " << endl << stereoParameters.ToString() << endl;
#if _DEBUG
cout << endl << "*** CAMERA CALIBRATION PARAMETERS ***" << endl;
{
cerr << "Failed to get camera calibration parameters." << endl;
return false;
}
#endif
// Acquire images
cout << endl << "Acquiring images..." << endl;
result &= AcquireImages(pCam, stereoParameters, numImageSets);
#ifdef _DEBUG
// Reset heartbeat for GEV camera
result &= ResetGVCPHeartbeat(pCam);
#endif
// Disable chunk data after acquisition
DisableChunkData(nodeMap);
// Deinitialize camera
pCam->DeInit();
}
{
cout << "Error: " << e.what() << endl;
result = false;
}
return result;
}
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");
// determine cmd line arguments
StereoAcquisitionParams stereoAcquisitionParams;
if (!ProcessArgs(argc, argv, stereoAcquisitionParams))
{
return -1;
}
StereoParameters stereoParameters;
StreamTransmitFlags& streamTransmitFlags = stereoParameters.streamTransmitFlags;
streamTransmitFlags.rawSensor1TransmitEnabled = stereoAcquisitionParams.doEnableRawSensor1Transmit;
streamTransmitFlags.rawSensor2TransmitEnabled = stereoAcquisitionParams.doEnableRawSensor2Transmit;
streamTransmitFlags.rectSensor1TransmitEnabled = stereoAcquisitionParams.doEnableRectSensor1Transmit;
streamTransmitFlags.rectSensor2TransmitEnabled = stereoAcquisitionParams.doEnableRectSensor2Transmit;
streamTransmitFlags.disparityTransmitEnabled = stereoAcquisitionParams.doEnableDisparityTransmit;
stereoParameters.doComputePointCloud = stereoAcquisitionParams.doEnablePointCloudOutput;
stereoParameters.postProcessDisparity = stereoAcquisitionParams.doEnableDisparityPostProcessing;
// Print application build information
cout << "Application build date: " << __DATE__ << " " << __TIME__ << endl << endl;
// 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 cameras from the system
CameraList camList = system->GetCameras();
const 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();
// Release system
system->ReleaseInstance();
cout << "Not enough cameras!" << endl;
cout << "Done! Press Enter to exit..." << endl;
getchar();
return -1;
}
//
// Create shared pointer to camera
//
// *** NOTES ***
// The CameraPtr object is a shared pointer, and will generally clean itself
// up upon exiting its scope. However, if a shared pointer is created in the
// same scope that a system object is explicitly released (i.e. this scope),
// the reference to the shared point must be broken manually.
//
// *** LATER ***
// Shared pointers can be terminated manually by assigning them to nullptr.
// This keeps releasing the system from throwing an exception.
//
CameraPtr pCam = nullptr;
bool result = true;
// Run example on each camera
for (unsigned int i = 0; i < numCameras; i++)
{
// Select camera
pCam = camList.GetByIndex(i);
cout << endl << "Running example for camera " << i << "..." << endl;
// Run example
result &= RunSingleCamera(pCam, stereoParameters, stereoAcquisitionParams.numImageSets);
cout << "Camera " << i << " example complete..." << endl << endl;
}
//
// Release reference to the camera
//
// *** NOTES ***
// Had the CameraPtr object been created within the for-loop, it would not
// be necessary to manually break the reference because the shared pointer
// would have automatically cleaned itself up upon exiting the loop.
//
pCam = nullptr;
// Clear camera list before releasing system
camList.Clear();
// Release system
system->ReleaseInstance();
cout << endl << "Done! Press Enter to exit..." << endl;
getchar();
return (result == true) ? 0 : -1;
}
int AcquireImages(CameraPtr pCam, INodeMap &nodeMap, INodeMap &nodeMapTLDevice)
Definition Acquisition.cpp:200
int main(int, char **)
Definition Acquisition.cpp:536
int ResetGVCPHeartbeat(CameraPtr pCam)
Definition Acquisition.cpp:139
int RunSingleCamera(CameraPtr pCam)
Definition Acquisition.cpp:488
int PrintDeviceInfo(INodeMap &nodeMap)
Definition Acquisition.cpp:442
int DisableGVCPHeartbeat(CameraPtr pCam)
Definition Acquisition.cpp:144
int DisplayChunkData(ImagePtr pImage)
Definition ChunkData.cpp:195
int ConfigureChunkData(INodeMap &nodeMap)
Definition ChunkData.cpp:71
int DisableChunkData(INodeMap &nodeMap)
Definition ChunkData.cpp:550
int GetOption(int argc, char **argv, const char *pszValidOpts, const char **ppszParam)
Definition Getopt.c:96
bool SetDeviceLinkThroughput(CameraPtr pCam)
Definition StereoAcquisition.cpp:647
bool ProcessArgs(int argc, char *argv[], StereoAcquisitionParams &params)
ProcessArgs.
Definition StereoAcquisition.cpp:75
bool Compute3DPointCloudAndSave(const StereoParameters &stereoParameters, ImageList &imageList, int counter, string prefix="")
Compute3DPointCloudAndSave.
Definition StereoAcquisition.cpp:542
void DisplayHelp(const string &pszProgramName, const StereoAcquisitionParams &params)
DisplayHelp.
Definition StereoAcquisition.cpp:200
bool SaveImagesToFile(const StreamTransmitFlags &streamTransmitFlags, ImageList &imageList, int counter, const string prefix="")
Definition StereoAcquisition.cpp:584
Class for handling parameters of the S3D camera.
Definition StereoParameters.h:66
std::string ToString() const
Converts the parameters to a string representation.
Definition StereoParameters.cpp:48
bool doComputePointCloud
flag to enable computation of the 3D point cloud.
Definition StereoParameters.h:86
StreamTransmitFlags streamTransmitFlags
Flags to enable streams image transmission.
Definition StereoParameters.h:84
float scan3dBaseline
Definition StereoParameters.h:100
float scan3dCoordinateOffset
Minimum number of disparities.
Definition StereoParameters.h:79
unsigned int totalDisparity
Number of disparities.
Definition StereoParameters.h:80
float scan3dPrincipalPointV
Definition StereoParameters.h:101
float scan3dInvalidDataValue
Definition StereoParameters.h:82
float scan3dPrincipalPointU
Definition StereoParameters.h:102
float scan3dFocalLength
Definition StereoParameters.h:99
float scan3dCoordinateScale
Definition StereoParameters.h:105
bool scan3dInvalidDataFlag
Definition StereoParameters.h:81
bool postProcessDisparity
Flag to enable disparity post-processing.
Definition StereoParameters.h:92
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 chunk data which contains additional information about an image.
Definition ChunkData.h:42
float64_t GetScan3dBaseline() const
Description: Returns the baseline as the physical distance of two cameras in a stereo camera setup.
float64_t GetScan3dCoordinateOffset() const
Description: Returns the Offset for the selected coordinate axis of the image included in the payload...
int64_t GetStereoWidth() const
Description: Returns the width of the image after stereo processing by the device (in pixels).
int64_t GetSmallPenalty() const
Description: Returns the penalty when the change of Disparity Change is plus or minus 1.
int64_t GetLargePenalty() const
Description: Returns the penalty when the change of Disparity Change is plus or minus 1.
float64_t GetMinZ() const
Description: Returns the minimum depth in meters for the point cloud range.
int64_t GetStereoHeight() const
Description: Returns the height of the image after stereo processing by the device (in pixels).
float64_t GetScan3dPrincipalPointV() const
Description: Returns the value of this feature gives the vertical position of the principal point,...
float64_t GetScan3dPrincipalPointU() const
Description: Returns the value of this feature gives the horizontal position of the principal point,...
int64_t GetUniquenessRatio() const
Description: Returns the difference between the best matching disparity and the second-best matching ...
float64_t GetMaxZ() const
Description: Returns the maximum depth in meters for the point cloud range.
float64_t GetExposureTime() const
Description: Returns the exposure time used to capture the image.
float64_t GetScan3dFocalLength() const
Description: Returns the focal length of the camera in pixel.
int64_t GetFrameID() const
Description: Returns the image frame ID.
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().
Encapsulates a GenApi pointer dealing with the dynamic_cast automatically.
Definition Pointer.h:75
Definition GCString.h:43
Used to hold a list of image objects.
Definition ImageList.h:42
ImagePtr GetByIndex(unsigned int index) const
Returns a pointer to an image object at the "index".
ImagePtr GetByPayloadType(const ImagePayloadType payloadType) const
Returns a pointer to an image object with the specified image payload type.
unsigned int GetSize() const
Returns the size of the image list.
A reference tracked pointer to an image object.
Definition ImagePtr.h:46
static PointCloud ComputePointCloud(const ImagePtr &disparityImage, const ImagePtr &rectifiedImage, const PointCloudParameters &pointCloudParameters, const StereoCameraParameters &stereoCameraParameters)
Computes 3D point cloud from a stereo pair consisting of a disparity/rectified image using a stereo m...
The PointCloud object class.
Definition PointCloud.h:46
A reference tracked pointer to a system object.
Definition SystemPtr.h:44
double float64_t
64 bit floating point
Definition GCTypes.h:261
bool IsWritable(EAccessMode AccessMode)
Tests if writable.
Definition INode.h:277
bool IsAvailable(EAccessMode AccessMode)
Tests if available.
Definition INode.h:325
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
void SavePointCloudAsPly(const std::string &) const
The function writes the point cloud data to the specified file in PLY format.
node_vector NodeList_t
a list of node references
Definition INode.h:54
bool PrintCameraCalibrationParams(INodeMap &nodeMap)
Prints the camera calibration parameters.
Definition SpinStereoHelper.cpp:956
Definition SpinStereoHelper.cpp:34
bool ValidateImageList(const StreamTransmitFlags &streamTransmitFlags, ImageList &imageList)
Definition SpinStereoHelper.cpp:765
bool ConfigureAcquisition(CameraPtr pCam, StreamTransmitFlags &streamTransmitFlags)
Definition SpinStereoHelper.cpp:249
bool ConfigureStereoProcessing(INodeMap &nodeMap, StereoParameters &stereoParameters)
Definition SpinStereoHelper.cpp:226
Definition AutoPollController.h:33
Definition GCString.h:31
Definition BasePtr.h:24
Definition StereoParameters.h:40
bool rawSensor1TransmitEnabled
Flag to enable raw sensor1 image transmission.
Definition StereoParameters.h:41
bool rawSensor2TransmitEnabled
Flag to enable raw sensor2 image transmission.
Definition StereoParameters.h:42
bool rectSensor1TransmitEnabled
Flag to enable rectified sensor1 image transmission.
Definition StereoParameters.h:43
bool disparityTransmitEnabled
Flag to enable disparity image transmission.
Definition StereoParameters.h:45
bool rectSensor2TransmitEnabled
Flag to enable rectified sensor2 image transmission.
Definition StereoParameters.h:44
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
Definition SpinnakerDefs.h:790
unsigned int ROIImageTop
Definition SpinnakerDefs.h:800
unsigned int ROIImageLeft
Definition SpinnakerDefs.h:796
unsigned int decimationFactor
Definition SpinnakerDefs.h:793
unsigned int ROIImageBottom
Definition SpinnakerDefs.h:806
unsigned int ROIImageRight
Definition SpinnakerDefs.h:803
Definition SpinnakerDefs.h:848
float invalidDataValue
Definition SpinnakerDefs.h:855
float disparityScaleFactor
Definition SpinnakerDefs.h:854
float principalPointV
Definition SpinnakerDefs.h:853
float focalLength
Definition SpinnakerDefs.h:851
float principalPointU
Definition SpinnakerDefs.h:852
bool invalidDataFlag
Definition SpinnakerDefs.h:856
unsigned int totalDisparity
Definition SpinnakerDefs.h:857
float baseline
Definition SpinnakerDefs.h:850
float coordinateOffset
Definition SpinnakerDefs.h:849
Definition StereoAcquisition.h:32
bool doEnableDisparityPostProcessing
Definition StereoAcquisition.h:40
bool doEnableRectSensor2Transmit
Definition StereoAcquisition.h:37
bool doEnableRawSensor1Transmit
Definition StereoAcquisition.h:34
unsigned int numImageSets
Definition StereoAcquisition.h:33
bool doEnableRawSensor2Transmit
Definition StereoAcquisition.h:35
bool doEnablePointCloudOutput
Definition StereoAcquisition.h:39
bool doEnableDisparityTransmit
Definition StereoAcquisition.h:38
bool doEnableRectSensor1Transmit
Definition StereoAcquisition.h:36