From edbc4d68bcd5d6e8786943bc0b98876e6995ad77 Mon Sep 17 00:00:00 2001 From: Jan Grewe Date: Mon, 7 Jul 2025 17:49:31 +0200 Subject: [PATCH] initial verion --- Makefile | 27 +++ minimal_pylon.cpp | 237 ++++++++++++++++++ stitchimage.h | 605 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 869 insertions(+) create mode 100644 Makefile create mode 100644 minimal_pylon.cpp create mode 100644 stitchimage.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7b2f088 --- /dev/null +++ b/Makefile @@ -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) diff --git a/minimal_pylon.cpp b/minimal_pylon.cpp new file mode 100644 index 0000000..1e66bf5 --- /dev/null +++ b/minimal_pylon.cpp @@ -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 +#include "stitchimage.h" +#include +#include +#include // for read(), STDIN_FILENO +#include // for tcgetattr(), tcsetattr() +#include // 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 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(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( 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(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; +} + diff --git a/stitchimage.h b/stitchimage.h new file mode 100644 index 0000000..c7e7df4 --- /dev/null +++ b/stitchimage.h @@ -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 + +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 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 +#ifdef PYLON_WIN_BUILD +# include +#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 +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 +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 +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; +} +*/ +// ********************************************************************************************************* \ No newline at end of file