parallel-capture-sample.cpp

This advanced example illustrates multithreaded capturing.

The sample code allows you to capture and process 3D frames in a time-efficient manner by employing all available threads.

The files required for compiling this sample are packed in the archive.
Note
The sample requires the Boost library to function. Before building the solution, make sure you have Boost version 1.51.0 installed in the root of your C: disk. If you have already installed a Boost of a different version, please edit the path to the BoostHome variable in the ..\samples\sdk-samples-user.props file. Also, edit the <AdditionalLibraryDirectories> path in ..\samples\sdk-samples-common.props.
/********************************************************************
*
* Project Artec 3D Scanning SDK Samples
*
* Purpose: Parallel capture sample
*
* Copyright: Artec Group
*
********************************************************************/
#include <string>
#include <iostream>
#include <iomanip>
#include <boost/thread.hpp>
#include <boost/chrono.hpp>
#include <boost/format.hpp>
using namespace boost::chrono;
namespace asdk {
using namespace artec::sdk::base;
using namespace artec::sdk::capturing;
};
using asdk::TRef;
using asdk::TArrayRef;
// this constant determines the number of frames to collect.
const int NumberOfFramesToCapture = 100;
int main( int argc, char **argv )
{
// The log verbosity level is set here. It is set to the most
// verbose value - Trace. If you have any problems working with
// our examples, please do not hesitate to send us this extensive
// information along with your questions. However, if you feel
// comfortable with these Artec Scanning SDK code examples,
// we suggest you to set this level to asdk::VerboseLevel_Info.
{
// Look for the scanners attached
std::wcout << L"Enumerating scanners... ";
if( asdk::enumerateScanners( &scannersList ) != asdk::ErrorCode_OK )
{
std::wcout << L"failed" << std::endl;
return 1;
}
std::wcout << L"done" << std::endl;
// Check for any scanners found
if( scannersList->getSize() == 0 )
{
std::wcout << L"No scanners are found" << std::endl;
return 2;
}
// Connect to the first available scanner
TArrayRef<asdk::IArrayScannerId> scannersArray( scannersList );
for( int i = 0; i < scannersArray.size(); i++ )
{
std::wcout << L"Scanner " << scannersArray[i].serial << L" is found" << std::endl;
std::wcout << L"Connecting to the scanner... ";
if( asdk::createScanner( &scanner, &scannersArray[i] ) != asdk::ErrorCode_OK )
{
std::wcout << L"failed" << std::endl;
continue;
}
std::wcout << L"done" << std::endl;
break;
}
if( !scanner )
{
std::wcout << L"No scanner can be connected to" << std::endl;
return 3;
}
}
// Start to work
int framesAlreadyCaptured = scanner->getFrameNumber();
// Storage for the frame meshes constructed
std::vector< TRef<asdk::IFrameMesh> > meshes;
meshes.resize( NumberOfFramesToCapture );
boost::mutex meshesProtection;
std::wcout << L"Capturing " << NumberOfFramesToCapture << " frames with " << boost::thread::hardware_concurrency() << L" threads" << std::endl;
high_resolution_clock::time_point startTime = high_resolution_clock::now();
// Start frame processing for every hard-supported thread available
boost::thread_group captureThreads;
for( unsigned i = 0; i < boost::thread::hardware_concurrency(); i++ )
{
captureThreads.create_thread( [&scanner, &meshes, &meshesProtection, framesAlreadyCaptured]
{
// Initialize a frame processor
if( scanner->createFrameProcessor( &processor ) != asdk::ErrorCode_OK )
{
return;
}
while(true)
{
// Capture the next single frame image
asdk::ErrorCode ec = scanner->capture( &frame, true );
if( ec != asdk::ErrorCode_OK )
{
{
std::wcout << L"Capture error: frame capture timeout" << std::endl;
}
{
std::wcout << L"Capture error: frame corrupted" << std::endl;
}
{
std::wcout << L"Capture error: frame reconstruction failed" << std::endl;
}
{
std::wcout << L"Capture error: frame registration failed" << std::endl;
}
else
{
std::wcout << L"Capture error: unknown error" << std::endl;
}
continue;
}
int frameNumber = frame->getFrameNumber();
if( frameNumber >= NumberOfFramesToCapture + framesAlreadyCaptured )
{
return;
}
std::wcout << "frame " << std::setw( 4 ) << (frameNumber+1) << "\r";
// Reconstruct 3D mesh for the captured frame
if( processor->reconstructAndTexturizeMesh( &mesh, frame ) != asdk::ErrorCode_OK )
{
std::wcout << L"Capture error: reconstruction failed for frame " << std::setw( 4 ) << (frameNumber+1) << std::endl;
continue;
}
// Calculate additional data
mesh->calculate( asdk::CM_Normals );
std::wcout << "mesh " << std::setw( 4 ) << (frameNumber+1) << "\r";
std::wcout.flush();
// Save the mesh for later use
boost::lock_guard<boost::mutex> guard( meshesProtection );
meshes[frameNumber - framesAlreadyCaptured] = mesh;
}
});
}
// Wait for the capture process to finish
captureThreads.join_all();
high_resolution_clock::time_point stopTime = high_resolution_clock::now();
float timeDelta = duration_cast<milliseconds>( stopTime - startTime ).count() / 1000.f;
float fps = NumberOfFramesToCapture / timeDelta;
std::wcout << "\nfps = " << std::fixed << std::setw( 4 ) << std::setprecision( 2 ) << fps << std::endl;
int successfullyCapturedMeshes = 0;
for( int i = 0; i < NumberOfFramesToCapture; i++ )
{
if( meshes[i] )
{
successfullyCapturedMeshes++;
}
}
std::wcout << NumberOfFramesToCapture << " shots captured with " << successfullyCapturedMeshes << " meshes constructed." << std::endl;
scanner = NULL;
std::wcout << L"Scanner released" << std::endl;
return 0;
}