Compare commits

...

19 Commits

Author SHA1 Message Date
d20ea22beb rename grabber to singlecamgrabber 2024-03-18 09:37:34 +01:00
ec3844ba9c rename pylonwrapper to singlecamwrapper 2024-03-18 09:34:52 +01:00
2bed70b971 remove debug code fix time conversion issue 2024-03-15 10:32:37 +01:00
dadce69944 [dualcam] properly read rois 2024-03-14 15:14:47 +01:00
d78b9d8b02 [recorder] fix missed signal 2024-03-14 15:14:18 +01:00
23b0a9afcd [writer] remove cam number, simplify writing done signal 2024-03-14 15:13:29 +01:00
fe20326953 [qt] remove deprecated pixmap calls 2024-03-14 11:17:44 +01:00
f803854da3 disable mode selection if selection was done 2024-03-13 09:19:23 +01:00
155ac6b471 add user given camera name to configuration 2024-03-13 08:58:45 +01:00
18f088c4fd [camids] add dialog to set camera User specified ids, disabled at the
moment
2024-03-13 08:30:38 +01:00
a3418bc25e cleanup and proper (de)activation of actions 2024-03-12 17:00:01 +01:00
ec203ba1ad cleanup 2024-03-12 16:40:24 +01:00
5263d04cac [recorde] revert back to single writers/buffers 2024-03-12 15:33:28 +01:00
03e5cd70c7 [myimage] double max frame width, allow setting data using PylonImage 2024-03-12 15:31:44 +01:00
e394c346ed fix isValid, some cleanup 2024-03-12 15:31:24 +01:00
aa265565f2 manually grab from cameras 2024-03-12 15:30:07 +01:00
e9b195674c stolen stitchimage from MattsProjects 2024-03-12 14:59:51 +01:00
555098cdba move VideoSpecs to util 2024-03-12 14:56:25 +01:00
41272ce08e intermediate state, more todos, writer not working in dual cam setting 2024-03-12 07:40:23 +01:00
24 changed files with 1064 additions and 195 deletions

View File

@@ -42,7 +42,8 @@ find_package (NIX REQUIRED)
include_directories (AFTER ${NIX_INCLUDE_DIR}) include_directories (AFTER ${NIX_INCLUDE_DIR})
# ####################################### # #######################################
# # OPENCV # OPENCV
# message ("=> finding opencv ...")
# find_package(OpenCV REQUIRED opencv_highgui opencv_core) # find_package(OpenCV REQUIRED opencv_highgui opencv_core)
# include_directories(AFTER ${OpenCV_INCLUDE_DIRS} ) # include_directories(AFTER ${OpenCV_INCLUDE_DIRS} )
# set(LINK_LIBS ${LINK_LIBS} ${OpenCV_LIBRARIES}) # set(LINK_LIBS ${LINK_LIBS} ${OpenCV_LIBRARIES})

View File

@@ -86,6 +86,7 @@ void CamConfigurator::modeChanged(int idx) {
stack->setCurrentIndex(1); stack->setCurrentIndex(1);
QString device = device_combo->currentText(); QString device = device_combo->currentText();
preview->setPrimaryCamera(device); preview->setPrimaryCamera(device);
mode_combo->setEnabled(false);
} else if (idx == 2) { } else if (idx == 2) {
qDebug() << "Mode changed to dual camera mode"; qDebug() << "Mode changed to dual camera mode";
preview = stereoCameraView(); preview = stereoCameraView();
@@ -100,6 +101,7 @@ void CamConfigurator::modeChanged(int idx) {
} }
QString device2 = device_combo->itemText(1 - i); QString device2 = device_combo->itemText(1 - i);
preview->setSecondaryCamera(device2); preview->setSecondaryCamera(device2);
mode_combo->setEnabled(false);
} else { } else {
qDebug() << "Mode changed mode selection"; qDebug() << "Mode changed mode selection";
stack->setCurrentIndex(0); stack->setCurrentIndex(0);

View File

@@ -60,13 +60,12 @@ CameraPreview::CameraPreview(QWidget *parent):cameraname(""), camera(nullptr), Q
void CameraPreview::setCamera(QString &device){ void CameraPreview::setCamera(QString &device){
qDebug() << "update camera! ";// << device.toStdString(); qDebug() << "update camera! ";// << device.toStdString();
cameraname = device; cameraname = device;
label->setText(device); if (camera != nullptr) {
if (camera != NULL) {
qDebug() << "camera is not nullptr! "; qDebug() << "camera is not nullptr! ";
delete camera; delete camera;
camera = nullptr; camera = nullptr;
} }
camera = new PylonWrapper(cameraname.toStdString()); camera = new SingleCamWrapper(cameraname.toStdString());
std::string message; std::string message;
bool success = camera->openCamera(message); bool success = camera->openCamera(message);
if (!success) { if (!success) {
@@ -76,7 +75,9 @@ void CameraPreview::setCamera(QString &device){
QString msg = "<p><b>Could not open camera device!</b><p><p>" + QString::fromStdString(message) + "</p>"; QString msg = "<p><b>Could not open camera device!</b><p><p>" + QString::fromStdString(message) + "</p>";
msgBox.setText(msg); msgBox.setText(msg);
msgBox.exec(); msgBox.exec();
return;
} }
label->setText(device + " - " + camera->userName());
takeStill(); takeStill();
} }

View File

@@ -12,7 +12,7 @@
#include <QPainter> #include <QPainter>
#include <pylon/PylonIncludes.h> #include <pylon/PylonIncludes.h>
#include "pylonwrapper.h" #include "singlecamwrapper.h"
#include "util.h" #include "util.h"
namespace Ui { namespace Ui {
class CameraPreview; class CameraPreview;
@@ -53,7 +53,7 @@ private:
void setImage(const QPixmap &img); void setImage(const QPixmap &img);
void validate(QSpinBox *origin, QSpinBox *dest, int limit); void validate(QSpinBox *origin, QSpinBox *dest, int limit);
PylonWrapper *camera; SingleCamWrapper *camera;
}; };

48
camids.cpp Normal file
View File

@@ -0,0 +1,48 @@
#include "camids.h"
#include "mylogger.h"
#include "util.h"
CameraID::CameraID(Pylon::DeviceInfoList &deviceList, QWidget *parent) :
deviceList(deviceList), QDialog(parent) {
device_combo = new QComboBox(this);
for (auto d : deviceList) {
device_combo->addItem(QString(d.GetFullName()) + " - " + QString(d.GetUserDefinedName()));
}
connect(device_combo, SIGNAL(currentIndexChanged(int)), SLOT(primaryDeviceChanged(int)));
QWidget *header = new QWidget(this);
QGridLayout *grid = new QGridLayout(header);
grid->addWidget(new QLabel("Camera device:", this), 1, 0);
grid->addWidget(device_combo, 1, 1);
edit = new QLineEdit(this);
grid->addWidget(new QLabel("Camera Id", this), 2, 0);
grid->addWidget(edit, 2, 1);
header->setLayout(grid);
QVBoxLayout *vbox = new QVBoxLayout(this);
vbox->addWidget(header);
buttonbox = new QDialogButtonBox(QDialogButtonBox::Ok
| QDialogButtonBox::Cancel);
connect(buttonbox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttonbox, &QDialogButtonBox::rejected, this, &QDialog::reject);
vbox->addWidget(buttonbox);
std::cerr <<"ping\n";
}
void CameraID::setID() {
std::cerr << "Set ID!" << std::endl;
}
QString CameraID::newID() {
std::cerr <<"ping\n";
return edit->text();
}
int CameraID::cameraIndex() {
std::cerr <<"ping\n";
return device_combo->currentIndex();
}

45
camids.h Normal file
View File

@@ -0,0 +1,45 @@
#ifndef CAMIDS_H
#define CAMIDS_H
#include <QDialog>
#include <QComboBox>
#include <QLabel>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QLineEdit>
#include <QDialogButtonBox>
#include <pylon/PylonIncludes.h>
#include "mylogger.h"
namespace Ui {
class CameraID;
}
class CameraID : public QDialog
{
Q_OBJECT
public:
explicit CameraID(Pylon::DeviceInfoList_t &deviceList, QWidget *parent = 0);
// ~CameraID(){};
QString newID();
int cameraIndex();
public slots:
void setID();
// signals:
// void column_visibility_changed(QString who, QString column, bool state);
// void recent_file_changed(QStringList);
private:
Pylon::DeviceInfoList_t deviceList;
QComboBox *device_combo;
QLineEdit *edit;
QDialogButtonBox *buttonbox;
};
#endif // CAMIDS_H

View File

@@ -1,28 +1,72 @@
#include "dualcamgrabber.h" #include "dualcamgrabber.h"
#include <iostream> #include <iostream>
#include <pylon/PylonIncludes.h> #include <pylon/PylonIncludes.h>
#include <stitchimage.h>
#include <chrono>
using namespace std::chrono;
typedef high_resolution_clock Time;
typedef milliseconds ms;
typedef duration<float> fsec;
void DualcamGrabber::run() { void DualcamGrabber::run() {
stop_request = false; stop_request = false;
size_t framecount = 0; size_t counter = 0;
if (wrapper->isOpen()) { if (wrapper->isOpen()) {
Pylon::CInstantCameraArray &cameras = wrapper->getCameraArray(); Pylon::CInstantCameraArray &cameras = wrapper->getCameraArray();
wrapper->frameRate(static_cast<uint>(framerate)); wrapper->frameRate(static_cast<uint>(framerate), -1);
wrapper->exposureTime(exposure); wrapper->exposureTime(exposure);
wrapper->gain(gain); wrapper->gain(gain);
cameras.StartGrabbing(); cameras.StartGrabbing();
Pylon::CGrabResultPtr frame0, frame1; Pylon::CGrabResultPtr frame0, frame1;
Pylon::CPylonImage leftImage;
Pylon::CPylonImage rightImage;
Pylon::CPylonImage stitchedImage;
std::string errorMessage = "";
// int ifi = 0;
// int deviation = 0;
// std::cerr << wrapper->frameRate(0) << "\t" << wrapper->frameRate(1) << "\t" << framerate << std::endl;
// int desired_ifi = (1./wrapper->frameRate(0) * 1000000);
// auto framestart = high_resolution_clock::now();
while (cameras.IsGrabbing() && !stop_request) { while (cameras.IsGrabbing() && !stop_request) {
// if (counter > 0) {
// deviation = desired_ifi - ifi;
// if (deviation > 0)
// // usleep(deviation);
// std::cerr << desired_ifi << "\t" << deviation << std::endl;
// }
// auto start = high_resolution_clock::now();
MyImage *img = new MyImage(); MyImage *img = new MyImage();
cameras.RetrieveResult( 5000, framecount % 2 == 0 ? frame0 : frame1, Pylon::TimeoutHandling_ThrowException ); // auto stop1 = high_resolution_clock::now();
img->setFrame(framecount % 2 == 0 ? frame0 : frame1); cameras[0].RetrieveResult( 5000, frame0, Pylon::TimeoutHandling_ThrowException );
if (framecount % 2 == 0) { // auto stop2 = high_resolution_clock::now();
buffer0->push(img); cameras[1].RetrieveResult( 5000, frame1, Pylon::TimeoutHandling_ThrowException );
} else { // auto stop3 = high_resolution_clock::now();
buffer1->push(img); leftImage.AttachGrabResultBuffer( frame0 );
rightImage.AttachGrabResultBuffer( frame1 );
if (leftImage.IsValid() && rightImage.IsValid()) {
try {
StitchImage::StitchToRight(leftImage, rightImage, &stitchedImage, errorMessage);
img->setFrame(stitchedImage);
buffer->push(img);
} catch(const std::exception& e) {
std::cerr << e.what() << '\n';
}
} }
framecount += 1; // auto stop4 = high_resolution_clock::now();
// auto duration1 = duration_cast<microseconds>(stop1 - start);
// auto duration2 = duration_cast<microseconds>(stop2 - stop1);
// auto duration3 = duration_cast<microseconds>(stop3 - stop2);
// auto duration4 = duration_cast<microseconds>(stop4 - stop3);
// std::cerr << "framecount: " << counter << " image constr: " << duration1.count() << "\t" << " retrieve1: " << duration2.count() << "\t" << " retrieve2: " << duration3.count() << "\t" << "conversion: " << duration4.count() << std::endl;
// ifi = duration_cast<microseconds>(stop4 - framestart).count();
// framestart = stop4;
// if (counter > 0) {
// std::cerr << "frame " << counter << " inter frame interval: " << ifi << "microseconds" << std::endl;
// }
counter += 1;
} }
cameras.StopGrabbing(); cameras.StopGrabbing();
} }

View File

@@ -10,8 +10,8 @@ class DualcamGrabber : public QThread
{ {
Q_OBJECT Q_OBJECT
public: public:
DualcamGrabber(DualcamWrapper *wrapper, ImageBuffer *buffer0, ImageBuffer * buffer1, int framerate, QObject *parent = nullptr) : DualcamGrabber(DualcamWrapper *wrapper, ImageBuffer *buffer, int framerate, QObject *parent = nullptr) :
QThread(parent), wrapper(wrapper), buffer0(buffer0), buffer1(buffer1), framerate(framerate) {} QThread(parent), wrapper(wrapper), buffer(buffer), framerate(framerate) {}
void run() override; void run() override;
void stop(); void stop();
@@ -30,7 +30,7 @@ public:
private: private:
bool stop_request = false; bool stop_request = false;
DualcamWrapper *wrapper; DualcamWrapper *wrapper;
ImageBuffer *buffer0, *buffer1; ImageBuffer *buffer;
int framerate; int framerate;
double exposure, gain; double exposure, gain;

View File

@@ -31,7 +31,7 @@ void DualcamWrapper::terminate() {
bool DualcamWrapper::isOpen() { bool DualcamWrapper::isOpen() {
return valid; return cameras.IsOpen();
} }
@@ -54,8 +54,8 @@ bool DualcamWrapper::frameRate(uint new_framerate, int camindex) {
frameRate(new_framerate, 0); frameRate(new_framerate, 0);
frameRate(new_framerate, 1); frameRate(new_framerate, 1);
return true; return true;
} else if (camindex == 0 && camindex ==1) { } else if (camindex >= 0 && camindex < 2) {
GenApi::INodeMap& nodemap = getNodemap(0); GenApi::INodeMap& nodemap = getNodemap(camindex);
GenApi::INode* n = nodemap.GetNode( "AcquisitionFrameRateEnable" ); GenApi::INode* n = nodemap.GetNode( "AcquisitionFrameRateEnable" );
Pylon::CBooleanParameter enableframerate(n); Pylon::CBooleanParameter enableframerate(n);
enableframerate.SetValue(true); enableframerate.SetValue(true);
@@ -72,7 +72,7 @@ bool DualcamWrapper::frameRate(uint new_framerate, int camindex) {
double DualcamWrapper::frameRate(int camindex) { double DualcamWrapper::frameRate(int camindex) {
assert(camindex > 0 && camindex < 2); assert(camindex >= 0 && camindex < 2);
double rate = -1.; double rate = -1.;
if (valid) { if (valid) {
GenApi::INodeMap& nodemap = getNodemap(camindex); GenApi::INodeMap& nodemap = getNodemap(camindex);
@@ -173,14 +173,14 @@ bool DualcamWrapper::grabFrame(MyImage &img, int camindex) {
qDebug() << "grabFrame from camera " << camindex; qDebug() << "grabFrame from camera " << camindex;
if (valid) { if (valid) {
GenApi::INodeMap &nodemap = getNodemap(camindex); GenApi::INodeMap &nodemap = getNodemap(camindex);
qDebug() << "Setting width" << layout.rois[0].width; qDebug() << "Setting width" << layout.rois[camindex].width;
Pylon::CIntegerParameter(nodemap, "Width").SetValue(layout.rois[0].width); Pylon::CIntegerParameter(nodemap, "Width").SetValue(layout.rois[camindex].width);
qDebug() << "Setting height" << layout.rois[0].height; qDebug() << "Setting height" << layout.rois[0].height;
Pylon::CIntegerParameter(nodemap, "Height").SetValue(layout.rois[0].height); Pylon::CIntegerParameter(nodemap, "Height").SetValue(layout.rois[camindex].height);
qDebug() << "Setting xoffset" << layout.rois[0].x; qDebug() << "Setting xoffset" << layout.rois[camindex].x;
Pylon::CIntegerParameter(nodemap, "OffsetX").SetValue(layout.rois[0].x); Pylon::CIntegerParameter(nodemap, "OffsetX").SetValue(layout.rois[camindex].x);
qDebug() << "Setting yoffset" << layout.rois[0].y; qDebug() << "Setting yoffset" << layout.rois[camindex].y;
Pylon::CIntegerParameter(nodemap, "OffsetY").SetValue(layout.rois[0].y); Pylon::CIntegerParameter(nodemap, "OffsetY").SetValue(layout.rois[camindex].y);
camera->StartGrabbing(); camera->StartGrabbing();
camera->RetrieveResult( 5000, frame, Pylon::TimeoutHandling_ThrowException); camera->RetrieveResult( 5000, frame, Pylon::TimeoutHandling_ThrowException);
@@ -191,15 +191,25 @@ bool DualcamWrapper::grabFrame(MyImage &img, int camindex) {
} }
void DualcamWrapper::setROI() {
for (int camindex = 0; camindex < 2; camindex++){
qDebug() << "Setting ROI: w" << layout.rois[camindex].width << " h: "<< layout.rois[camindex].height << " x " << layout.rois[camindex].x << " y " << layout.rois[camindex].y;
GenApi::INodeMap &nodemap = getNodemap(camindex);
Pylon::CIntegerParameter(nodemap, "Width").SetValue(layout.rois[camindex].width);
Pylon::CIntegerParameter(nodemap, "Height").SetValue(layout.rois[camindex].height);
Pylon::CIntegerParameter(nodemap, "OffsetX").SetValue(layout.rois[camindex].x);
Pylon::CIntegerParameter(nodemap, "OffsetY").SetValue(layout.rois[camindex].y);
}
}
void DualcamWrapper::resetCamera(int camindex) { void DualcamWrapper::resetCamera(int camindex) {
GenApi::INodeMap &nodemap = getNodemap( camindex ); GenApi::INodeMap &nodemap = getNodemap( camindex );
int64_t dfltWidth = 2048; int64_t dfltWidth = 2048;
int64_t dfltHeight = 1536; int64_t dfltHeight = 1536;
qDebug() << "resetting camera to default ROI (" << dfltWidth << ", " << dfltHeight << ")"; qDebug() << "resetting camera to default ROI (" << dfltWidth << ", " << dfltHeight << ")";
try { try {
// std::cerr << "MaxWidth: " << Pylon::CIntegerParameter(nodemap, "WidthMax").GetValue() << std::endl;
Pylon::CIntegerParameter(nodemap, "Width").SetValue(dfltWidth, false); Pylon::CIntegerParameter(nodemap, "Width").SetValue(dfltWidth, false);
// std::cerr << "MaxHeight: " << Pylon::CIntegerParameter(nodemap, "HeightMax").GetValue() << std::endl;
Pylon::CIntegerParameter(nodemap, "Height").SetValue(dfltHeight, false); Pylon::CIntegerParameter(nodemap, "Height").SetValue(dfltHeight, false);
Pylon::CIntegerParameter(nodemap, "OffsetX").SetValue(0); Pylon::CIntegerParameter(nodemap, "OffsetX").SetValue(0);
Pylon::CIntegerParameter(nodemap, "OffsetY").SetValue(0); Pylon::CIntegerParameter(nodemap, "OffsetY").SetValue(0);
@@ -213,13 +223,13 @@ void DualcamWrapper::resetCamera(int camindex) {
bool DualcamWrapper::openCameras(std::string &message) { bool DualcamWrapper::openCameras(std::string &message) {
qDebug() << "opening cameras"; qDebug() << "opening cameras";
bool valid = true;
Pylon::CTlFactory& tlFactory = Pylon::CTlFactory::GetInstance(); Pylon::CTlFactory& tlFactory = Pylon::CTlFactory::GetInstance();
// Pylon::CInstantCameraArray cameras(2);
cameras.Initialize(2); cameras.Initialize(2);
try { try {
cameras[0].Attach( tlFactory.CreateDevice( layout.devices[0].c_str() ) ); cameras[0].Attach( tlFactory.CreateDevice( layout.devices[0].c_str() ) );
cameras[0].Open();
cameras[1].Attach( tlFactory.CreateDevice( layout.devices[1].c_str() ) ); cameras[1].Attach( tlFactory.CreateDevice( layout.devices[1].c_str() ) );
cameras[1].Open();
valid = cameras[0].IsOpen(); valid = cameras[0].IsOpen();
valid = valid & cameras[1].IsOpen(); valid = valid & cameras[1].IsOpen();
message = "Successfully opened camera!"; message = "Successfully opened camera!";
@@ -229,9 +239,9 @@ bool DualcamWrapper::openCameras(std::string &message) {
valid = false; valid = false;
return valid; return valid;
} }
resetCamera(0); // resetCamera(0);
resetCamera(1); // resetCamera(1);
setROI();
return valid; return valid;
} }

View File

@@ -15,7 +15,6 @@ public:
DualcamWrapper(const CameraLayout &layout); DualcamWrapper(const CameraLayout &layout);
~DualcamWrapper(); ~DualcamWrapper();
ImageSettings getImageSettings(int camindex); ImageSettings getImageSettings(int camindex);
bool isOpen(); bool isOpen();
void terminate(); void terminate();
@@ -30,12 +29,12 @@ public:
double gain(int camindex); double gain(int camindex);
bool gain(double gain_db, int camindex=-1); bool gain(double gain_db, int camindex=-1);
Pylon::CInstantCameraArray &getCameraArray(); Pylon::CInstantCameraArray &getCameraArray();
// Pylon::CInstantCamera getCamera(int camindex);
private: private:
void resetCamera(int camindex); void resetCamera(int camindex);
Pylon::CInstantCameraArray cameras; Pylon::CInstantCameraArray cameras;
GenApi::INodeMap& getNodemap(int camindex); GenApi::INodeMap& getNodemap(int camindex);
void setROI();
bool valid, withLayout; bool valid, withLayout;
CameraLayout layout; CameraLayout layout;

View File

@@ -72,7 +72,6 @@ void ImageBuffer::push(MyImage *img) {
buffer[head_idx] = img; buffer[head_idx] = img;
framecounts[head_idx] = framecount; framecounts[head_idx] = framecount;
load = load < buffer_size ? load +=1 : buffer_size; load = load < buffer_size ? load +=1 : buffer_size;
mutex.unlock(); mutex.unlock();
} }
@@ -111,6 +110,6 @@ MyImage* ImageBuffer::readLast(size_t &framecount) {
} }
ImageBuffer::~ImageBuffer(){ ImageBuffer::~ImageBuffer(){
std::cerr << "Image buffer destructor" << std::endl; qDebug() << "Image buffer destructor";
clear(); clear();
} }

View File

@@ -21,6 +21,18 @@ bool MyImage::setFrame(Pylon::CGrabResultPtr ptr) {
return valid; return valid;
} }
bool MyImage::setFrame( Pylon::CPylonImage &img) {
bool valid = img.IsValid() && img.GetWidth() <= max_width && img.GetHeight() <= max_height;
if (valid) {
img_width = img.GetWidth();
img_height = img.GetHeight();
memcpy(&buffer, img.GetBuffer(), img.GetImageSize());
auto t = std::chrono::system_clock::now();
img_timestamp = std::chrono::system_clock::to_time_t(t);
}
return valid;
}
int MyImage::width() { int MyImage::width() {
return static_cast<int>(img_width); return static_cast<int>(img_width);
} }

View File

@@ -16,13 +16,14 @@ public:
void* data(); void* data();
time_t timestamp(); time_t timestamp();
bool setFrame(Pylon::CGrabResultPtr ptr); bool setFrame(Pylon::CGrabResultPtr ptr);
bool setFrame(Pylon::CPylonImage &img);
private: private:
uint32_t img_width = 0; uint32_t img_width = 0;
uint32_t img_height = 0; uint32_t img_height = 0;
int64_t img_index = 0; int64_t img_index = 0;
time_t img_timestamp; time_t img_timestamp;
static const int max_width = 2048; static const int max_width = 4096;
static const int max_height = 1536; static const int max_height = 1536;
char buffer[max_width * max_height]; char buffer[max_width * max_height];
}; };

View File

@@ -6,7 +6,7 @@ Recorder for up to two Basler cameras.
* implement grabbing from 2 joined cameras * implement grabbing from 2 joined cameras
* set the region of interest * set the region of interest
* save properly * !!! dual cam writer!!! chgeck file opening!
## FIXMEs ## FIXMEs

View File

@@ -34,8 +34,7 @@
PylonRecorder::PylonRecorder(QWidget *parent) PylonRecorder::PylonRecorder(QWidget *parent)
: QMainWindow(parent), imageLabel(new QLabel), scrollArea(new QScrollArea), : QMainWindow(parent), imageLabel(new QLabel), scrollArea(new QScrollArea),
singlecamgrabber(nullptr), dualcamgrabber(nullptr), singlecamgrabber(nullptr), dualcamgrabber(nullptr),
writer0(nullptr), writer1(nullptr), writer(nullptr), buffer(nullptr),
buffer0(nullptr), buffer1(nullptr),
singlecam(nullptr), dualcam(nullptr), singlecam(nullptr), dualcam(nullptr),
dryRun(false), cameraOpened(false), camsconfigured(false) dryRun(false), cameraOpened(false), camsconfigured(false)
{ {
@@ -62,8 +61,8 @@ PylonRecorder::PylonRecorder(QWidget *parent)
QPalette progressPalette = pressureBar->palette(); QPalette progressPalette = pressureBar->palette();
progressPalette.setBrush(QPalette::Highlight, QBrush(color)); progressPalette.setBrush(QPalette::Highlight, QBrush(color));
pressureBar->setPalette(progressPalette); pressureBar->setPalette(progressPalette);
QLabel *preassureLabel = new QLabel("Buffer preassure:", this); QLabel *pressureLabel = new QLabel("Buffer pressure:", this);
preassureLabel->setStyleSheet("QLabel{font-size: 11pt;font-family: Arial;font-weight: Bold}"); pressureLabel->setStyleSheet("QLabel{font-size: 11pt;font-family: Arial;font-weight: Bold}");
loadBar = new QProgressBar(this); loadBar = new QProgressBar(this);
loadBar->setRange(0, defaultBufferSize); loadBar->setRange(0, defaultBufferSize);
loadBar->setFixedSize(200, 25); loadBar->setFixedSize(200, 25);
@@ -90,7 +89,7 @@ PylonRecorder::PylonRecorder(QWidget *parent)
fileHeader->setStyleSheet("QLabel{font-size: 11pt;font-family: Arial; font-weight: Bold}"); fileHeader->setStyleSheet("QLabel{font-size: 11pt;font-family: Arial; font-weight: Bold}");
statusBar()->addWidget(camHeader); statusBar()->addWidget(camHeader);
statusBar()->addWidget(cameraConnectedLabel); statusBar()->addWidget(cameraConnectedLabel);
statusBar()->addWidget(preassureLabel); statusBar()->addWidget(pressureLabel);
statusBar()->addWidget(pressureBar); statusBar()->addWidget(pressureBar);
statusBar()->addWidget(loadLabel); statusBar()->addWidget(loadLabel);
statusBar()->addWidget(loadBar); statusBar()->addWidget(loadBar);
@@ -119,9 +118,9 @@ PylonRecorder::~PylonRecorder(){
singlecamgrabber->requestStop(); singlecamgrabber->requestStop();
singlecamgrabber->wait(1000); singlecamgrabber->wait(1000);
} }
if (writer0 != nullptr && writer0->isRunning()) { if (writer != nullptr && writer->isRunning()) {
writer0->forceStop(); writer->forceStop();
writer0->wait(1000); writer->wait(1000);
} }
storeSettings(); storeSettings();
if (singlecam != nullptr) { if (singlecam != nullptr) {
@@ -135,16 +134,12 @@ PylonRecorder::~PylonRecorder(){
dualcam = nullptr; dualcam = nullptr;
} }
if (buffer0 != nullptr) { if (buffer != nullptr) {
qDebug() << "Deleting buffer"; qDebug() << "Deleting buffer";
delete buffer0; delete buffer;
buffer0 = nullptr; buffer = nullptr;
}
if (buffer1 != nullptr) {
qDebug() << "Deleting buffer";
delete buffer1;
buffer1 = nullptr;
} }
if (singlecamgrabber != nullptr) { if (singlecamgrabber != nullptr) {
qDebug() << "Deleting grabber"; qDebug() << "Deleting grabber";
delete singlecamgrabber; delete singlecamgrabber;
@@ -155,15 +150,10 @@ PylonRecorder::~PylonRecorder(){
delete dualcamgrabber; delete dualcamgrabber;
dualcamgrabber = nullptr; dualcamgrabber = nullptr;
} }
if (writer0 != nullptr) { if (writer != nullptr) {
qDebug() << "Deleting writer"; qDebug() << "Deleting writer";
delete writer0; delete writer;
writer0 = nullptr; writer = nullptr;
}
if (writer1 != nullptr) {
qDebug() << "Deleting writer";
delete writer1;
writer1 = nullptr;
} }
qDebug() << "Deleting setting"; qDebug() << "Deleting setting";
delete settings; delete settings;
@@ -206,11 +196,8 @@ bool PylonRecorder::loadFile(const QString &fileName) {
.arg(QDir::toNativeSeparators(fileName), reader.errorString())); .arg(QDir::toNativeSeparators(fileName), reader.errorString()));
return false; return false;
} }
setImage(newImage); setImage(newImage);
setWindowFilePath(fileName); setWindowFilePath(fileName);
const QString message = tr("Opened \"%1\", %2x%3, Depth: %4") const QString message = tr("Opened \"%1\", %2x%3, Depth: %4")
.arg(QDir::toNativeSeparators(fileName)).arg(image.width()).arg(image.height()).arg(image.depth()); .arg(QDir::toNativeSeparators(fileName)).arg(image.width()).arg(image.height()).arg(image.depth());
statusBar()->showMessage(message); statusBar()->showMessage(message);
@@ -293,8 +280,8 @@ void PylonRecorder::saveAs() {
void PylonRecorder::print() { void PylonRecorder::print() {
QPixmap map = imageLabel->pixmap(Qt::ReturnByValue); const QPixmap *map = imageLabel->pixmap();
Q_ASSERT(!map.isNull()); Q_ASSERT(!map->isNull());
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog) #if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog)
QPrintDialog dialog(&printer, this); QPrintDialog dialog(&printer, this);
@@ -302,11 +289,11 @@ void PylonRecorder::print() {
if (dialog.exec()) { if (dialog.exec()) {
QPainter painter(&printer); QPainter painter(&printer);
QRect rect = painter.viewport(); QRect rect = painter.viewport();
QSize size = map.size(); QSize size = map->size();
size.scale(rect.size(), Qt::KeepAspectRatio); size.scale(rect.size(), Qt::KeepAspectRatio);
painter.setViewport(rect.x(), rect.y(), size.width(), size.height()); painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
painter.setWindow(map.rect()); painter.setWindow(map->rect());
painter.drawPixmap(0, 0, map); painter.drawPixmap(0, 0, *map);
} }
#endif #endif
} }
@@ -447,6 +434,7 @@ void PylonRecorder::createActions() {
connect_camera_action->setStatusTip(tr("Connect to to camera and open device")); connect_camera_action->setStatusTip(tr("Connect to to camera and open device"));
disconnect_camera_action = camera_menu->addAction(disconnect_icon, tr("&disconnect"), this, &PylonRecorder::disconnectCamera); disconnect_camera_action = camera_menu->addAction(disconnect_icon, tr("&disconnect"), this, &PylonRecorder::disconnectCamera);
disconnect_camera_action->setStatusTip(tr("Disconnect from the camera device")); disconnect_camera_action->setStatusTip(tr("Disconnect from the camera device"));
disconnect_camera_action->setEnabled(false);
camera_menu->addSeparator(); camera_menu->addSeparator();
grab_still_action = camera_menu->addAction(snapshot_icon, tr("&grab still"), this, &PylonRecorder::grabStillFromPylon); grab_still_action = camera_menu->addAction(snapshot_icon, tr("&grab still"), this, &PylonRecorder::grabStillFromPylon);
grab_still_action->setStatusTip(tr("Grab single image from Pylon camera")); grab_still_action->setStatusTip(tr("Grab single image from Pylon camera"));
@@ -455,6 +443,9 @@ void PylonRecorder::createActions() {
grab_continuous_action->setShortcut(tr("Ctrl+Enter")); grab_continuous_action->setShortcut(tr("Ctrl+Enter"));
grab_stop_action = camera_menu->addAction(stop_icon, tr("&stop grabbing"), this, &PylonRecorder::stopRecording); grab_stop_action = camera_menu->addAction(stop_icon, tr("&stop grabbing"), this, &PylonRecorder::stopRecording);
grab_stop_action->setShortcut(tr("Ctrl+Shift+Enter")); grab_stop_action->setShortcut(tr("Ctrl+Shift+Enter"));
set_cam_identifier_action = camera_menu->addAction(tr("set identifier"), this, &PylonRecorder::setCameraIDs);
set_cam_identifier_action->setStatusTip(tr("Set human readable camera identifier or easier recognition."));
set_cam_identifier_action->setToolTip(tr("Set human readable camera identifier or easier recognition."));
selectStorageAction = new QAction(tr("storage location"), this); selectStorageAction = new QAction(tr("storage location"), this);
selectStorageAction->setStatusTip(tr("Select a storage location for the recorded videos")); selectStorageAction->setStatusTip(tr("Select a storage location for the recorded videos"));
@@ -547,20 +538,42 @@ void PylonRecorder::updateActions() {
zoomInAct->setEnabled(!fitToWindowAct->isChecked()); zoomInAct->setEnabled(!fitToWindowAct->isChecked());
zoomOutAct->setEnabled(!fitToWindowAct->isChecked()); zoomOutAct->setEnabled(!fitToWindowAct->isChecked());
normalSizeAct->setEnabled(!fitToWindowAct->isChecked()); normalSizeAct->setEnabled(!fitToWindowAct->isChecked());
disconnect_camera_action->setEnabled(deviceList.size() > 0); disconnect_camera_action->setEnabled(cameraOpened);
connect_camera_action->setEnabled(true); connect_camera_action->setEnabled(true);
grab_still_action->setEnabled(deviceList.size() > 0); grab_still_action->setEnabled(cameraOpened);
grab_continuous_action->setEnabled(cameraOpened && !grabbing); grab_continuous_action->setEnabled(cameraOpened && !grabbing);
// grab_continuous_action->setEnabled(!grabbing);
grab_stop_action->setEnabled(grabbing); grab_stop_action->setEnabled(grabbing);
set_cam_identifier_action->setEnabled(false);
} }
void PylonRecorder::setCameraIDs() {
if (deviceList.size() == 0) {
QMessageBox msgBox;
QString msg = "<p><b>No camera device found!</b></p><br><p>Connect camera and try again!</p>";
msgBox.setText(msg);
msgBox.exec();
qWarning() << msg.toStdString().c_str();
return;
}
cameraIdDialog = new CameraID(deviceList, this);
connect(cameraConfigDialog, SIGNAL(accepted()), SLOT(cameraIDAccepted()));
std::cerr <<"ping\n";
cameraIdDialog->exec();
}
void PylonRecorder::cameraIDAccepted() {
QString newid = cameraIdDialog->newID();
int deviceindex = cameraIdDialog->cameraIndex();
std::cerr << "New camera id " << newid.toStdString() << " index: " << deviceindex << std::endl;
delete(cameraIdDialog);
}
void PylonRecorder::scaleImage(double factor) { void PylonRecorder::scaleImage(double factor) {
QPixmap map = imageLabel->pixmap(Qt::ReturnByValue); const QPixmap *map = imageLabel->pixmap();
Q_ASSERT(!map.isNull()); Q_ASSERT(!map->isNull());
scaleFactor *= factor; scaleFactor *= factor;
imageLabel->resize(scaleFactor * map.size()); imageLabel->resize(scaleFactor * map->size());
adjustScrollBar(scrollArea->horizontalScrollBar(), factor); adjustScrollBar(scrollArea->horizontalScrollBar(), factor);
adjustScrollBar(scrollArea->verticalScrollBar(), factor); adjustScrollBar(scrollArea->verticalScrollBar(), factor);
@@ -571,7 +584,7 @@ void PylonRecorder::scaleImage(double factor) {
void PylonRecorder::applyScaling(){ void PylonRecorder::applyScaling(){
imageLabel->resize(scaleFactor * imageLabel->pixmap(Qt::ReturnByValue).size()); imageLabel->resize(scaleFactor * imageLabel->pixmap()->size());
} }
@@ -595,19 +608,19 @@ void PylonRecorder::adjustScrollBar(QScrollBar *scrollBar, double factor) {
void PylonRecorder::cameraConfiguration(){ void PylonRecorder::cameraConfiguration(){
d = new CamConfigurator(deviceList, this); cameraConfigDialog = new CamConfigurator(deviceList, this);
connect(d, SIGNAL(accepted()), SLOT(cameraConfigurationAccepted())); connect(cameraConfigDialog, SIGNAL(accepted()), SLOT(cameraConfigurationAccepted()));
connect(d, SIGNAL(rejected()), SLOT(cameraConfigurationAborted())); connect(cameraConfigDialog, SIGNAL(rejected()), SLOT(cameraConfigurationAborted()));
// QObject::connect(&d, SIGNAL(column_visibility_changed(QString, QString,bool)), this, SLOT(visible_columns_update(QString, QString,bool))); // QObject::connect(&d, SIGNAL(column_visibility_changed(QString, QString,bool)), this, SLOT(visible_columns_update(QString, QString,bool)));
d->exec(); cameraConfigDialog->exec();
} }
void PylonRecorder::cameraConfigurationAccepted() { void PylonRecorder::cameraConfigurationAccepted() {
qDebug() << "Cameras setting " << ((d->result()) ? "Accepted" : "Discarded"); qDebug() << "Cameras setting " << ((cameraConfigDialog->result()) ? "Accepted" : "Discarded");
this->layout = d->layout(); this->layout = cameraConfigDialog->layout();
camsconfigured = true; camsconfigured = true;
delete d; delete cameraConfigDialog;
} }
@@ -619,7 +632,6 @@ void PylonRecorder::cameraConfigurationAborted() {
void PylonRecorder::connectCamera() { void PylonRecorder::connectCamera() {
this->layout = CameraLayout(); this->layout = CameraLayout();
std::cerr << this->layout.rois.size() << " " << this->layout.devices.size() << std::endl;
qDebug() << "connecting camera(s)"; qDebug() << "connecting camera(s)";
if (deviceList.size() == 0) { if (deviceList.size() == 0) {
detectCameras(); detectCameras();
@@ -640,7 +652,7 @@ void PylonRecorder::connectCamera() {
std::string cname = layout.devices[0]; std::string cname = layout.devices[0];
std::string message; std::string message;
qDebug() << "connecting to camera " << cname.c_str(); qDebug() << "connecting to camera " << cname.c_str();
singlecam = new PylonWrapper(layout); singlecam = new SingleCamWrapper(layout);
bool success = singlecam->openCamera(message); bool success = singlecam->openCamera(message);
if (success) { if (success) {
cameraConnectedLabel->setText("connected"); cameraConnectedLabel->setText("connected");
@@ -659,7 +671,6 @@ void PylonRecorder::connectCamera() {
if (layout.mode == CameraMode::dual && layout.devices.size() == 2) { if (layout.mode == CameraMode::dual && layout.devices.size() == 2) {
qDebug() << "dual camera mode"; qDebug() << "dual camera mode";
std::string message; std::string message;
qDebug() << "creating dual cam wrapper";
dualcam = new DualcamWrapper(layout); dualcam = new DualcamWrapper(layout);
bool success = dualcam->openCameras(message); bool success = dualcam->openCameras(message);
if (success) { if (success) {
@@ -699,28 +710,30 @@ void PylonRecorder::disconnectCamera() {
VideoSpecs PylonRecorder::getVideoSpecs(const ImageSettings &settings) { VideoSpecs PylonRecorder::getVideoSpecs(const ImageSettings &settings) {
VideoSpecs s = VideoSpecs(); VideoSpecs s = VideoSpecs();
if (this->layout.mode == CameraMode::single && this->layout.devices.size() > 0) { if (!this->layout.devices.size() > 0) {
s.fps = framerateSpinner->value(); return s;
s.exposureTime = static_cast<double>(exposureSpinner->value()); }
s.detectorGain = static_cast<double>(gainSpinner->value()); s.fps = framerateSpinner->value();
s.exposureTime = static_cast<double>(exposureSpinner->value());
s.detectorGain = static_cast<double>(gainSpinner->value());
s.pixelType = settings.pixelType;
s.orientation = settings.orientation;
s.quality = 95;
if (layout.mode == CameraMode::single) {
s.width = static_cast<uint32_t>(this->layout.rois[0].width); s.width = static_cast<uint32_t>(this->layout.rois[0].width);
s.height = static_cast<uint32_t>(this->layout.rois[0].height); s.height = static_cast<uint32_t>(this->layout.rois[0].height);
s.xoffset = static_cast<uint32_t>(this->layout.rois[0].x); } else if (layout.mode == CameraMode::dual) {
s.yoffset = static_cast<uint32_t>(this->layout.rois[0].y); s.width = static_cast<uint32_t>(this->layout.rois[0].width * 2);
s.height = static_cast<uint32_t>(this->layout.rois[0].height);
s.pixelType = settings.pixelType;
s.orientation = settings.orientation;
s.quality = 95;
} else {
qWarning() << "Dual camera mode not supported yet!";
} }
return s; return s;
} }
void PylonRecorder::startSinglecamRecording() { void PylonRecorder::startSinglecamRecording() {
qDebug() << "start recording!"; qDebug() << "start single-camera recording!";
std::string filename = createFilename(".mp4"); std::string filename = createFilename("", ".mp4");
fileLabel->setText(QString::fromStdString(filename)); fileLabel->setText(QString::fromStdString(filename));
qDebug() << "storing to file " << filename.c_str(); qDebug() << "storing to file " << filename.c_str();
@@ -732,15 +745,15 @@ void PylonRecorder::startSinglecamRecording() {
specs.format = VideoFormat::mp4; specs.format = VideoFormat::mp4;
qDebug() << "got video specifications"; qDebug() << "got video specifications";
if (buffer0 != nullptr) { if (buffer != nullptr) {
buffer0->clear(); buffer->clear();
delete buffer0; delete buffer;
buffer0 = nullptr; buffer = nullptr;
} }
qDebug() << "setting image buffer to size " << buffersizeSpinner->value(); qDebug() << "setting image buffer to size " << buffersizeSpinner->value();
buffer0 = new ImageBuffer(defaultBufferSize); buffer = new ImageBuffer(defaultBufferSize);
if (buffersizeSpinner->value() != static_cast<int>(buffer0->capacity())) { if (buffersizeSpinner->value() != static_cast<int>(buffer->capacity())) {
buffer0->resize(static_cast<size_t>(buffersizeSpinner->value())); buffer->resize(static_cast<size_t>(buffersizeSpinner->value()));
loadBar->setRange(0, buffersizeSpinner->value()); loadBar->setRange(0, buffersizeSpinner->value());
} }
@@ -749,7 +762,7 @@ void PylonRecorder::startSinglecamRecording() {
delete singlecamgrabber; delete singlecamgrabber;
singlecamgrabber = nullptr; singlecamgrabber = nullptr;
} }
singlecamgrabber = new Grabber(singlecam, buffer0, defaultFrameRate); singlecamgrabber = new SinglecamGrabber(singlecam, buffer, defaultFrameRate);
if (framerateSpinner->value() != singlecamgrabber->currentFramerate()) if (framerateSpinner->value() != singlecamgrabber->currentFramerate())
singlecamgrabber->setFrameRate(framerateSpinner->value()); singlecamgrabber->setFrameRate(framerateSpinner->value());
@@ -759,21 +772,21 @@ void PylonRecorder::startSinglecamRecording() {
singlecamgrabber->setGain(static_cast<double>(gainSpinner->value())); singlecamgrabber->setGain(static_cast<double>(gainSpinner->value()));
qDebug() << "setup writer"; qDebug() << "setup writer";
if (writer0 != nullptr) { if (writer != nullptr) {
delete writer0; delete writer;
writer0 = nullptr; writer = nullptr;
} }
writer0 = new Writer(buffer0); writer = new Writer(buffer);
connect(writer0, &Writer::writingDone, this, &PylonRecorder::writerDone); connect(writer, SIGNAL(writingDone()), this, SLOT(writerDone()));
writer0->setVideoSpecs(specs); writer->setVideoSpecs(specs);
QSettings s; QSettings s;
this->mdata.read(s); this->mdata.read(s);
writer0->setProjectMetadata(mdata); writer->setProjectMetadata(mdata);
buffer0->clear(); buffer->clear();
if (!dryRunCheckBox->isChecked()) { if (!dryRunCheckBox->isChecked()) {
writer0->start(); writer->start();
writing = true; writing = true;
} }
dryRun = dryRunCheckBox->isChecked(); dryRun = dryRunCheckBox->isChecked();
@@ -784,7 +797,67 @@ void PylonRecorder::startSinglecamRecording() {
void PylonRecorder::startDualcamRecording() { void PylonRecorder::startDualcamRecording() {
qDebug() << "start dual-camera recording!";
std::string filename = createFilename("", ".mp4");
fileLabel->setText(QString::fromStdString(filename));
qDebug() << "storing to file " << filename.c_str();
ImageSettings settings = dualcam->getImageSettings(0); //FIXME!
qDebug() << "got image settings";
VideoSpecs specs = getVideoSpecs(settings);
specs.filename = filename;
specs.format = VideoFormat::mp4;
qDebug() << "got video specifications " << specs.fps;
if (buffer != nullptr) {
buffer->clear();
delete buffer;
buffer = nullptr;
}
qDebug() << "setting image buffer to size " << buffersizeSpinner->value();
buffer = new ImageBuffer(defaultBufferSize);
if (buffersizeSpinner->value() != static_cast<int>(buffer->capacity())) {
buffer->resize(static_cast<size_t>(buffersizeSpinner->value()));
loadBar->setRange(0, buffersizeSpinner->value());
}
qDebug() << "setting up grabber";
if (dualcamgrabber != nullptr) {
delete dualcamgrabber;
dualcamgrabber = nullptr;
}
dualcamgrabber = new DualcamGrabber(dualcam, buffer, defaultFrameRate);
if (framerateSpinner->value() != dualcamgrabber->currentFramerate())
dualcamgrabber->setFrameRate(framerateSpinner->value());
if (exposureSpinner->value() != int(dualcamgrabber->currentExposureTime()))
dualcamgrabber->setExposureTime(static_cast<double>(exposureSpinner->value()));
if (gainSpinner->value() != int(dualcamgrabber->currentGain()))
dualcamgrabber->setGain(static_cast<double>(gainSpinner->value()));
qDebug() << "setting up writers";
if (writer != nullptr) {
delete writer;
writer = nullptr;
}
writer = new Writer(buffer);
connect(writer, SIGNAL(writingDone()), this, SLOT(writerDone()));
writer->setVideoSpecs(specs);
qDebug() << "push metadata to writer";
QSettings s;
this->mdata.read(s);
writer->setProjectMetadata(mdata);
dryRun = dryRunCheckBox->isChecked();
buffer->clear();
if (!dryRun) {
writer->start();
writing = true;
}
dualcamgrabber->start();
grabbing = true;
stopRequest = false;
} }
@@ -812,16 +885,20 @@ void PylonRecorder::stopRecording() {
qDebug() << "StopRecording: stop grabber!"; qDebug() << "StopRecording: stop grabber!";
if (singlecamgrabber !=nullptr) if (singlecamgrabber !=nullptr)
singlecamgrabber->requestStop(); singlecamgrabber->requestStop();
if (dualcamgrabber !=nullptr)
dualcamgrabber->requestStop();
qDebug() << "StopRecording: stop writer!"; qDebug() << "StopRecording: stop writer!";
if (writer0 != nullptr) if (writer != nullptr)
writer0->requestStop(); writer->requestStop();
grabbing = false; grabbing = false;
stopRequest = true; stopRequest = true;
grab_stop_action->setEnabled(false); grab_stop_action->setEnabled(false);
qDebug() << "StopRecording: clear buffer!"; qDebug() << "StopRecording: clear buffer!";
if(buffer0 != nullptr) { if(buffer != nullptr) {
buffer0->clear(); buffer->clear();
writerDone(); if (dryRun)
writerDone();
} }
} }
qDebug() << "StopRecording done!"; qDebug() << "StopRecording done!";
@@ -829,15 +906,19 @@ void PylonRecorder::stopRecording() {
void PylonRecorder::writerDone() { void PylonRecorder::writerDone() {
std::cerr << "writer is Done!!!" << std::endl;
pressureTimer->stop(); pressureTimer->stop();
pressureBar->reset(); pressureBar->reset();
loadBar->reset(); loadBar->reset();
labelTimer->stop(); labelTimer->stop();
writingLabel->setStyleSheet(inactiveLabelStyle); writingLabel->setStyleSheet(inactiveLabelStyle);
grabbingLabel->setStyleSheet(inactiveLabelStyle); grabbingLabel->setStyleSheet(inactiveLabelStyle);
singlecamgrabber->wait(10000); if (layout.mode == CameraMode::single) {
writer0->wait(10000); singlecamgrabber->wait(10000);
} else {
dualcamgrabber->wait(10000);
}
if (writer != nullptr)
writer->wait(10000);
writing = false; writing = false;
updateActions(); updateActions();
qInfo() << "writer is Done!"; qInfo() << "writer is Done!";
@@ -854,9 +935,8 @@ void PylonRecorder::displayActivity() {
void PylonRecorder::displaySingleFrame() { void PylonRecorder::displaySingleFrame() {
MyImage *img; MyImage *img;
size_t fc = 0; size_t fc = 0;
img = buffer0->readLast(fc); img = buffer->readLast(fc);
if (img != nullptr){ if (img != nullptr){
std::cerr << "display, last frame count " << fc << std::endl;
QImage qimg(static_cast<uchar *>(img->data()), img->width(), img->height(), QImage::Format::Format_Grayscale8); QImage qimg(static_cast<uchar *>(img->data()), img->width(), img->height(), QImage::Format::Format_Grayscale8);
setImage(qimg); setImage(qimg);
}else { }else {
@@ -892,13 +972,13 @@ std::string PylonRecorder::createFilename(const std::string &suffix, const std::
void PylonRecorder::displayBufferPressure() { void PylonRecorder::displayBufferPressure() {
int value = static_cast<int>(round(buffer0->bufferPressure())); int value = static_cast<int>(round(buffer->bufferPressure()));
pressureBar->setValue(value); pressureBar->setValue(value);
QColor color = progressColor(value); QColor color = progressColor(value);
progressPalette.setBrush(QPalette::Highlight, QBrush(color)); progressPalette.setBrush(QPalette::Highlight, QBrush(color));
pressureBar->setPalette(progressPalette); pressureBar->setPalette(progressPalette);
int load = static_cast<int>(buffer0->bufferLoad()); int load = static_cast<int>(buffer->bufferLoad());
loadBar->setValue(load); loadBar->setValue(load);
} }
@@ -916,6 +996,7 @@ void PylonRecorder::grabStillFromPylon() {
} else { } else {
statusBar()->showMessage(tr("Camera is not open! Connect to camera first!")); statusBar()->showMessage(tr("Camera is not open! Connect to camera first!"));
} }
//FIXME does not work for single camera mode!
qDebug() << "grabbing still image done!"; qDebug() << "grabbing still image done!";
} }

View File

@@ -7,14 +7,15 @@
#include <QCheckBox> #include <QCheckBox>
#include <QSettings> #include <QSettings>
#include <pylon/PylonIncludes.h> #include <pylon/PylonIncludes.h>
#include "pylonwrapper.h" #include "singlecamwrapper.h"
#include "dualcamwrapper.h" #include "dualcamwrapper.h"
#include "imagebuffer.h" #include "imagebuffer.h"
#include "grabber.h" #include "singlecamgrabber.h"
#include "dualcamgrabber.h" #include "dualcamgrabber.h"
#include "writer.h" #include "writer.h"
#include "projectsettings.h" #include "projectsettings.h"
#include "camconfig.h" #include "camconfig.h"
#include "camids.h"
#include "util.h" #include "util.h"
#include <QImage> #include <QImage>
@@ -70,6 +71,8 @@ private slots:
void selectStorageLocation(); void selectStorageLocation();
void cameraConfigurationAccepted(); void cameraConfigurationAccepted();
void cameraConfigurationAborted(); void cameraConfigurationAborted();
void setCameraIDs();
void cameraIDAccepted();
private: private:
void createActions(); void createActions();
@@ -86,7 +89,6 @@ private:
VideoSpecs getVideoSpecs(const ImageSettings &settings); VideoSpecs getVideoSpecs(const ImageSettings &settings);
void startSinglecamRecording(); void startSinglecamRecording();
void startDualcamRecording(); void startDualcamRecording();
bool saveFile(const QString &fileName); bool saveFile(const QString &fileName);
void setImage(const QImage &newImage); void setImage(const QImage &newImage);
void scaleImage(double factor); void scaleImage(double factor);
@@ -103,12 +105,12 @@ private:
QProgressBar *loadBar; QProgressBar *loadBar;
QScrollArea *scrollArea; QScrollArea *scrollArea;
double scaleFactor = 1; double scaleFactor = 1;
PylonWrapper *singlecam; SingleCamWrapper *singlecam;
DualcamWrapper *dualcam; DualcamWrapper *dualcam;
ImageBuffer *buffer0, *buffer1; ImageBuffer *buffer;
Grabber *singlecamgrabber; SinglecamGrabber *singlecamgrabber;
DualcamGrabber *dualcamgrabber; DualcamGrabber *dualcamgrabber;
Writer *writer0, *writer1; Writer *writer;
CameraLayout layout; CameraLayout layout;
bool grabbing, stopRequest, writing, labelSwitch, dryRun, cameraOpened, camsconfigured; bool grabbing, stopRequest, writing, labelSwitch, dryRun, cameraOpened, camsconfigured;
QPalette progressPalette; QPalette progressPalette;
@@ -121,8 +123,9 @@ private:
QString storageLocation = ""; QString storageLocation = "";
ProjectMetadata mdata; ProjectMetadata mdata;
Pylon::DeviceInfoList_t deviceList; Pylon::DeviceInfoList_t deviceList;
CamConfigurator *d;
Pylon::PylonAutoInitTerm autoInitTerm; Pylon::PylonAutoInitTerm autoInitTerm;
CamConfigurator *cameraConfigDialog;
CameraID *cameraIdDialog;
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer) #if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer)
@@ -141,6 +144,7 @@ private:
QAction *grab_stop_action; QAction *grab_stop_action;
QAction *connect_camera_action; QAction *connect_camera_action;
QAction *disconnect_camera_action; QAction *disconnect_camera_action;
QAction *set_cam_identifier_action;
}; };
#endif #endif

View File

@@ -1,8 +1,8 @@
#include "grabber.h" #include "singlecamgrabber.h"
#include <iostream> #include <iostream>
#include <pylon/PylonIncludes.h> #include <pylon/PylonIncludes.h>
void Grabber::run() { void SinglecamGrabber::run() {
stop_request = false; stop_request = false;
int count = 0; int count = 0;
if (camera->isOpen()) { if (camera->isOpen()) {

View File

@@ -1,16 +1,16 @@
#ifndef GRABBER_H #ifndef SINGLECAMGRABBER_H
#define GRABBER_H #define SINGLECAMGRABBER_H
#include <QObject> #include <QObject>
#include <QThread> #include <QThread>
#include "pylonwrapper.h" #include "singlecamwrapper.h"
#include "imagebuffer.h" #include "imagebuffer.h"
class Grabber : public QThread class SinglecamGrabber : public QThread
{ {
Q_OBJECT Q_OBJECT
public: public:
Grabber(PylonWrapper *camera, ImageBuffer*buffer, int framerate, QObject *parent = nullptr) : SinglecamGrabber(SingleCamWrapper *camera, ImageBuffer*buffer, int framerate, QObject *parent = nullptr) :
QThread(parent), camera(camera), buffer(buffer), framerate(framerate) {} QThread(parent), camera(camera), buffer(buffer), framerate(framerate) {}
void run() override; void run() override;
@@ -29,7 +29,7 @@ public:
private: private:
bool stop_request = false; bool stop_request = false;
PylonWrapper *camera; SingleCamWrapper *camera;
ImageBuffer *buffer; ImageBuffer *buffer;
int framerate; int framerate;
double exposure, gain; double exposure, gain;
@@ -51,4 +51,4 @@ signals:
void terminated(); void terminated();
}; };
#endif // GRABBER_H #endif // SINGLECAMGRABBER_H

View File

@@ -1,19 +1,19 @@
#include "pylonwrapper.h" #include "singlecamwrapper.h"
PylonWrapper::PylonWrapper(const std::string &fullName): SingleCamWrapper::SingleCamWrapper(const std::string &fullName):
valid(false), fullName(fullName), camera(nullptr), withLayout(false) { valid(false), fullName(fullName), camera(nullptr), withLayout(false) {
qDebug() << "Constructor with name"; qDebug() << "Constructor with name";
Pylon::PylonInitialize(); Pylon::PylonInitialize();
} }
PylonWrapper::PylonWrapper(const CameraLayout &layout): valid(false), withLayout(true), camera(nullptr) { SingleCamWrapper::SingleCamWrapper(const CameraLayout &layout): valid(false), withLayout(true), camera(nullptr) {
qDebug() << "Constructor with layout"; qDebug() << "Constructor with layout";
this->fullName = layout.devices[0]; this->fullName = layout.devices[0];
this->layout = layout; this->layout = layout;
Pylon::PylonInitialize(); Pylon::PylonInitialize();
} }
PylonWrapper::~PylonWrapper() { SingleCamWrapper::~SingleCamWrapper() {
qDebug() << "wrapper destructor"; qDebug() << "wrapper destructor";
if (camera != nullptr){ if (camera != nullptr){
if (camera->IsOpen()) { if (camera->IsOpen()) {
@@ -27,7 +27,7 @@ PylonWrapper::~PylonWrapper() {
qDebug() << "Successfully deleted camera"; qDebug() << "Successfully deleted camera";
} }
void PylonWrapper::terminate() { void SingleCamWrapper::terminate() {
qDebug() << "Terminate"; qDebug() << "Terminate";
try { try {
Pylon::PylonTerminate(); Pylon::PylonTerminate();
@@ -36,11 +36,11 @@ void PylonWrapper::terminate() {
} }
} }
bool PylonWrapper::isOpen() { bool SingleCamWrapper::isOpen() {
return valid; return valid;
} }
double PylonWrapper::maxFrameRate() { double SingleCamWrapper::maxFrameRate() {
double max_rate = -1; double max_rate = -1;
if (valid) { if (valid) {
GenApi::INodeMap& nodemap = camera->GetNodeMap(); GenApi::INodeMap& nodemap = camera->GetNodeMap();
@@ -51,7 +51,7 @@ double PylonWrapper::maxFrameRate() {
return max_rate; return max_rate;
} }
bool PylonWrapper::frameRate(uint new_framerate) { bool SingleCamWrapper::frameRate(uint new_framerate) {
if (valid) { if (valid) {
GenApi::INodeMap& nodemap = camera->GetNodeMap(); GenApi::INodeMap& nodemap = camera->GetNodeMap();
GenApi::INode* n = nodemap.GetNode( "AcquisitionFrameRateEnable" ); GenApi::INode* n = nodemap.GetNode( "AcquisitionFrameRateEnable" );
@@ -66,7 +66,7 @@ bool PylonWrapper::frameRate(uint new_framerate) {
return false; return false;
} }
double PylonWrapper::frameRate() { double SingleCamWrapper::frameRate() {
double rate = -1.; double rate = -1.;
if (valid) { if (valid) {
GenApi::INodeMap& nodemap = camera->GetNodeMap(); GenApi::INodeMap& nodemap = camera->GetNodeMap();
@@ -77,7 +77,7 @@ double PylonWrapper::frameRate() {
return rate; return rate;
} }
double PylonWrapper::exposureTime() { double SingleCamWrapper::exposureTime() {
double time = -1.; double time = -1.;
if (valid) { if (valid) {
GenApi::INodeMap& nodemap = camera->GetNodeMap(); GenApi::INodeMap& nodemap = camera->GetNodeMap();
@@ -88,7 +88,7 @@ double PylonWrapper::exposureTime() {
return time; return time;
} }
bool PylonWrapper::exposureTime(double exposure_time) { bool SingleCamWrapper::exposureTime(double exposure_time) {
if (valid) { if (valid) {
GenApi::INodeMap& nodemap = camera->GetNodeMap(); GenApi::INodeMap& nodemap = camera->GetNodeMap();
double d = GenApi::CFloatPtr(nodemap.GetNode("ExposureTime"))->GetValue(); double d = GenApi::CFloatPtr(nodemap.GetNode("ExposureTime"))->GetValue();
@@ -105,7 +105,7 @@ bool PylonWrapper::exposureTime(double exposure_time) {
return false; return false;
} }
double PylonWrapper::gain() { double SingleCamWrapper::gain() {
double gain = -1.; double gain = -1.;
if (valid) { if (valid) {
GenApi::INodeMap& nodemap = camera->GetNodeMap(); GenApi::INodeMap& nodemap = camera->GetNodeMap();
@@ -116,7 +116,7 @@ double PylonWrapper::gain() {
return gain; return gain;
} }
bool PylonWrapper::gain(double gain_db) { bool SingleCamWrapper::gain(double gain_db) {
if (valid) { if (valid) {
GenApi::INodeMap& nodemap = camera->GetNodeMap(); GenApi::INodeMap& nodemap = camera->GetNodeMap();
GenApi::CFloatPtr(nodemap.GetNode("Gain"))->SetValue(gain_db); GenApi::CFloatPtr(nodemap.GetNode("Gain"))->SetValue(gain_db);
@@ -125,7 +125,7 @@ bool PylonWrapper::gain(double gain_db) {
return false; return false;
} }
ImageSettings PylonWrapper::getImageSettings() { ImageSettings SingleCamWrapper::getImageSettings() {
ImageSettings settings; ImageSettings settings;
if (valid) { if (valid) {
Pylon::CEnumParameter pixelFormat( camera->GetNodeMap(), "PixelFormat" ); Pylon::CEnumParameter pixelFormat( camera->GetNodeMap(), "PixelFormat" );
@@ -141,7 +141,7 @@ ImageSettings PylonWrapper::getImageSettings() {
return settings; return settings;
} }
bool PylonWrapper::grabFrame(MyImage &img) { bool SingleCamWrapper::grabFrame(MyImage &img) {
Pylon::CGrabResultPtr frame; Pylon::CGrabResultPtr frame;
qDebug() << "grabFrame"; qDebug() << "grabFrame";
if (valid) { if (valid) {
@@ -162,7 +162,7 @@ bool PylonWrapper::grabFrame(MyImage &img) {
return frame.IsValid(); return frame.IsValid();
} }
void PylonWrapper::resetCamera() { void SingleCamWrapper::resetCamera() {
int64_t dfltWidth = 2048; int64_t dfltWidth = 2048;
int64_t dfltHeight = 1536; int64_t dfltHeight = 1536;
qDebug() << "resetting camera to default ROI (" << dfltWidth << ", " << dfltHeight << ")"; qDebug() << "resetting camera to default ROI (" << dfltWidth << ", " << dfltHeight << ")";
@@ -181,7 +181,7 @@ void PylonWrapper::resetCamera() {
} }
} }
bool PylonWrapper::openCamera(std::string &message) { bool SingleCamWrapper::openCamera(std::string &message) {
qDebug() << "opening camera"; qDebug() << "opening camera";
try { try {
camera = new Pylon::CInstantCamera(); camera = new Pylon::CInstantCamera();
@@ -215,7 +215,7 @@ bool PylonWrapper::openCamera(std::string &message) {
return valid; return valid;
} }
void PylonWrapper::closeCamera() { void SingleCamWrapper::closeCamera() {
qDebug() << "Close camera!"; qDebug() << "Close camera!";
if (camera->IsOpen()) { if (camera->IsOpen()) {
try { try {
@@ -229,6 +229,12 @@ void PylonWrapper::closeCamera() {
} }
} }
Pylon::CInstantCamera *PylonWrapper::getCamera() { Pylon::CInstantCamera *SingleCamWrapper::getCamera() {
return camera; return camera;
} }
QString SingleCamWrapper::userName() {
GenApi::INodeMap& nodemap = camera->GetNodeMap();
QString username = Pylon::CStringParameter(nodemap, "DeviceUserID").GetValue().c_str();
return username;
}

View File

@@ -1,5 +1,5 @@
#ifndef PYLONWRAPPER_H #ifndef SINGLECAMWRAPPER_H
#define PYLONWRAPPER_H #define SINGLECAMWRAPPER_H
#include <pylon/PylonIncludes.h> #include <pylon/PylonIncludes.h>
#include <pylon/BaslerUniversalInstantCamera.h> #include <pylon/BaslerUniversalInstantCamera.h>
@@ -7,12 +7,12 @@
#include "util.h" #include "util.h"
#include "myimage.h" #include "myimage.h"
class PylonWrapper class SingleCamWrapper
{ {
public: public:
PylonWrapper(const std::string &name); SingleCamWrapper(const std::string &name);
PylonWrapper(const CameraLayout &layout); SingleCamWrapper(const CameraLayout &layout);
~PylonWrapper(); ~SingleCamWrapper();
ImageSettings getImageSettings(); ImageSettings getImageSettings();
bool isOpen(); bool isOpen();
@@ -27,6 +27,7 @@ public:
bool exposureTime(double exposure_time); bool exposureTime(double exposure_time);
double gain(); double gain();
bool gain(double gain_db); bool gain(double gain_db);
QString userName();
Pylon::CInstantCamera *getCamera(); Pylon::CInstantCamera *getCamera();
void resetCamera(); void resetCamera();
@@ -40,4 +41,4 @@ private:
}; };
#endif // PYLONWRAPPER_H #endif // SINGLECAMWRAPPER_H

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;
}
*/
// *********************************************************************************************************

12
util.h
View File

@@ -37,4 +37,16 @@ struct ImageSettings {
Pylon::EImageOrientation orientation; Pylon::EImageOrientation orientation;
}; };
struct VideoSpecs {
std::string filename;
uint32_t width, height, quality = 10;
int fps;
double exposureTime;
double detectorGain;
Pylon::EPixelType pixelType;
Pylon::EImageOrientation orientation;
VideoFormat format = VideoFormat::raw;
};
#endif /*UTIL_H*/ #endif /*UTIL_H*/

View File

@@ -1,9 +1,7 @@
#include "writer.h" #include "writer.h"
#include <chrono> #include <chrono>
#include <fstream> #include <fstream>
#include <pylon/VideoWriter.h> #include <pylon/VideoWriter.h>
using namespace std::chrono;
void Writer::setVideoSpecs(VideoSpecs specs) { void Writer::setVideoSpecs(VideoSpecs specs) {
videoSpecs = specs; videoSpecs = specs;
@@ -11,6 +9,7 @@ void Writer::setVideoSpecs(VideoSpecs specs) {
} }
void Writer::setProjectMetadata(ProjectMetadata mdata) { void Writer::setProjectMetadata(ProjectMetadata mdata) {
qDebug() << "received metadata";
metadata = mdata; metadata = mdata;
metadata_valid = true; metadata_valid = true;
} }
@@ -26,6 +25,7 @@ void Writer::writeMetadata(nix::Section &s){
} }
void Writer::run() { void Writer::run() {
qDebug() << "writer running!";
size_t count = 0; size_t count = 0;
size_t chunksize = 256; size_t chunksize = 256;
// size_t framecount = 0; // size_t framecount = 0;
@@ -38,6 +38,8 @@ void Writer::run() {
emit writingDone(); emit writingDone();
return; return;
} }
qDebug() << "checks done!";
Pylon::CVideoWriter videoWriter; Pylon::CVideoWriter videoWriter;
if (specs_valid) { if (specs_valid) {
stop_request = false; stop_request = false;
@@ -47,7 +49,8 @@ void Writer::run() {
myFile.write((char*)&videoSpecs.width, 4); myFile.write((char*)&videoSpecs.width, 4);
myFile.write((char*)&videoSpecs.height, 4); myFile.write((char*)&videoSpecs.height, 4);
} else { } else {
videoWriter.SetParameter(videoSpecs.width, videoSpecs.height, videoSpecs.pixelType, videoSpecs.fps, videoSpecs.quality); qDebug() << "setting parameters for video";
videoWriter.SetParameter((uint32_t)videoSpecs.width, (uint32_t)videoSpecs.height, videoSpecs.pixelType, (double)videoSpecs.fps, videoSpecs.quality);
videoWriter.Open(videoSpecs.filename.c_str()); videoWriter.Open(videoSpecs.filename.c_str());
} }
@@ -90,6 +93,8 @@ void Writer::run() {
nix::NDSize offset(1, 0); nix::NDSize offset(1, 0);
nix::NDSize current_shape(initial_shape); nix::NDSize current_shape(initial_shape);
nix::NDSize chunk_shape(1, chunksize); nix::NDSize chunk_shape(1, chunksize);
qDebug() << "preparations done, starting loop!";
while ((!stop_request || buffer->bufferLoad() > 0) && !stopNow) { while ((!stop_request || buffer->bufferLoad() > 0) && !stopNow) {
if (buffer->bufferLoad() > 0 ) { if (buffer->bufferLoad() > 0 ) {
size_t framecount = 0; size_t framecount = 0;
@@ -107,7 +112,12 @@ void Writer::run() {
} }
} }
if (count < chunksize) { if (count < chunksize) {
stamps_buffer[count] = nix::util::timeToStr(img->timestamp()); try {
stamps_buffer[count] = nix::util::timeToStr(img->timestamp());
} catch (...) {
std::cerr << "Bad time to string conversion " << img->timestamp() << std::endl;
stamps_buffer[count] = "invalid";
}
ids_buffer[count] = img->index(); ids_buffer[count] = img->index();
count ++; count ++;
} else { } else {
@@ -131,7 +141,7 @@ void Writer::run() {
frametimes.setData(nix::DataType::String, stamps_buffer.data(), chunk_shape, offset); frametimes.setData(nix::DataType::String, stamps_buffer.data(), chunk_shape, offset);
frameindices.setData(nix::DataType::Int64, ids_buffer.data(), chunk_shape, offset); frameindices.setData(nix::DataType::Int64, ids_buffer.data(), chunk_shape, offset);
} }
// videoWriter.Close(); videoWriter.Close();
myFile.close(); myFile.close();
nix_file.close(); nix_file.close();
} else { } else {

View File

@@ -6,23 +6,11 @@
#include <pylon/PylonIncludes.h> #include <pylon/PylonIncludes.h>
#include <nix.hpp> #include <nix.hpp>
#include "pylonwrapper.h" #include "singlecamwrapper.h"
#include "imagebuffer.h" #include "imagebuffer.h"
#include "projectsettings.h" #include "projectsettings.h"
#include "util.h" #include "util.h"
struct VideoSpecs {
std::string filename;
uint32_t width, height, quality = 10;
uint32_t xoffset, yoffset = 0;
int fps;
double exposureTime;
double detectorGain;
Pylon::EPixelType pixelType;
Pylon::EImageOrientation orientation;
VideoFormat format = VideoFormat::raw;
};
class Writer : public QThread class Writer : public QThread
{ {
Q_OBJECT Q_OBJECT