Spinnaker C++
2.6.0.0
Inference.cpp

Inference.cpp shows how to perform the following:

Inference is only available for Firefly deep learning cameras. See the related content section on the Firefly DL product page for relevant documentation.

https://www.flir.com/products/firefly-dl/

It can also be helpful to familiarize yourself with the Acquisition, ChunkData and FileAccess_QuickSpin examples.

//=============================================================================
// Copyright (c) 2001-2021 FLIR Systems, 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 <iostream>
#include <fstream>
using namespace Spinnaker;
using namespace Spinnaker::GenApi;
using namespace Spinnaker::GenICam;
using namespace std;
// Use the following enum and global constant to select whether inference network
// type is Detection or Classification.
{
};
// Use the following enum and global constant to select whether uploaded inference
// network and injected image should be written to camera flash or DDR
{
FLASH, // Slower upload but data persists after power cycling the camera
DDR // Faster upload but data clears after power cycling the camera
};
// The example provides two existing custom networks that can be uploaded
// on to the camera to demonstrate classification and detection capabilities.
// "Network_Classification" file is created with Tensorflow using a mobilenet
// neural network for classifying flowers.
// "Network_Detection" file is created with Caffe using mobilenet SSD network
// for people object detection.
// Note: Make sure these files exist on the system and are accessible by the example
const std::string networkFilePath =
(chosenInferenceNetworkType == CLASSIFICATION ? "Network_Classification" : "Network_Detection");
// The example provides two raw images that can be injected into the camera
// to demonstrate camera inference classification and detection capabilities. Jpeg
// representation of the raw images can be found packaged with the example with
// the names "Injected_Image_Classification_Daisy.jpg" and "Injected_Image_Detection_Aeroplane.jpg".
// Note: Make sure these files exist on the system and are accessible by the example
const std::string injectedImageFilePath =
(chosenInferenceNetworkType == CLASSIFICATION ? "Injected_Image_Classification.raw"
: "Injected_Image_Detection.raw");
// The injected images have different ROI sizes so the camera needs to be
// configured to the appropriate width and height to match the injected image
const unsigned int injectedImageWidth = (chosenInferenceNetworkType == CLASSIFICATION ? 640 : 720);
const unsigned int injectedImageHeight = (chosenInferenceNetworkType == CLASSIFICATION ? 400 : 540);
// The sample classification inference network file was trained with the following
// data set labels
// Note: This list should match the list of labels used during the training
// stage of the network file
const char* arrayLabelClassification[] = {"daisy", "dandelion", "roses", "sunflowers", "tulips"};
// The sample detection inference network file was trained with the following
// data set labels
// Note: This list should match the list of labels used during the training
// stage of the network file
const char* arrayLabelDetection[] = {"background", "aeroplane", "bicycle", "bird", "boat", "bottle",
"bus", "car", "cat", "chair", "cow", "diningtable",
"dog", "horse", "motorbike", "person", "pottedplant", "sheep",
"sofa", "train", "monitor"};
const std::vector<std::string> labelDetection(arrayLabelDetection, end(arrayLabelDetection));
// 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 result = 0;
cout << endl << "*** DEVICE INFORMATION ***" << endl << endl;
try
{
FeatureList_t features;
const CCategoryPtr category = nodeMap.GetNode("DeviceInformation");
if (IsReadable(category))
{
category->GetFeatures(features);
for (FeatureList_t::const_iterator it = features.begin(); it != features.end(); ++it)
{
CNodePtr pfeatureNode = *it;
cout << pfeatureNode->GetName() << " : ";
CValuePtr pValue = static_cast<CValuePtr>(pfeatureNode);
cout << (IsReadable(pValue) ? pValue->ToString() : "Node not readable");
cout << endl;
}
}
else
{
cout << "Device control information not available." << endl;
}
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// This function executes a file delete operation on the camera.
bool CameraDeleteFile(INodeMap& nodeMap)
{
bool result = true;
CIntegerPtr ptrFileSize = nodeMap.GetNode("FileSize");
if (!IsReadable(ptrFileSize))
{
cout << "Unable to query FileSize. Aborting..." << endl;
return false;
}
if (ptrFileSize->GetValue() == 0)
{
// No file uploaded yet, skip delete
cout << "No files found, skipping file deletion." << endl;
return true;
}
cout << "Deleting file..." << endl;
try
{
CEnumerationPtr ptrFileOperationSelector = nodeMap.GetNode("FileOperationSelector");
if (!IsWritable(ptrFileOperationSelector))
{
cout << "Unable to configure FileOperationSelector. Aborting..." << endl;
return false;
}
CEnumEntryPtr ptrFileOperationDelete = ptrFileOperationSelector->GetEntryByName("Delete");
if (!IsReadable(ptrFileOperationDelete))
{
cout << "Unable to configure FileOperationSelector Delete. Aborting..." << endl;
return false;
}
ptrFileOperationSelector->SetIntValue(static_cast<int64_t>(ptrFileOperationDelete->GetNumericValue()));
CCommandPtr ptrFileOperationExecute = nodeMap.GetNode("FileOperationExecute");
if (!IsWritable(ptrFileOperationExecute))
{
cout << "Unable to configure FileOperationExecute. Aborting..." << endl;
return false;
}
ptrFileOperationExecute->Execute();
CEnumerationPtr ptrFileOperationStatus = nodeMap.GetNode("FileOperationStatus");
if (!IsReadable(ptrFileOperationStatus))
{
cout << "Unable to query FileOperationStatus. Aborting..." << endl;
return false;
}
CEnumEntryPtr ptrFileOperationStatusSuccess = ptrFileOperationStatus->GetEntryByName("Success");
if (!IsReadable(ptrFileOperationStatusSuccess))
{
cout << "Unable to query FileOperationStatus Success. Aborting..." << endl;
return false;
}
if (ptrFileOperationStatus->GetCurrentEntry() != ptrFileOperationStatusSuccess)
{
cout << "Failed to delete file! File Operation Status : "
<< ptrFileOperationStatus->GetCurrentEntry()->GetSymbolic() << endl;
return false;
}
}
{
cout << "Unexpected exception : " << e.what() << endl;
result = false;
}
return result;
}
// This function executes file open/write on the camera, sets the uploaded file persistence
// and attempt to set FileAccessLength to FileAccessBufferNode length to speed up the write.
bool CameraOpenFile(INodeMap& nodeMap)
{
bool result = true;
cout << "Opening file for writing..." << endl;
try
{
CEnumerationPtr ptrFileOperationSelector = nodeMap.GetNode("FileOperationSelector");
if (!IsWritable(ptrFileOperationSelector))
{
cout << "Unable to configure FileOperationSelector. Aborting..." << endl;
return false;
}
CEnumEntryPtr ptrFileOperationOpen = ptrFileOperationSelector->GetEntryByName("Open");
if (!IsReadable(ptrFileOperationOpen))
{
cout << "Unable to configure FileOperationSelector Open. Aborting..." << endl;
return false;
}
ptrFileOperationSelector->SetIntValue(static_cast<int64_t>(ptrFileOperationOpen->GetNumericValue()));
CEnumerationPtr ptrFileOpenMode = nodeMap.GetNode("FileOpenMode");
if (!IsWritable(ptrFileOpenMode))
{
cout << "Unable to configure ptrFileOpenMode. Aborting..." << endl;
return false;
}
CEnumEntryPtr ptrFileOpenModeWrite = ptrFileOpenMode->GetEntryByName("Write");
if (!IsReadable(ptrFileOpenModeWrite))
{
cout << "Unable to configure FileOperationSelector Write. Aborting..." << endl;
return false;
}
ptrFileOpenMode->SetIntValue(static_cast<int64_t>(ptrFileOpenModeWrite->GetNumericValue()));
CCommandPtr ptrFileOperationExecute = nodeMap.GetNode("FileOperationExecute");
if (!IsWritable(ptrFileOperationExecute))
{
cout << "Unable to configure FileOperationExecute. Aborting..." << endl;
return false;
}
ptrFileOperationExecute->Execute();
CEnumerationPtr ptrFileOperationStatus = nodeMap.GetNode("FileOperationStatus");
if (!IsReadable(ptrFileOperationStatus))
{
cout << "Unable to query FileOperationStatus. Aborting..." << endl;
return false;
}
CEnumEntryPtr ptrFileOperationStatusSuccess = ptrFileOperationStatus->GetEntryByName("Success");
if (!IsReadable(ptrFileOperationStatusSuccess))
{
cout << "Unable to query FileOperationStatus Success. Aborting..." << endl;
return false;
}
if (ptrFileOperationStatus->GetCurrentEntry() != ptrFileOperationStatusSuccess)
{
cout << "Failed to open file for writing!" << endl;
return false;
}
// Set file upload persistence settings
CBooleanPtr ptrFileWriteToFlash = nodeMap.GetNode("FileWriteToFlash");
if (IsWritable(ptrFileWriteToFlash))
{
{
ptrFileWriteToFlash->SetValue(true);
cout << "FileWriteToFlash is set to true" << endl;
}
else
{
ptrFileWriteToFlash->SetValue(false);
cout << "FileWriteToFlash is set to false" << endl;
}
}
// Attempt to set FileAccessLength to FileAccessBufferNode length to speed up the write
CIntegerPtr ptrFileAccessLength = nodeMap.GetNode("FileAccessLength");
if (!IsReadable(ptrFileAccessLength) || !IsWritable(ptrFileAccessLength))
{
cout << "Unable to query/configure FileAccessLength. Aborting..." << endl;
return false;
}
CRegisterPtr ptrFileAccessBuffer = nodeMap.GetNode("FileAccessBuffer");
if (!IsReadable(ptrFileAccessBuffer))
{
cout << "Unable to query FileAccessBuffer. Aborting..." << endl;
return false;
}
if (ptrFileAccessLength->GetValue() < ptrFileAccessBuffer->GetLength())
{
try
{
ptrFileAccessLength->SetValue(ptrFileAccessBuffer->GetLength());
}
{
cout << "Unable to set FileAccessLength to FileAccessBuffer length : " << e.what();
}
}
// Set File Access Offset to zero
CIntegerPtr ptrFileAccessOffset = nodeMap.GetNode("FileAccessOffset");
if (!IsReadable(ptrFileAccessOffset) || !IsWritable(ptrFileAccessOffset))
{
cout << "Unable to query/configure ptrFileAccessOffset. Aborting..." << endl;
return false;
}
ptrFileAccessOffset->SetValue(0);
}
{
cout << "Unexpected exception : " << e.what();
result = false;
}
return result;
}
// This function executes a file write operation on the camera.
{
bool result = true;
try
{
CEnumerationPtr ptrFileOperationSelector = nodeMap.GetNode("FileOperationSelector");
if (!IsWritable(ptrFileOperationSelector))
{
cout << "Unable to configure FileOperationSelector. Aborting..." << endl;
return false;
}
CEnumEntryPtr ptrFileOperationWrite = ptrFileOperationSelector->GetEntryByName("Write");
if (!IsReadable(ptrFileOperationWrite))
{
cout << "Unable to configure FileOperationSelector Write. Aborting..." << endl;
return false;
}
ptrFileOperationSelector->SetIntValue(static_cast<int64_t>(ptrFileOperationWrite->GetNumericValue()));
CCommandPtr ptrFileOperationExecute = nodeMap.GetNode("FileOperationExecute");
if (!IsWritable(ptrFileOperationExecute))
{
cout << "Unable to configure FileOperationExecute. Aborting..." << endl;
return false;
}
ptrFileOperationExecute->Execute();
CEnumerationPtr ptrFileOperationStatus = nodeMap.GetNode("FileOperationStatus");
if (!IsReadable(ptrFileOperationStatus))
{
cout << "Unable to query FileOperationStatus. Aborting..." << endl;
return false;
}
CEnumEntryPtr ptrFileOperationStatusSuccess = ptrFileOperationStatus->GetEntryByName("Success");
if (!IsReadable(ptrFileOperationStatusSuccess))
{
cout << "Unable to query FileOperationStatus Success. Aborting..." << endl;
return false;
}
if (ptrFileOperationStatus->GetCurrentEntry() != ptrFileOperationStatusSuccess)
{
cout << "Failed to write to file!" << endl;
return false;
}
}
{
cout << "Unexpected exception : " << e.what();
result = false;
}
return result;
}
// This function executes a file close operation on the camera.
bool CameraCloseFile(INodeMap& nodeMap)
{
bool result = true;
cout << "Closing file..." << endl;
try
{
CEnumerationPtr ptrFileOperationSelector = nodeMap.GetNode("FileOperationSelector");
if (!IsWritable(ptrFileOperationSelector))
{
cout << "Unable to configure FileOperationSelector. Aborting..." << endl;
return false;
}
CEnumEntryPtr ptrFileOperationClose = ptrFileOperationSelector->GetEntryByName("Close");
if (!IsReadable(ptrFileOperationClose))
{
cout << "Unable to configure FileOperationSelector Close. Aborting..." << endl;
return false;
}
ptrFileOperationSelector->SetIntValue((int64_t)ptrFileOperationClose->GetNumericValue());
CCommandPtr ptrFileOperationExecute = nodeMap.GetNode("FileOperationExecute");
if (!IsWritable(ptrFileOperationExecute))
{
cout << "Unable to configure FileOperationExecute. Aborting..." << endl;
return false;
}
ptrFileOperationExecute->Execute();
CEnumerationPtr ptrFileOperationStatus = nodeMap.GetNode("FileOperationStatus");
if (!IsReadable(ptrFileOperationStatus))
{
cout << "Unable to query FileOperationStatus. Aborting..." << endl;
return false;
}
CEnumEntryPtr ptrFileOperationStatusSuccess = ptrFileOperationStatus->GetEntryByName("Success");
if (!IsReadable(ptrFileOperationStatusSuccess))
{
cout << "Unable to query FileOperationStatus Success. Aborting..." << endl;
return false;
}
if (ptrFileOperationStatus->GetCurrentEntry() != ptrFileOperationStatusSuccess)
{
cout << "Failed to close file!" << endl;
return false;
}
}
{
cout << "Unexpected exception : " << e.what();
result = false;
}
return result;
}
// This function loads a file given a file path on the system into memory.
std::vector<char> LoadFileIntoMemory(const string& filename)
{
ifstream ifs(filename, ios::binary | ios::ate | ios::in);
if (ifs.fail())
{
cout << "Failed to open " << filename << endl;
std::vector<char> data;
return data;
}
const ifstream::pos_type pos = ifs.tellg();
std::vector<char> data(static_cast<unsigned int>(pos));
ifs.seekg(0, ios::beg);
ifs.read(&data[0], pos);
return data;
}
// This function uploads a file on the system to the camera given the selected
// file selector entry.
int UploadFileToCamera(INodeMap& nodeMap, const std::string& fileSelectorEntryName, const std::string& filePath)
{
cout << endl << endl << "*** CONFIGURING FILE SELECTOR ***" << endl << endl;
CEnumerationPtr ptrFileSelector = nodeMap.GetNode("FileSelector");
if (!IsWritable(ptrFileSelector))
{
cout << "Unable to configure FileSelector. Aborting..." << endl;
return -1;
}
CEnumEntryPtr ptrInferenceSelectorEntry = ptrFileSelector->GetEntryByName(fileSelectorEntryName.c_str());
if (!IsReadable(ptrInferenceSelectorEntry))
{
cout << "Unable to query FileSelector entry " << fileSelectorEntryName << ". Aborting..." << endl;
return -1;
}
// Set file selector to entry
cout << "Setting FileSelector to " << ptrInferenceSelectorEntry->GetSymbolic() << "..." << endl;
ptrFileSelector->SetIntValue(static_cast<int64_t>(ptrInferenceSelectorEntry->GetNumericValue()));
// Delete file on camera before writing in case camera runs out of space
if (CameraDeleteFile(nodeMap) != true)
{
cout << "Failed to delete existing file for selector entry " << ptrInferenceSelectorEntry->GetSymbolic()
<< ". Aborting..." << endl;
return -1;
}
// Open file on camera for write
if (CameraOpenFile(nodeMap) != true)
{
// File may not be closed properly last time
// Close and re-open again
if (!CameraCloseFile(nodeMap))
{
// It fails to close the file. Abort!
cout << "Problem opening file node. Aborting..." << endl;
return -1;
}
// File was closed. Open again.
if (!CameraOpenFile(nodeMap))
{
// Fails again. Abort!
cout << "Problem opening file node. Aborting..." << endl;
return -1;
}
}
CIntegerPtr ptrFileAccessLength = nodeMap.GetNode("FileAccessLength");
if (!IsReadable(ptrFileAccessLength) || !IsWritable(ptrFileAccessLength))
{
cout << "Unable to query FileAccessLength. Aborting..." << endl;
return -1;
}
CRegisterPtr ptrFileAccessBuffer = nodeMap.GetNode("FileAccessBuffer");
if (!IsReadable(ptrFileAccessBuffer) || !IsWritable(ptrFileAccessBuffer))
{
cout << "Unable to query FileAccessBuffer. Aborting..." << endl;
return -1;
}
CIntegerPtr ptrFileAccessOffset = nodeMap.GetNode("FileAccessOffset");
if (!IsReadable(ptrFileAccessOffset) || !IsWritable(ptrFileAccessOffset))
{
cout << "Unable to query FileAccessOffset. Aborting..." << endl;
return -1;
}
CIntegerPtr ptrFileOperationResult = nodeMap.GetNode("FileOperationResult");
if (!IsReadable(ptrFileOperationResult))
{
cout << "Unable to query FileOperationResult. Aborting..." << endl;
return -1;
}
// Load network file from path depending on network type
std::vector<char> fileBytes = LoadFileIntoMemory(filePath);
if (fileBytes.size() == 0)
{
cout << "Failed to load file path : " << filePath << ". Aborting..." << endl;
return -1;
}
// Compute number of write operations required
const int64_t totalBytesToWrite = fileBytes.size();
int64_t intermediateBufferSize = ptrFileAccessLength->GetValue();
const int64_t writeIterations =
(totalBytesToWrite / intermediateBufferSize) + (totalBytesToWrite % intermediateBufferSize == 0 ? 0 : 1);
if (totalBytesToWrite == 0)
{
cout << "Empty Image. No data will be written to camera. Aborting..." << endl;
return -1;
}
cout << "Start uploading \"" << filePath << "\" to device..." << endl;
cout << "Total Bytes to write : " << to_string(static_cast<long long>(totalBytesToWrite)) << endl;
cout << "FileAccessLength : " << to_string(static_cast<long long>(intermediateBufferSize)) << endl;
cout << "Write Iterations : " << to_string(static_cast<long long>(writeIterations)) << endl;
int64_t index = 0;
int64_t bytesLeftToWrite = totalBytesToWrite;
int64_t totalBytesWritten = 0;
bool paddingRequired = false;
int numPaddings = 0;
cout << "Writing data to device..." << endl;
char* pFileData = fileBytes.data();
for (unsigned int i = 0; i < writeIterations; i++)
{
// Check whether padding is required
if (intermediateBufferSize > bytesLeftToWrite)
{
// Check for multiple of 4 bytes
const unsigned int remainder = bytesLeftToWrite % 4;
if (remainder != 0)
{
paddingRequired = true;
numPaddings = 4 - remainder;
}
}
// Setup data to write
const int64_t tmpBufferSize =
intermediateBufferSize <= bytesLeftToWrite ? intermediateBufferSize : (bytesLeftToWrite + numPaddings);
std::unique_ptr<unsigned char> tmpBuffer(new unsigned char[static_cast<unsigned int>(tmpBufferSize)]);
memcpy(
tmpBuffer.get(),
&pFileData[index],
static_cast<size_t>(
(intermediateBufferSize <= bytesLeftToWrite) ? intermediateBufferSize : bytesLeftToWrite));
if (paddingRequired)
{
// Fill padded bytes
for (int j = 0; j < numPaddings; j++)
{
unsigned char* pTmpBuffer = tmpBuffer.get();
pTmpBuffer[bytesLeftToWrite + j] = 255;
}
}
// Update index for next write iteration
index = index + (intermediateBufferSize <= bytesLeftToWrite ? intermediateBufferSize : bytesLeftToWrite);
// Write to FileAccessBufferNode
ptrFileAccessBuffer->Set(tmpBuffer.get(), tmpBufferSize);
if (intermediateBufferSize > bytesLeftToWrite)
{
// Update FileAccessLength node appropriately to prevent garbage data outside the range of
// the uploaded file to be written to the camera
ptrFileAccessLength->SetValue(bytesLeftToWrite);
}
// Perform Write command
if (!CameraWriteToFile(nodeMap))
{
cout << "Writing to stream failed! Aborting..." << endl;
return -1;
}
// Verify size of bytes written
const int64_t sizeWritten = ptrFileOperationResult->GetValue();
// Keep track of total bytes written
totalBytesWritten += sizeWritten;
// Keep track of bytes left to write
bytesLeftToWrite = totalBytesToWrite - totalBytesWritten;
cout << "Progress : " << (i * 100 / writeIterations) << " %" << '\r' << flush;
}
cout << "Writing complete" << endl;
if (!CameraCloseFile(nodeMap))
{
cout << "Failed to close file!" << endl;
}
return 0;
}
// This function deletes the file uploaded to the camera given the selected
// file selector entry.
int DeleteFileOnCamera(INodeMap& nodeMap, const std::string& fileSelectorEntryName)
{
cout << endl << endl << "*** CLEANING UP FILE SELECTOR ***" << endl << endl;
CEnumerationPtr ptrFileSelector = nodeMap.GetNode("FileSelector");
if (!IsWritable(ptrFileSelector))
{
cout << "Unable to configure FileSelector. Aborting..." << endl;
return -1;
}
CEnumEntryPtr ptrInferenceSelectorEntry = ptrFileSelector->GetEntryByName(fileSelectorEntryName.c_str());
if (!IsReadable(ptrInferenceSelectorEntry))
{
cout << "Unable to query FileSelector entry " << fileSelectorEntryName << ". Aborting..." << endl;
return -1;
}
// Set file selector to entry
cout << "Setting FileSelector to " << ptrInferenceSelectorEntry->GetSymbolic() << endl;
ptrFileSelector->SetIntValue(static_cast<int64_t>(ptrInferenceSelectorEntry->GetNumericValue()));
// Delete file on camera before writing in case camera runs out of space
if (CameraDeleteFile(nodeMap) != true)
{
cout << "Failed to delete existing file for selector entry " << ptrInferenceSelectorEntry->GetSymbolic()
<< ". Aborting..." << endl;
return -1;
}
return 0;
}
// This function enables or disables the given chunk data type based on
// the specified entry name.
int SetChunkEnable(INodeMap& nodeMap, const gcstring& entryName, const bool enable)
{
int result = 0;
CEnumerationPtr ptrChunkSelector = nodeMap.GetNode("ChunkSelector");
const CEnumEntryPtr ptrEntry = ptrChunkSelector->GetEntryByName(entryName);
if (!IsReadable(ptrEntry))
{
return -1;
}
ptrChunkSelector->SetIntValue(ptrEntry->GetValue());
// Enable the boolean, thus enabling the corresponding chunk data
cout << entryName << " ";
CBooleanPtr ptrChunkEnable = nodeMap.GetNode("ChunkEnable");
if (!IsAvailable(ptrChunkEnable))
{
cout << "not available" << endl;
return -1;
}
if (enable)
{
if (ptrChunkEnable->GetValue())
{
cout << "enabled" << endl;
}
else if (IsWritable(ptrChunkEnable))
{
ptrChunkEnable->SetValue(true);
cout << "enabled" << endl;
}
else
{
cout << "not writable" << endl;
result = -1;
}
}
else
{
if (!ptrChunkEnable->GetValue())
{
cout << "disabled" << endl;
}
else if (IsWritable(ptrChunkEnable))
{
ptrChunkEnable->SetValue(false);
cout << "disabled" << endl;
}
else
{
cout << "not writable" << endl;
result = -1;
}
}
return result;
}
// This function configures the camera to add inference chunk data to each image.
// When chunk data is turned on, the data is made available in both the nodemap
// and each image.
{
int result = 0;
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;
return -1;
}
ptrChunkModeActive->SetValue(true);
cout << "Chunk mode activated..." << endl;
// Enable inference related chunks in chunk data
// Retrieve the chunk data selector node
const CEnumerationPtr ptrChunkSelector = nodeMap.GetNode("ChunkSelector");
if (!IsReadable(ptrChunkSelector))
{
cout << "Unable to retrieve chunk selector (enum retrieval). Aborting..." << endl;
return -1;
}
// Enable chunk data inference Frame Id
result = SetChunkEnable(nodeMap, "InferenceFrameId", true);
if (result == -1)
{
cout << "Unable to enable Inference Frame Id chunk data. Aborting..." << endl;
return result;
}
{
// Detection network type
// Enable chunk data inference bounding box
result = SetChunkEnable(nodeMap, "InferenceBoundingBoxResult", true);
if (result == -1)
{
cout << "Unable to enable Inference Bounding Box chunk data. Aborting..." << endl;
return result;
}
}
else
{
// Classification network type
// Enable chunk data inference result
result = SetChunkEnable(nodeMap, "InferenceResult", true);
if (result == -1)
{
cout << "Unable to enable Inference Result chunk data. Aborting..." << endl;
return result;
}
// Enable chunk data inference confidence
result = SetChunkEnable(nodeMap, "InferenceConfidence", true);
if (result == -1)
{
cout << "Unable to enable Inference Confidence chunk data. Aborting..." << endl;
return result;
}
}
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// This function disables each type of chunk data before disabling chunk data mode.
{
cout << endl << endl << "*** DISABLING CHUNK DATA ***" << endl << endl;
int result = 0;
try
{
// Retrieve the selector node
const CEnumerationPtr ptrChunkSelector = nodeMap.GetNode("ChunkSelector");
if (!IsReadable(ptrChunkSelector))
{
cout << "Unable to retrieve chunk selector. Aborting..." << endl;
return -1;
}
result = SetChunkEnable(nodeMap, "InferenceFrameId", false);
if (result == -1)
{
cout << "Unable to disable Inference Frame Id chunk data. Aborting..." << endl;
return result;
}
{
// Detection network type
// Disable chunk data inference bounding box
result = SetChunkEnable(nodeMap, "InferenceBoundingBoxResult", false);
if (result == -1)
{
cout << "Unable to disable Inference Bounding Box chunk data. Aborting..." << endl;
return result;
}
}
else
{
// Classification network type
// Disable chunk data inference result
result = SetChunkEnable(nodeMap, "InferenceResult", false);
if (result == -1)
{
cout << "Unable to disable Inference Result chunk data. Aborting..." << endl;
return result;
}
// Disable chunk data inference confidence
result = SetChunkEnable(nodeMap, "InferenceConfidence", false);
if (result == -1)
{
cout << "Unable to disable Inference Confidence chunk data. Aborting..." << endl;
return result;
}
}
// Deactivate ChunkMode
CBooleanPtr ptrChunkModeActive = nodeMap.GetNode("ChunkModeActive");
if (!IsWritable(ptrChunkModeActive))
{
cout << "Unable to deactivate chunk mode. Aborting..." << endl;
return -1;
}
ptrChunkModeActive->SetValue(false);
cout << "Chunk mode deactivated..." << endl;
// Disable Inference
CBooleanPtr ptrInferenceEnable = nodeMap.GetNode("InferenceEnable");
if (!IsWritable(ptrInferenceEnable))
{
cout << "Unable to disable inference. Aborting..." << endl;
return -1;
}
ptrInferenceEnable->SetValue(false);
cout << "Inference disabled..." << endl;
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// This function displays the inference-related chunk data from the image.
int DisplayChunkData(const ImagePtr pImage)
{
int result = 0;
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.
//
const ChunkData chunkData = pImage->GetChunkData();
const int64_t inferenceFrameID = chunkData.GetInferenceFrameId();
cout << "\tInference Frame ID: " << inferenceFrameID << endl;
{
const int16_t boxCount = boxResult.GetBoxCount();
cout << "\tInference Bounding Box Result:" << endl;
if (boxCount == 0)
{
cout << "\tNo bounding box" << endl;
}
for (int16_t i = 0; i < boxCount; ++i)
{
const InferenceBoundingBox box = boxResult.GetBoxAt(i);
switch (box.boxType)
{
cout << "\tBox[" << i + 1 << "]: "
<< "Class " << box.classId << " ("
<< (static_cast<uint64_t>(box.classId) < labelDetection.size() ? labelDetection[box.classId]
: "N/A")
<< ") - " << box.confidence * 100 << "% - "
<< "Rectangle ("
<< "X=" << box.rect.topLeftXCoord << ", "
<< "Y=" << box.rect.topLeftYCoord << ", "
<< "W=" << box.rect.bottomRightXCoord - box.rect.topLeftXCoord << ", "
<< "H=" << box.rect.bottomRightYCoord - box.rect.topLeftYCoord << ")" << endl;
break;
cout << "\tBox[" << i + 1 << "]: "
<< "Class " << box.classId << " ("
<< (static_cast<uint64_t>(box.classId) < labelDetection.size() ? labelDetection[box.classId]
: "N/A")
<< ") - " << box.confidence * 100 << "% - "
<< "Circle ("
<< "X=" << box.circle.centerXCoord << ", "
<< "Y=" << box.circle.centerYCoord << ", "
<< "R=" << box.circle.radius << ")" << endl;
break;
cout << "\tBox[" << i + 1 << "]: "
<< "Class " << box.classId << " ("
<< (static_cast<uint64_t>(box.classId) < labelDetection.size() ? labelDetection[box.classId]
: "N/A")
<< ") - " << box.confidence * 100 << "% - "
<< "Rotated Rectangle ("
<< "X1=" << box.rotatedRect.topLeftXCoord << ", "
<< "Y1=" << box.rotatedRect.topLeftYCoord << ", "
<< "X2=" << box.rotatedRect.bottomRightXCoord << ", "
<< "Y2=" << box.rotatedRect.bottomRightYCoord << ", "
<< "angle=" << box.rotatedRect.rotationAngle << ")" << endl;
break;
default:
cout << "\tBox[" << i + 1 << "]: "
<< "Class " << box.classId << " ("
<< (static_cast<uint64_t>(box.classId) < labelDetection.size() ? labelDetection[box.classId]
: "N/A")
<< ") - " << box.confidence * 100 << "% - "
<< "Unknown bounding box type (not supported)" << endl;
break;
}
}
}
else
{
uint64_t inferenceResult = chunkData.GetInferenceResult();
cout << "\tInference Result: " << inferenceResult << " ("
<< (inferenceResult < labelClassification.size()
? labelClassification[static_cast<unsigned int>(inferenceResult)]
: "N/A")
<< ")" << endl;
double inferenceConfidence = chunkData.GetInferenceConfidence();
cout << "\tInference Confidence: " << inferenceConfidence << endl;
}
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// This function disables trigger mode on the camera.
int DisableTrigger(INodeMap& nodeMap)
{
cout << endl << endl << "*** DISABLING TRIGGER ***" << endl << endl;
int result = 0;
try
{
// Configure TriggerMode
CEnumerationPtr ptrTriggerMode = nodeMap.GetNode("TriggerMode");
if (!IsWritable(ptrTriggerMode))
{
cout << "Unable to configure TriggerMode. Aborting..." << endl;
return -1;
}
CEnumEntryPtr ptrTriggerOff = ptrTriggerMode->GetEntryByName("Off");
if (!IsReadable(ptrTriggerOff))
{
cout << "Unable to query TriggerMode Off. Aborting..." << endl;
return -1;
}
cout << "Configure TriggerMode to " << ptrTriggerOff->GetSymbolic() << endl;
ptrTriggerMode->SetIntValue(static_cast<int64_t>(ptrTriggerOff->GetNumericValue()));
}
{
cout << "Unexpected exception : " << e.what();
result = -1;
}
return result;
}
// This function configures camera to run in "inference sync" trigger mode.
{
cout << endl << endl << "*** CONFIGURING TRIGGER ***" << endl << endl;
int result = 0;
try
{
// Configure TriggerSelector
CEnumerationPtr ptrTriggerSelector = nodeMap.GetNode("TriggerSelector");
if (!IsWritable(ptrTriggerSelector))
{
cout << "Unable to configure TriggerSelector. Aborting..." << endl;
return -1;
}
CEnumEntryPtr ptrFrameStart = ptrTriggerSelector->GetEntryByName("FrameStart");
if (!IsReadable(ptrFrameStart))
{
cout << "Unable to query TriggerSelector FrameStart. Aborting..." << endl;
return -1;
}
cout << "Configure TriggerSelector to " << ptrFrameStart->GetSymbolic() << endl;
ptrTriggerSelector->SetIntValue(static_cast<int64_t>(ptrFrameStart->GetNumericValue()));
// Configure TriggerSource
CEnumerationPtr ptrTriggerSource = nodeMap.GetNode("TriggerSource");
if (!IsWritable(ptrTriggerSource))
{
cout << "Unable to configure TriggerSource. Aborting..." << endl;
return -1;
}
CEnumEntryPtr ptrInferenceReady = ptrTriggerSource->GetEntryByName("InferenceReady");
if (!IsReadable(ptrInferenceReady))
{
cout << "Unable to query TriggerSource InferenceReady. Aborting..." << endl;
return -1;
}
cout << "Configure TriggerSource to " << ptrInferenceReady->GetSymbolic() << endl;
ptrTriggerSource->SetIntValue(static_cast<int64_t>(ptrInferenceReady->GetNumericValue()));
// Configure TriggerMode
CEnumerationPtr ptrTriggerMode = nodeMap.GetNode("TriggerMode");
if (!IsWritable(ptrTriggerMode))
{
cout << "Unable to configure TriggerMode. Aborting..." << endl;
return -1;
}
CEnumEntryPtr ptrTriggerOn = ptrTriggerMode->GetEntryByName("On");
if (!IsReadable(ptrTriggerOn))
{
cout << "Unable to query TriggerMode On. Aborting..." << endl;
return -1;
}
cout << "Configure TriggerMode to " << ptrTriggerOn->GetSymbolic() << endl;
ptrTriggerMode->SetIntValue(static_cast<int64_t>(ptrTriggerOn->GetNumericValue()));
}
{
cout << "Unexpected exception : " << e.what();
result = -1;
}
return result;
}
// This function enables/disables inference on the camera and configures the inference network type
int ConfigureInference(INodeMap& nodeMap, bool isEnabled)
{
int result = 0;
if (isEnabled)
{
cout << endl
<< endl
<< "*** CONFIGURING INFERENCE ("
<< ((chosenInferenceNetworkType == DETECTION) ? "DETECTION" : "CLASSIFICATION") << ") ***" << endl
<< endl;
}
else
{
cout << endl << endl << "*** DISABLING INFERENCE ***" << endl << endl;
}
try
{
if (isEnabled)
{
// Set Network Type to Detection
CEnumerationPtr ptrInferenceNetworkTypeSelector = nodeMap.GetNode("InferenceNetworkTypeSelector");
if (!IsWritable(ptrInferenceNetworkTypeSelector))
{
cout << "Unable to query InferenceNetworkTypeSelector. Aborting..." << endl;
return -1;
}
const gcstring networkTypeString =
(chosenInferenceNetworkType == DETECTION) ? "Detection" : "Classification";
// Retrieve entry node from enumeration node
CEnumEntryPtr ptrInferenceNetworkType = ptrInferenceNetworkTypeSelector->GetEntryByName(networkTypeString);
if (!IsReadable(ptrInferenceNetworkType))
{
cout << "Unable to set inference network type to " << networkTypeString
<< " (entry retrieval). Aborting..." << endl
<< endl;
return -1;
}
ptrInferenceNetworkTypeSelector->SetIntValue(
static_cast<int64_t>(ptrInferenceNetworkType->GetNumericValue()));
cout << "Inference network type set to " << networkTypeString << "..." << endl;
}
// Enable/Disable inference
cout << (isEnabled ? "Enabling" : "Disabling") << " inference..." << endl;
CBooleanPtr ptrInferenceEnable = nodeMap.GetNode("InferenceEnable");
if (!IsWritable(ptrInferenceEnable))
{
cout << "Unable to enable inference. Aborting..." << endl;
return -1;
}
ptrInferenceEnable->SetValue(isEnabled);
cout << "Inference " << (isEnabled ? "enabled..." : "disabled...") << endl;
}
{
cout << "Unexpected exception : " << e.what() << endl;
result = -1;
}
return result;
}
// This function configures camera test pattern to make use of the injected test image for inference
int ConfigureTestPattern(INodeMap& nodeMap, bool isEnabled)
{
int result = 0;
if (isEnabled)
{
cout << endl << endl << "*** CONFIGURING TEST PATTERN ***" << endl << endl;
}
else
{
cout << endl << endl << "*** DISABLING TEST PATTERN ***" << endl << endl;
}
try
{
// Set TestPatternGeneratorSelector to PipelineStart
CEnumerationPtr ptrTestPatternGeneratorSelector = nodeMap.GetNode("TestPatternGeneratorSelector");
if (!IsWritable(ptrTestPatternGeneratorSelector))
{
cout << "Unable to query TestPatternGeneratorSelector. Aborting..." << endl;
return -1;
}
if (isEnabled)
{
CEnumEntryPtr ptrTestPatternGeneratorPipelineStart =
ptrTestPatternGeneratorSelector->GetEntryByName("PipelineStart");
if (!IsReadable(ptrTestPatternGeneratorPipelineStart))
{
cout << "Unable to query TestPatternGeneratorSelector PipelineStart. Aborting..." << endl;
return -1;
}
ptrTestPatternGeneratorSelector->SetIntValue(
static_cast<int64_t>(ptrTestPatternGeneratorPipelineStart->GetNumericValue()));
cout << "TestPatternGeneratorSelector set to " << ptrTestPatternGeneratorPipelineStart->GetSymbolic()
<< "..." << endl;
}
else
{
CEnumEntryPtr ptrTestPatternGeneratorSensor = ptrTestPatternGeneratorSelector->GetEntryByName("Sensor");
if (!IsReadable(ptrTestPatternGeneratorSensor))
{
cout << "Unable to query TestPatternGeneratorSelector Sensor. Aborting..." << endl;
return -1;
}
ptrTestPatternGeneratorSelector->SetIntValue(
static_cast<int64_t>(ptrTestPatternGeneratorSensor->GetNumericValue()));
cout << "TestPatternGeneratorSelector set to " << ptrTestPatternGeneratorSensor->GetSymbolic() << "..."
<< endl;
}
// Set TestPattern to InjectedImage
CEnumerationPtr ptrTestPattern = nodeMap.GetNode("TestPattern");
if (!IsWritable(ptrTestPattern))
{
cout << "Unable to query TestPattern. Aborting..." << endl;
return -1;
}
if (isEnabled)
{
CEnumEntryPtr ptrInjectedImage = ptrTestPattern->GetEntryByName("InjectedImage");
if (!IsReadable(ptrInjectedImage))
{
cout << "Unable to query TestPattern InjectedImage. Aborting..." << endl;
return -1;
}
ptrTestPattern->SetIntValue(static_cast<int64_t>(ptrInjectedImage->GetNumericValue()));
cout << "TestPattern set to " << ptrInjectedImage->GetSymbolic() << "..." << endl;
}
else
{
CEnumEntryPtr ptrTestPatternOff = ptrTestPattern->GetEntryByName("Off");
if (!IsReadable(ptrTestPatternOff))
{
cout << "Unable to query TestPattern Off. Aborting..." << endl;
return -1;
}
ptrTestPattern->SetIntValue(static_cast<int64_t>(ptrTestPatternOff->GetNumericValue()));
cout << "TestPattern set to " << ptrTestPatternOff->GetSymbolic() << "..." << endl;
}
if (isEnabled)
{
// The inject images have different ROI sizes so camera needs to be configured to the appropriate
// injected width and height
CIntegerPtr ptrInjectedWidth = nodeMap.GetNode("InjectedWidth");
if (!IsWritable(ptrInjectedWidth))
{
cout << "Unable to query InjectedWidth. Aborting..." << endl;
return -1;
}
ptrInjectedWidth->SetValue(isEnabled ? injectedImageWidth : ptrInjectedWidth->GetMax());
CIntegerPtr ptrInjectedHeight = nodeMap.GetNode("InjectedHeight");
if (!IsWritable(ptrInjectedHeight))
{
cout << "Unable to query InjectedHeight. Aborting..." << endl;
return -1;
}
ptrInjectedHeight->SetValue(isEnabled ? injectedImageHeight : ptrInjectedHeight->GetMax());
}
}
{
cout << "Unexpected exception : " << e.what() << endl;
result = -1;
}
return result;
}
// This function acquires and saves 10 images from a device; please see
// Acquisition example for more in-depth comments on acquiring images.
int AcquireImages(const CameraPtr& pCam, INodeMap& nodeMap, INodeMap& nodeMapTLDevice)
{
int result = 0;
cout << endl << endl << "*** IMAGE ACQUISITION ***" << endl << endl;
try
{
// Set acquisition mode to continuous
CEnumerationPtr ptrAcquisitionMode = nodeMap.GetNode("AcquisitionMode");
if (!IsWritable(ptrAcquisitionMode))
{
cout << "Unable to set acquisition mode to continuous (node retrieval). Aborting..." << endl;
return -1;
}
CEnumEntryPtr ptrAcquisitionModeContinuous = ptrAcquisitionMode->GetEntryByName("Continuous");
if (!IsReadable(ptrAcquisitionModeContinuous))
{
cout << "Unable to set acquisition mode to continuous (entry 'continuous' retrieval). Aborting..." << endl
<< endl;
return -1;
}
const int64_t acquisitionModeContinuous = ptrAcquisitionModeContinuous->GetValue();
ptrAcquisitionMode->SetIntValue(acquisitionModeContinuous);
cout << "Acquisition mode set to continuous..." << endl;
// Begin acquiring images
pCam->BeginAcquisition();
cout << "Acquiring images..." << endl;
// Retrieve device serial number for filename
gcstring deviceSerialNumber("");
CStringPtr ptrStringSerial = nodeMapTLDevice.GetNode("DeviceSerialNumber");
if (IsReadable(ptrStringSerial))
{
deviceSerialNumber = ptrStringSerial->GetValue();
cout << "Device serial number retrieved as " << deviceSerialNumber << "..." << endl;
}
cout << endl;
// Retrieve, convert, and save images
const unsigned int k_numImages = 10;
for (unsigned int imageCnt = 0; imageCnt < k_numImages; imageCnt++)
{
try
{
// Retrieve next received image and ensure image completion
ImagePtr pResultImage = pCam->GetNextImage(1000);
if (pResultImage->IsIncomplete())
{
cout << "Image incomplete with image status " << pResultImage->GetImageStatus() << "..." << endl
<< endl;
}
else
{
// Print image information
cout << "Grabbed image " << imageCnt << ", width = " << pResultImage->GetWidth()
<< ", height = " << pResultImage->GetHeight() << "." << endl;
// Display chunk data
result = DisplayChunkData(pResultImage);
pResultImage->Save("image.jpg");
}
// Release image
pResultImage->Release();
cout << endl;
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
}
// End acquisition
pCam->EndAcquisition();
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// This function acts as the body of the example; please see NodeMapInfo example
// for more in-depth comments on setting up cameras.
int RunSingleCamera(const CameraPtr& pCam)
{
int result = 0;
int err = 0;
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 inference
cout << endl << "Checking camera inference support..." << endl;
CBooleanPtr ptrInferenceEnable = nodeMap.GetNode("InferenceEnable");
if (!IsWritable(ptrInferenceEnable))
{
cout << "Inference is not supported on this camera. Aborting..." << endl;
return -1;
}
// Upload custom inference network onto the camera
// The inference network file is in a movidius specific neural network format.
// Uploading the network to the camera allows for "inference on the edge" where
// camera can apply deep learning on a live stream. Refer to "Getting Started
// with Firefly-DL" for information on how to create your own custom inference
// network files using pre-existing neural network.
err = UploadFileToCamera(nodeMap, "InferenceNetwork", networkFilePath);
if (err < 0)
{
return err;
}
// Upload injected test image
// Instead of applying deep learning on a live stream, the camera can be
// tested with an injected test image.
err = UploadFileToCamera(nodeMap, "InjectedImage", injectedImageFilePath);
if (err < 0)
{
return err;
}
// Configure inference
err = ConfigureInference(nodeMap, true);
if (err < 0)
{
return err;
}
// Configure test pattern to make use of the injected image
err = ConfigureTestPattern(nodeMap, true);
if (err < 0)
{
return err;
}
// Configure trigger
// When enabling inference results via chunk data, the results that accompany a frame
// will likely not be the frame that inference was run on. In order to guarantee that
// the chunk inference results always correspond to the frame that they are sent with,
// the camera needs to be put into the "inference sync" trigger mode.
// Note: Enabling this setting will limit frame rate so that every frame contains new
// inference dataset. To not limit the frame rate, you can enable InferenceFrameID
// chunk data to help determine which frame is associated with a particular
// inference data.
err = ConfigureTrigger(nodeMap);
if (err < 0)
{
return err;
}
// Configure chunk data
err = ConfigureChunkData(nodeMap);
if (err < 0)
{
return err;
}
// Acquire images and display chunk data
result = result | AcquireImages(pCam, nodeMap, nodeMapTLDevice);
// Disable chunk data
err = DisableChunkData(nodeMap);
if (err < 0)
{
return err;
}
// Disable trigger
err = DisableTrigger(nodeMap);
if (err < 0)
{
return err;
}
// Disable test pattern
err = ConfigureTestPattern(nodeMap, false);
if (err < 0)
{
return err;
}
// Disable inference
err = ConfigureInference(nodeMap, false);
if (err < 0)
{
return err;
}
// Clear injected test image
err = DeleteFileOnCamera(nodeMap, "InjectedImage");
if (err < 0)
{
return err;
}
// Clear uploaded inference network
err = DeleteFileOnCamera(nodeMap, "InferenceNetwork");
if (err < 0)
{
return err;
}
// Deinitialize camera
pCam->DeInit();
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// Example entry point; please see Enumeration example for more in-depth
// comments on preparing and cleaning up the system.
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;
// Retrieve singleton reference to system object
// 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;
}
// Run example on each camera
for (unsigned int i = 0; i < numCameras; i++)
{
cout << endl << "Running example for camera " << i << "..." << endl;
result = result | RunSingleCamera(camList.GetByIndex(i));
cout << "Camera " << i << " example complete..." << endl << endl;
}
// Clear camera list before releasing system
camList.Clear();
// Release system
system->ReleaseInstance();
cout << endl << "Done! Press Enter to exit..." << endl;
getchar();
return result;
}
Contact Support Spinnaker® SDK Programmer's Guide and API Reference