initial verion
This commit is contained in:
237
minimal_pylon.cpp
Normal file
237
minimal_pylon.cpp
Normal file
@@ -0,0 +1,237 @@
|
||||
// Grab_MultipleCameras.cpp
|
||||
/*
|
||||
Note: Before getting started, Basler recommends reading the "Programmer's Guide" topic
|
||||
in the pylon C++ API documentation delivered with pylon.
|
||||
If you are upgrading to a higher major version of pylon, Basler also
|
||||
strongly recommends reading the "Migrating from Previous Versions" topic in the pylon C++ API documentation.
|
||||
|
||||
This sample illustrates how to grab and process images from multiple cameras
|
||||
using the CInstantCameraArray class. The CInstantCameraArray class represents
|
||||
an array of instant camera objects. It provides almost the same interface
|
||||
as the instant camera for grabbing.
|
||||
The main purpose of the CInstantCameraArray is to simplify waiting for images and
|
||||
camera events of multiple cameras in one thread. This is done by providing a single
|
||||
RetrieveResult method for all cameras in the array.
|
||||
Alternatively, the grabbing can be started using the internal grab loop threads
|
||||
of all cameras in the CInstantCameraArray. The grabbed images can then be processed by one or more
|
||||
image event handlers. Please note that this is not shown in this example.
|
||||
*/
|
||||
|
||||
#include <pylon/PylonIncludes.h>
|
||||
#include "stitchimage.h"
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <unistd.h> // for read(), STDIN_FILENO
|
||||
#include <termios.h> // for tcgetattr(), tcsetattr()
|
||||
#include <sys/select.h> // for select()
|
||||
|
||||
using namespace Pylon;
|
||||
using namespace GenApi;
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
|
||||
typedef high_resolution_clock Time;
|
||||
typedef milliseconds ms;
|
||||
typedef duration<float> fsec;
|
||||
|
||||
int main( int argc, char* argv[] ) {
|
||||
uint32_t frameCount = 100;
|
||||
size_t maxCameras = 1;
|
||||
int exitCode = 0;
|
||||
bool stop_request = false;
|
||||
int camCount = 0;
|
||||
int framerate = 20;
|
||||
uint32_t quality = 50;
|
||||
int cWidth = 2000; //2592;
|
||||
int cHeight = 2000; //2048;
|
||||
int camIndex = 0;
|
||||
string errorMessage = "";
|
||||
String_t filename = "_TestVideo.mp4";
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string arg = argv[i];
|
||||
if ((arg == "--help") || arg == "?"){
|
||||
cout << "Expected args:\n"
|
||||
<< "\t --fps|-f \t the framerate, defaults to 20 Hz\n"
|
||||
<< "\t --help|? \t this help\n"
|
||||
<< "\t --width|-w \t the image width in pixel, defaults to 2000\n"
|
||||
<< "\t --height|-h \t the image height in pixel, defaults to 2000\n"
|
||||
<< "\t --cameras|-c \t the desired number of cameras to grab at the same time, defaults to 1\n"
|
||||
<< "\t --framecount|-n \t the number of frames, defaults to 100\n"
|
||||
<< "\t --quality|-q \t the qualtiy of the compression (0 < q <= 100), defaults to 50\n"
|
||||
<< "\t --index|-i \t the camera index, ignored if cameras > 1, defaults to 0\n"
|
||||
<< "\t --outfile|-o \t the output filename";
|
||||
}
|
||||
if ((arg == "--framecount" || arg == "-n") && i + 1 < argc) {
|
||||
frameCount = std::atoi(argv[++i]);
|
||||
}
|
||||
if ((arg == "--fps" || arg == "-f") && i + 1 < argc) {
|
||||
framerate = std::atoi(argv[++i]);
|
||||
}
|
||||
if ((arg == "--cameras" || arg == "-c") && i + 1 < argc) {
|
||||
maxCameras = std::atoi(argv[++i]);
|
||||
}
|
||||
if ((arg == "--width" || arg == "-w") && i + 1 < argc) {
|
||||
cWidth = std::atoi(argv[++i]);
|
||||
}
|
||||
if ((arg == "--height" || arg == "-h") && i + 1 < argc) {
|
||||
cHeight = std::atoi(argv[++i]);
|
||||
}
|
||||
if ((arg == "--index" || arg == "-i") && i + 1 < argc) {
|
||||
camIndex = std::atoi(argv[++i]);
|
||||
}
|
||||
if ((arg == "--quality" || arg == "-q") && i + 1 < argc) {
|
||||
quality = (uint32_t)std::atoi(argv[++i]);
|
||||
if (quality < 1)
|
||||
quality = 1;
|
||||
if (quality > 100)
|
||||
quality = 100;
|
||||
}
|
||||
if ((arg == "--outfile" || arg == "-o") && i + 1 < argc) {
|
||||
filename = Pylon::String_t(argv[++i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PylonInitialize();
|
||||
|
||||
try {
|
||||
// Check if CVideoWriter is supported and all DLLs are available.
|
||||
if (!CVideoWriter::IsSupported()) {
|
||||
cout << "VideoWriter is not supported at the moment. Please install the pylon Supplementary Package for MPEG-4 which is available on the Basler website." << endl;
|
||||
// Releases all pylon resources.
|
||||
PylonTerminate();
|
||||
// Return with error code 1.
|
||||
return 1;
|
||||
}
|
||||
|
||||
CTlFactory& tlFactory = CTlFactory::GetInstance();
|
||||
DeviceInfoList_t devices;
|
||||
if (tlFactory.EnumerateDevices( devices ) == 0) {
|
||||
throw RUNTIME_EXCEPTION( "No camera present." );
|
||||
}
|
||||
|
||||
CInstantCameraArray cameras( min( devices.size(), maxCameras ) );
|
||||
for (size_t i = 0; i < cameras.GetSize(); ++i) {
|
||||
if ( maxCameras == 1 && devices.size() > 1 && camIndex < devices.size() ){
|
||||
cameras[i].Attach( tlFactory.CreateDevice( devices[camIndex] ) );
|
||||
} else {
|
||||
cameras[i].Attach( tlFactory.CreateDevice( devices[i] ) );
|
||||
}
|
||||
camCount += 1;
|
||||
cameras[i].Open();
|
||||
cout << "Using device " << cameras[i].GetDeviceInfo().GetModelName() << endl;
|
||||
|
||||
CIntegerParameter width( cameras[i].GetNodeMap(), "Width" );
|
||||
CIntegerParameter height( cameras[i].GetNodeMap(), "Height" );
|
||||
CEnumParameter pixelFormat( cameras[i].GetNodeMap(), "PixelFormat" );
|
||||
CEnumParameter trigmode( cameras[i].GetNodeMap(), "TriggerMode");
|
||||
trigmode.TrySetValue( "On" );
|
||||
CEnumParameter trigsource( cameras[i].GetNodeMap(), "TriggerSource");
|
||||
trigsource.TrySetValue( "Software" );
|
||||
width.TrySetValue( cWidth, IntegerValueCorrection_Nearest );
|
||||
height.TrySetValue( cHeight, IntegerValueCorrection_Nearest );
|
||||
|
||||
}
|
||||
|
||||
CIntegerParameter width( cameras[0].GetNodeMap(), "Width" );
|
||||
CIntegerParameter height( cameras[0].GetNodeMap(), "Height" );
|
||||
CEnumParameter pixelFormat( cameras[0].GetNodeMap(), "PixelFormat" );
|
||||
CPixelTypeMapper pixelTypeMapper( &pixelFormat );
|
||||
EPixelType pixelType = pixelTypeMapper.GetPylonPixelTypeFromNodeValue( pixelFormat.GetIntValue() );
|
||||
|
||||
CGrabResultPtr frames[camCount];
|
||||
for (int i =0; i < camCount; i++) {
|
||||
CGrabResultPtr ptrGrabResult;
|
||||
frames[i] = ptrGrabResult;
|
||||
}
|
||||
Pylon::CPylonImage leftImage;
|
||||
Pylon::CPylonImage rightImage;
|
||||
Pylon::CPylonImage stitchedImage;
|
||||
|
||||
// Create a video writer object. Set parameters before opening the video writer.
|
||||
CVideoWriter videoWriter;
|
||||
videoWriter.SetParameter( (uint32_t) width.GetValue() * camCount,
|
||||
(uint32_t) height.GetValue(),
|
||||
pixelType,
|
||||
framerate,
|
||||
quality );
|
||||
// Open the video writer.
|
||||
videoWriter.Open( filename );
|
||||
|
||||
// Starts grabbing for all cameras starting with index 0. The grabbing
|
||||
// is started for one camera after the other. That's why the images of all
|
||||
// cameras are not taken at the same time.
|
||||
// However, a hardware trigger setup can be used to cause all cameras to grab images synchronously.
|
||||
// According to their default configuration, the cameras are
|
||||
// set up for free-running continuous acquisition.
|
||||
cameras.StartGrabbing();
|
||||
int counter = 0;
|
||||
auto before = high_resolution_clock::now();
|
||||
auto done = high_resolution_clock::now();
|
||||
auto total_duration = duration_cast<microseconds>(done - before);
|
||||
int expected_usecs = (int)(1./framerate * 1000000);
|
||||
|
||||
while ( cameras.IsGrabbing() && !stop_request && counter < frameCount) {
|
||||
if (counter > 0) {
|
||||
long delay = total_duration.count() - expected_usecs;
|
||||
if (delay > 0) {
|
||||
cout << "frame: " << counter-1 << " took " << delay << " usecs too long to record!" << endl;
|
||||
} else {
|
||||
auto now = high_resolution_clock::now();
|
||||
while (duration_cast<microseconds>( now - before).count() < expected_usecs ) {
|
||||
now = high_resolution_clock::now();
|
||||
}
|
||||
}
|
||||
}
|
||||
before = high_resolution_clock::now();
|
||||
|
||||
if ( camCount > 1 ) {
|
||||
if ( cameras[0].WaitForFrameTriggerReady( 1000, Pylon::TimeoutHandling_ThrowException ) &&
|
||||
cameras[1].WaitForFrameTriggerReady( 1000, Pylon::TimeoutHandling_ThrowException )) {
|
||||
cameras[0].ExecuteSoftwareTrigger();
|
||||
cameras[1].ExecuteSoftwareTrigger();
|
||||
}
|
||||
} else {
|
||||
cameras[0].WaitForFrameTriggerReady( 1000, Pylon::TimeoutHandling_ThrowException );
|
||||
cameras[0].ExecuteSoftwareTrigger();
|
||||
}
|
||||
|
||||
for ( int i =0; i < camCount; ++i ) {
|
||||
cameras[i].RetrieveResult( 5000, frames[i], TimeoutHandling_ThrowException );
|
||||
}
|
||||
// Image grabbed successfully?
|
||||
bool success = true;
|
||||
for ( int i =0; i < camCount; ++i ) {
|
||||
success = success & frames[i]->GrabSucceeded();
|
||||
}
|
||||
if (success) {
|
||||
if ( camCount > 1 ) {
|
||||
leftImage.AttachGrabResultBuffer( frames[0] );
|
||||
rightImage.AttachGrabResultBuffer( frames[1] );
|
||||
StitchImage::StitchToRight(leftImage, rightImage, &stitchedImage, errorMessage);
|
||||
videoWriter.Add( stitchedImage );
|
||||
} else {
|
||||
videoWriter.Add( frames[0] );
|
||||
}
|
||||
} else {
|
||||
cout << "Error: " << std::hex << frames[0]->GetErrorCode() << std::dec << " " << frames[0]->GetErrorDescription() << endl;
|
||||
}
|
||||
|
||||
counter += 1;
|
||||
std::cout << "." << std::flush;
|
||||
done = high_resolution_clock::now();
|
||||
total_duration = duration_cast<microseconds>(done - before);
|
||||
}
|
||||
} catch (const GenericException& e) {
|
||||
// Error handling
|
||||
cerr << "An exception occurred." << endl << e.GetDescription() << endl;
|
||||
exitCode = 1;
|
||||
}
|
||||
|
||||
// Releases all pylon resources.
|
||||
PylonTerminate();
|
||||
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user