initial verion

This commit is contained in:
Jan Grewe 2025-07-07 17:49:31 +02:00
commit edbc4d68bc
3 changed files with 869 additions and 0 deletions

27
Makefile Normal file
View File

@ -0,0 +1,27 @@
# Makefile for Basler pylon sample program
.PHONY: all clean
# The program to build
NAME := minimal_pylon
# Installation directories for pylon
PYLON_ROOT ?= /opt/pylon
# Build tools and flags
LD := $(CXX)
CPPFLAGS := $(shell $(PYLON_ROOT)/bin/pylon-config --cflags)
CXXFLAGS := #e.g., CXXFLAGS=-g -O0 for debugging
LDFLAGS := $(shell $(PYLON_ROOT)/bin/pylon-config --libs-rpath)
LDLIBS := $(shell $(PYLON_ROOT)/bin/pylon-config --libs)
# Rules for building
all: $(NAME)
$(NAME): $(NAME).o
$(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS)
$(NAME).o: $(NAME).cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) $(NAME).o $(NAME)

237
minimal_pylon.cpp Normal file
View 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;
}

605
stitchimage.h Normal file
View File

@ -0,0 +1,605 @@
// StitchImage.h
// Stitches multiple CPylonImage's into a single image, either vertically or horizontally.
// Also can make collages of images.
// Copyright (c) 2019 Matthew Breit - matt.breit@baslerweb.com or matt.breit@gmail.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http ://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef STITCHIMAGE_H
#define STITCHIMAGE_H
#ifndef LINUX_BUILD
#define WIN_BUILD
#endif
#ifdef WIN_BUILD
#define _CRT_SECURE_NO_WARNINGS // suppress fopen_s warnings for convinience
#endif
// Include Pylon libraries (if needed)
#include <pylon/PylonIncludes.h>
namespace StitchImage
{
int StitchToBottom(Pylon::CPylonImage &topImage, Pylon::CPylonImage &bottomImage, Pylon::CPylonImage *stitchedImage, std::string &errorMessage);
int StitchToRight(Pylon::CPylonImage &leftImage, Pylon::CPylonImage &rightImage, Pylon::CPylonImage *stitchedImage, std::string &errorMessage);
class CollageMaker
{
private:
Pylon::CPylonImage m_collageImage;
Pylon::CPylonImage m_tempImage;
Pylon::CPylonImage m_collageRow;
std::vector<Pylon::CPylonImage> m_collageRows;
int m_collageWidth = 0;
int m_collageHeight = 0;
int m_collageImagesCounter = 0;
bool m_collageComplete = false;
public:
CollageMaker();
~CollageMaker();
int StitchToCollage(Pylon::CPylonImage &image, std::string &errorMessage);
int GetLatestCollage(Pylon::CPylonImage *collageImage, std::string &errorMessage);
int ResetCollage(std::string &errorMessage);
int GetWidth();
int GetHeight();
void SetWidth(int numImages);
void SetHeight(int numImages);
bool IsCollageComplete();
};
}
// *********************************************************************************************************
// DEFINITIONS
int StitchImage::StitchToBottom(Pylon::CPylonImage &topImage, Pylon::CPylonImage &bottomImage, Pylon::CPylonImage *stitchedImage, std::string &errorMessage)
{
errorMessage = "ERROR: ";
errorMessage.append(__FUNCTION__);
errorMessage.append("(): ");
try
{
Pylon::CPylonImage tempImage;
Pylon::EPixelType tempPixelType;
int tempWidth;
if (topImage.GetPixelType() == Pylon::EPixelType::PixelType_Undefined)
{
if (bottomImage.GetPixelType() == Pylon::EPixelType::PixelType_Undefined)
{
errorMessage.append("Both images have undefined pixel types!");
return 1;
}
else
tempPixelType = bottomImage.GetPixelType();
}
else
{
if (topImage.GetPixelType() != bottomImage.GetPixelType())
{
errorMessage.append("Images must be same PixelType");
return 1;
}
else
tempPixelType = topImage.GetPixelType();
}
if (topImage.GetWidth() == 0)
{
if (bottomImage.GetWidth() == 0)
{
errorMessage.append("Both Images have Width = 0!");
return 1;
}
else
tempWidth = bottomImage.GetWidth();
}
else
{
if (topImage.GetWidth() != bottomImage.GetWidth())
{
errorMessage.append("Images must be same Width!");
return 1;
}
else
tempWidth = topImage.GetWidth();
}
int topImageHeight = topImage.GetHeight();
int bottomImageHeight = bottomImage.GetHeight();
size_t topImageSize = topImage.GetImageSize();
size_t bottomImageSize = bottomImage.GetImageSize();
int tempHeight = topImageHeight + bottomImageHeight;
tempImage.Reset(tempPixelType, tempWidth, tempHeight);
uint8_t *pTopImage = (uint8_t*)topImage.GetBuffer();
uint8_t *pBottomImage = (uint8_t*)bottomImage.GetBuffer();
uint8_t *pTempImage = (uint8_t*)tempImage.GetBuffer();
memcpy(&pTempImage[0], &pTopImage[0], topImageSize);
memcpy(&pTempImage[0 + topImageSize], &pBottomImage[0], bottomImageSize);
stitchedImage->CopyImage(tempImage);
return 0;
}
catch (GenICam::GenericException &e)
{
errorMessage.append("EXCEPTION: ");
errorMessage.append(e.GetDescription());
return 1;
}
catch (std::exception &e)
{
errorMessage.append("EXCEPTION: ");
errorMessage.append(e.what());
return 1;
}
catch (...)
{
errorMessage.append("EXCEPTION: ");
errorMessage.append("UNKNOWN.");
return 1;
}
}
int StitchImage::StitchToRight(Pylon::CPylonImage &leftImage, Pylon::CPylonImage &rightImage, Pylon::CPylonImage *stitchedImage, std::string &errorMessage)
{
errorMessage = "ERROR: ";
errorMessage.append(__FUNCTION__);
errorMessage.append("(): ");
try
{
Pylon::CPylonImage tempImage;
Pylon::EPixelType tempPixelType;
int tempHeight;
if (Pylon::IsPacked(leftImage.GetPixelType()) == true || Pylon::IsPacked(rightImage.GetPixelType()) == true)
{
errorMessage.append("Packed pixel formats are not supported yet");
return 1;
}
if (leftImage.GetPixelType() == Pylon::EPixelType::PixelType_Undefined)
{
if (rightImage.GetPixelType() == Pylon::EPixelType::PixelType_Undefined)
{
errorMessage.append("Both images have undefined pixel types!");
return 1;
}
else
tempPixelType = rightImage.GetPixelType();
}
else
{
if (leftImage.GetPixelType() != rightImage.GetPixelType())
{
errorMessage.append("Images must be same PixelType");
return 1;
}
else
tempPixelType = leftImage.GetPixelType();
}
if (leftImage.GetHeight() == 0)
{
if (rightImage.GetHeight() == 0)
{
errorMessage.append("Both Images have Height = 0!");
return 1;
}
else
tempHeight = rightImage.GetHeight();
}
else
{
if (leftImage.GetHeight() != rightImage.GetHeight())
{
errorMessage.append("Images must be same Height!");
return 1;
}
else
tempHeight = leftImage.GetHeight();
}
int BytesPerPixel = Pylon::BitPerPixel(tempPixelType) / 8;
int LeftImageWidth = leftImage.GetWidth();
int RightImageWidth = rightImage.GetWidth();
int tempWidth = LeftImageWidth + RightImageWidth;
tempImage.Reset(tempPixelType, tempWidth, tempHeight);
uint8_t *pLeftImage = (uint8_t*)leftImage.GetBuffer();
uint8_t *pRightImage = (uint8_t*)rightImage.GetBuffer();
uint8_t *pTempImage = (uint8_t*)tempImage.GetBuffer();
for (int i = 0; i < tempHeight; i++)
{
memcpy(&pTempImage[(tempWidth * i * BytesPerPixel)], &pLeftImage[LeftImageWidth * i * BytesPerPixel], LeftImageWidth * BytesPerPixel);
memcpy(&pTempImage[(tempWidth * i * BytesPerPixel) + (LeftImageWidth * BytesPerPixel)], &pRightImage[RightImageWidth * i * BytesPerPixel], RightImageWidth * BytesPerPixel);
}
stitchedImage->CopyImage(tempImage);
return 0;
}
catch (GenICam::GenericException &e)
{
errorMessage.append("EXCEPTION: ");
errorMessage.append(e.GetDescription());
return 1;
}
catch (std::exception &e)
{
errorMessage.append("EXCEPTION: ");
errorMessage.append(e.what());
return 1;
}
catch (...)
{
errorMessage.append("EXCEPTION: ");
errorMessage.append("UNKNOWN.");
return 1;
}
}
StitchImage::CollageMaker::CollageMaker()
{
// nothing
}
StitchImage::CollageMaker::~CollageMaker()
{
// nothing
}
int StitchImage::CollageMaker::StitchToCollage(Pylon::CPylonImage &image, std::string &errorMessage)
{
errorMessage = "ERROR: ";
errorMessage.append(__FUNCTION__);
errorMessage.append("(): ");
try
{
if (StitchImage::StitchToRight(m_collageRow, image, &m_collageRow, errorMessage) != 0)
return 1;
m_collageComplete = false;
m_collageImagesCounter++;
if (m_collageImagesCounter % m_collageWidth == 0 && m_collageImagesCounter > 0)
{
m_collageRows.push_back(m_collageRow);
m_collageRow.Release();
}
if (m_collageImagesCounter % (m_collageWidth * m_collageHeight) == 0 && m_collageImagesCounter > 0)
{
for (size_t i = 0; i < m_collageRows.size(); i++)
{
std::string errorMessage = "";
if (StitchImage::StitchToBottom(m_tempImage, m_collageRows[i], &m_tempImage, errorMessage) != 0)
return 1;
}
m_collageImage.CopyImage(m_tempImage);
m_tempImage.Release();
m_collageRow.Release();
m_collageRows.clear();
m_collageImagesCounter = 0;
m_collageComplete = true;
}
return 0;
}
catch (GenICam::GenericException &e)
{
errorMessage.append("EXCEPTION: ");
errorMessage.append(e.GetDescription());
return 1;
}
catch (std::exception &e)
{
errorMessage.append("EXCEPTION: ");
errorMessage.append(e.what());
return 1;
}
catch (...)
{
errorMessage.append("EXCEPTION: ");
errorMessage.append("UNKNOWN.");
return 1;
}
}
int StitchImage::CollageMaker::GetLatestCollage(Pylon::CPylonImage *collageImage, std::string &errorMessage)
{
errorMessage = "ERROR: ";
errorMessage.append(__FUNCTION__);
errorMessage.append("(): ");
try
{
if (m_collageImage.GetImageSize() == 0)
{
errorMessage.append("No Collage available yet");
return 1;
}
else
{
collageImage->CopyImage(m_collageImage);
return 0;
}
}
catch (GenICam::GenericException &e)
{
errorMessage.append("EXCEPTION: ");
errorMessage.append(e.GetDescription());
return 1;
}
catch (std::exception &e)
{
errorMessage.append("EXCEPTION: ");
errorMessage.append(e.what());
return 1;
}
catch (...)
{
errorMessage.append("EXCEPTION: ");
errorMessage.append("UNKNOWN.");
return 1;
}
}
int StitchImage::CollageMaker::ResetCollage(std::string &errorMessage)
{
errorMessage = "ERROR: ";
errorMessage.append(__FUNCTION__);
errorMessage.append("(): ");
try
{
m_tempImage.Release();
m_collageImage.Release();
m_collageRow.Release();
m_collageRows.clear();
m_collageImagesCounter = 0;
m_collageComplete = false;
return 0;
}
catch (GenICam::GenericException &e)
{
errorMessage.append("EXCEPTION: ");
errorMessage.append(e.GetDescription());
return 1;
}
catch (std::exception &e)
{
errorMessage.append("EXCEPTION: ");
errorMessage.append(e.what());
return 1;
}
catch (...)
{
errorMessage.append("EXCEPTION: ");
errorMessage.append("UNKNOWN.");
return 1;
}
}
int StitchImage::CollageMaker::GetWidth()
{
return m_collageWidth;
}
int StitchImage::CollageMaker::GetHeight()
{
return m_collageHeight;
}
void StitchImage::CollageMaker::SetWidth(int numImages)
{
m_collageWidth = numImages;
}
void StitchImage::CollageMaker::SetHeight(int numImages)
{
m_collageHeight = numImages;
}
bool StitchImage::CollageMaker::IsCollageComplete()
{
return m_collageComplete;
}
// *********************************************************************************************************
#endif
// *********************************************************************************************************
// SAMPLE PROGRAM
/*
// Include files to use the PYLON API
#include <pylon/PylonIncludes.h>
#ifdef PYLON_WIN_BUILD
# include <pylon/PylonGUI.h>
#endif
#include "StitchImage.h"
// Namespace for using pylon objects.
using namespace Pylon;
#define USE_USB
#if defined( USE_1394 )
// Settings for using Basler IEEE 1394 cameras.
#include <pylon/1394/Basler1394InstantCamera.h>
typedef Pylon::CBasler1394InstantCamera Camera_t;
typedef Pylon::CBasler1394GrabResultPtr GrabResultPtr_t; // Or use Camera_t::GrabResultPtr_t
using namespace Basler_IIDC1394CameraParams;
#elif defined ( USE_GIGE )
// Settings for using Basler GigE cameras.
#include <pylon/gige/BaslerGigEInstantCamera.h>
typedef Pylon::CBaslerGigEInstantCamera Camera_t;
typedef Pylon::CBaslerGigEGrabResultPtr GrabResultPtr_t; // Or use Camera_t::GrabResultPtr_t
using namespace Basler_GigECameraParams;
#elif defined( USE_USB )
// Settings for using Basler USB cameras.
#include <pylon/usb/BaslerUsbInstantCamera.h>
typedef Pylon::CBaslerUsbInstantCamera Camera_t;
typedef Pylon::CBaslerUsbGrabResultPtr GrabResultPtr_t; // Or use Camera_t::GrabResultPtr_t
using namespace Basler_UsbCameraParams;
#else
#error Camera type is not specified. For example, define USE_GIGE for using GigE cameras.
#endif
// Namespace for using cout.
using namespace std;
// Number of images to be grabbed.
static const uint32_t c_countOfImagesToGrab = 27;
int main(int argc, char* argv[])
{
// The exit code of the sample application.
int exitCode = 0;
// Before using any pylon methods, the pylon runtime must be initialized.
PylonInitialize();
try
{
// Only look for cameras supported by Camera_t
CDeviceInfo info;
info.SetDeviceClass(Camera_t::DeviceClass());
info.SetSerialNumber("22479283");
// Create an instant camera object with the first found camera device that matches the specified device class.
Camera_t camera(CTlFactory::GetInstance().CreateFirstDevice(info));
// Print the model name of the camera.
cout << "Using device " << camera.GetDeviceInfo().GetModelName() << endl;
// Open the camera.
camera.Open();
camera.PixelFormat.SetValue(PixelFormat_Mono8);
camera.Width.SetValue(640);
camera.Height.SetValue(480);
camera.CenterX.SetValue(true);
camera.CenterY.SetValue(true);
camera.AcquisitionFrameRateEnable.SetValue(true);
camera.AcquisitionFrameRate.SetValue(1);
// This smart pointer will receive the grab result data.
GrabResultPtr_t ptrGrabResult;
// This pylon image will be the vertically stitched image
CPylonImage verticalStitchedImage;
// This pylon image will be the horizontally stitched image
CPylonImage horizontalStitchedImage;
// to make a collage
StitchImage::CollageMaker myCollageMaker;
myCollageMaker.SetWidth(3); // how many images wide do we want the collage to be
myCollageMaker.SetHeight(3); // how many images high do we want the collage to be
camera.StartGrabbing(c_countOfImagesToGrab);
// Camera.StopGrabbing() is called automatically by the RetrieveResult() method
// when c_countOfImagesToGrab images have been retrieved.
while (camera.IsGrabbing())
{
// Wait for an image and then retrieve it. A timeout of 5000 ms is used.
// RetrieveResult calls the image event handler's OnImageGrabbed method.
camera.RetrieveResult(5000, ptrGrabResult, TimeoutHandling_ThrowException);
if (ptrGrabResult->GrabSucceeded())
{
cout << "GrabSucceeded: " << ptrGrabResult->GrabSucceeded() << endl;
cout << "SizeX: " << ptrGrabResult->GetWidth() << endl;
cout << "SizeY: " << ptrGrabResult->GetHeight() << endl;
const uint8_t *pImageBuffer = (uint8_t *)ptrGrabResult->GetBuffer();
cout << "Gray value of first pixel: " << (uint32_t)pImageBuffer[0] << endl;
cout << endl;
CPylonImage image;
image.AttachGrabResultBuffer(ptrGrabResult);
std::string errorMessage = "";
// make a tall strip of images (reusing the verticalStitchedImage as the Top image gives the effect of adding to the stitchedimage)
if (StitchImage::StitchToBottom(verticalStitchedImage, image, &verticalStitchedImage, errorMessage) == 0)
Pylon::DisplayImage(0, verticalStitchedImage);
else
cout << errorMessage << endl;
// make a wide strip of images (reusing the horizontalStitchedImage as the Left image gives the effect of adding to the stitchedimage)
if (StitchImage::StitchToRight(horizontalStitchedImage, image, &horizontalStitchedImage, errorMessage) == 0)
Pylon::DisplayImage(1, horizontalStitchedImage);
else
cout << errorMessage << endl;
// stitch to a collage (the images will be added to the collage in top-left to bottom-right order)
if (myCollageMaker.StitchToCollage(image, errorMessage) != 0)
cout << errorMessage << endl;
if (myCollageMaker.IsCollageComplete() == true)
{
CPylonImage myCollage;
if (myCollageMaker.GetCollageImage(&myCollage, errorMessage) == 0)
Pylon::DisplayImage(2, myCollage);
else
cout << errorMessage << endl;
}
}
}
}
catch (const GenericException &e)
{
// Error handling.
cerr << "An exception occurred." << endl
<< e.GetDescription() << endl;
exitCode = 1;
}
catch (std::exception &e)
{
// Error handling.
cerr << "An exception occurred." << endl
<< e.what() << endl;
exitCode = 1;
}
// Comment the following two lines to disable waiting on exit.
cerr << endl << "Press Enter to exit." << endl;
while (cin.get() != '\n');
// Releases all pylon resources.
PylonTerminate();
return exitCode;
}
*/
// *********************************************************************************************************