Compare commits
18 Commits
41272ce08e
...
softwaretr
| Author | SHA1 | Date | |
|---|---|---|---|
| d20ea22beb | |||
| ec3844ba9c | |||
| 2bed70b971 | |||
| dadce69944 | |||
| d78b9d8b02 | |||
| 23b0a9afcd | |||
| fe20326953 | |||
| f803854da3 | |||
| 155ac6b471 | |||
| 18f088c4fd | |||
| a3418bc25e | |||
| ec203ba1ad | |||
| 5263d04cac | |||
| 03e5cd70c7 | |||
| e394c346ed | |||
| aa265565f2 | |||
| e9b195674c | |||
| 555098cdba |
@@ -42,7 +42,8 @@ find_package (NIX REQUIRED)
|
||||
include_directories (AFTER ${NIX_INCLUDE_DIR})
|
||||
|
||||
# #######################################
|
||||
# # OPENCV
|
||||
# OPENCV
|
||||
# message ("=> finding opencv ...")
|
||||
# find_package(OpenCV REQUIRED opencv_highgui opencv_core)
|
||||
# include_directories(AFTER ${OpenCV_INCLUDE_DIRS} )
|
||||
# set(LINK_LIBS ${LINK_LIBS} ${OpenCV_LIBRARIES})
|
||||
|
||||
@@ -86,6 +86,7 @@ void CamConfigurator::modeChanged(int idx) {
|
||||
stack->setCurrentIndex(1);
|
||||
QString device = device_combo->currentText();
|
||||
preview->setPrimaryCamera(device);
|
||||
mode_combo->setEnabled(false);
|
||||
} else if (idx == 2) {
|
||||
qDebug() << "Mode changed to dual camera mode";
|
||||
preview = stereoCameraView();
|
||||
@@ -100,6 +101,7 @@ void CamConfigurator::modeChanged(int idx) {
|
||||
}
|
||||
QString device2 = device_combo->itemText(1 - i);
|
||||
preview->setSecondaryCamera(device2);
|
||||
mode_combo->setEnabled(false);
|
||||
} else {
|
||||
qDebug() << "Mode changed mode selection";
|
||||
stack->setCurrentIndex(0);
|
||||
|
||||
@@ -60,13 +60,12 @@ CameraPreview::CameraPreview(QWidget *parent):cameraname(""), camera(nullptr), Q
|
||||
void CameraPreview::setCamera(QString &device){
|
||||
qDebug() << "update camera! ";// << device.toStdString();
|
||||
cameraname = device;
|
||||
label->setText(device);
|
||||
if (camera != NULL) {
|
||||
if (camera != nullptr) {
|
||||
qDebug() << "camera is not nullptr! ";
|
||||
delete camera;
|
||||
camera = nullptr;
|
||||
}
|
||||
camera = new PylonWrapper(cameraname.toStdString());
|
||||
camera = new SingleCamWrapper(cameraname.toStdString());
|
||||
std::string message;
|
||||
bool success = camera->openCamera(message);
|
||||
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>";
|
||||
msgBox.setText(msg);
|
||||
msgBox.exec();
|
||||
return;
|
||||
}
|
||||
label->setText(device + " - " + camera->userName());
|
||||
takeStill();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <QPainter>
|
||||
#include <pylon/PylonIncludes.h>
|
||||
|
||||
#include "pylonwrapper.h"
|
||||
#include "singlecamwrapper.h"
|
||||
#include "util.h"
|
||||
namespace Ui {
|
||||
class CameraPreview;
|
||||
@@ -53,7 +53,7 @@ private:
|
||||
void setImage(const QPixmap &img);
|
||||
void validate(QSpinBox *origin, QSpinBox *dest, int limit);
|
||||
|
||||
PylonWrapper *camera;
|
||||
SingleCamWrapper *camera;
|
||||
|
||||
};
|
||||
|
||||
|
||||
48
camids.cpp
Normal file
48
camids.cpp
Normal 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
45
camids.h
Normal 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
|
||||
|
||||
@@ -1,28 +1,72 @@
|
||||
#include "dualcamgrabber.h"
|
||||
#include <iostream>
|
||||
#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() {
|
||||
stop_request = false;
|
||||
size_t framecount = 0;
|
||||
size_t counter = 0;
|
||||
|
||||
if (wrapper->isOpen()) {
|
||||
Pylon::CInstantCameraArray &cameras = wrapper->getCameraArray();
|
||||
wrapper->frameRate(static_cast<uint>(framerate));
|
||||
wrapper->frameRate(static_cast<uint>(framerate), -1);
|
||||
wrapper->exposureTime(exposure);
|
||||
wrapper->gain(gain);
|
||||
|
||||
cameras.StartGrabbing();
|
||||
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) {
|
||||
// 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();
|
||||
cameras.RetrieveResult( 5000, framecount % 2 == 0 ? frame0 : frame1, Pylon::TimeoutHandling_ThrowException );
|
||||
img->setFrame(framecount % 2 == 0 ? frame0 : frame1);
|
||||
if (framecount % 2 == 0) {
|
||||
buffer0->push(img);
|
||||
} else {
|
||||
buffer1->push(img);
|
||||
// auto stop1 = high_resolution_clock::now();
|
||||
cameras[0].RetrieveResult( 5000, frame0, Pylon::TimeoutHandling_ThrowException );
|
||||
// auto stop2 = high_resolution_clock::now();
|
||||
cameras[1].RetrieveResult( 5000, frame1, Pylon::TimeoutHandling_ThrowException );
|
||||
// auto stop3 = high_resolution_clock::now();
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ class DualcamGrabber : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DualcamGrabber(DualcamWrapper *wrapper, ImageBuffer *buffer0, ImageBuffer * buffer1, int framerate, QObject *parent = nullptr) :
|
||||
QThread(parent), wrapper(wrapper), buffer0(buffer0), buffer1(buffer1), framerate(framerate) {}
|
||||
DualcamGrabber(DualcamWrapper *wrapper, ImageBuffer *buffer, int framerate, QObject *parent = nullptr) :
|
||||
QThread(parent), wrapper(wrapper), buffer(buffer), framerate(framerate) {}
|
||||
|
||||
void run() override;
|
||||
void stop();
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
private:
|
||||
bool stop_request = false;
|
||||
DualcamWrapper *wrapper;
|
||||
ImageBuffer *buffer0, *buffer1;
|
||||
ImageBuffer *buffer;
|
||||
int framerate;
|
||||
double exposure, gain;
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ void DualcamWrapper::terminate() {
|
||||
|
||||
|
||||
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, 1);
|
||||
return true;
|
||||
} else if (camindex == 0 && camindex ==1) {
|
||||
GenApi::INodeMap& nodemap = getNodemap(0);
|
||||
} else if (camindex >= 0 && camindex < 2) {
|
||||
GenApi::INodeMap& nodemap = getNodemap(camindex);
|
||||
GenApi::INode* n = nodemap.GetNode( "AcquisitionFrameRateEnable" );
|
||||
Pylon::CBooleanParameter enableframerate(n);
|
||||
enableframerate.SetValue(true);
|
||||
@@ -72,7 +72,7 @@ bool DualcamWrapper::frameRate(uint new_framerate, int camindex) {
|
||||
|
||||
|
||||
double DualcamWrapper::frameRate(int camindex) {
|
||||
assert(camindex > 0 && camindex < 2);
|
||||
assert(camindex >= 0 && camindex < 2);
|
||||
double rate = -1.;
|
||||
if (valid) {
|
||||
GenApi::INodeMap& nodemap = getNodemap(camindex);
|
||||
@@ -173,14 +173,14 @@ bool DualcamWrapper::grabFrame(MyImage &img, int camindex) {
|
||||
qDebug() << "grabFrame from camera " << camindex;
|
||||
if (valid) {
|
||||
GenApi::INodeMap &nodemap = getNodemap(camindex);
|
||||
qDebug() << "Setting width" << layout.rois[0].width;
|
||||
Pylon::CIntegerParameter(nodemap, "Width").SetValue(layout.rois[0].width);
|
||||
qDebug() << "Setting width" << layout.rois[camindex].width;
|
||||
Pylon::CIntegerParameter(nodemap, "Width").SetValue(layout.rois[camindex].width);
|
||||
qDebug() << "Setting height" << layout.rois[0].height;
|
||||
Pylon::CIntegerParameter(nodemap, "Height").SetValue(layout.rois[0].height);
|
||||
qDebug() << "Setting xoffset" << layout.rois[0].x;
|
||||
Pylon::CIntegerParameter(nodemap, "OffsetX").SetValue(layout.rois[0].x);
|
||||
qDebug() << "Setting yoffset" << layout.rois[0].y;
|
||||
Pylon::CIntegerParameter(nodemap, "OffsetY").SetValue(layout.rois[0].y);
|
||||
Pylon::CIntegerParameter(nodemap, "Height").SetValue(layout.rois[camindex].height);
|
||||
qDebug() << "Setting xoffset" << layout.rois[camindex].x;
|
||||
Pylon::CIntegerParameter(nodemap, "OffsetX").SetValue(layout.rois[camindex].x);
|
||||
qDebug() << "Setting yoffset" << layout.rois[camindex].y;
|
||||
Pylon::CIntegerParameter(nodemap, "OffsetY").SetValue(layout.rois[camindex].y);
|
||||
|
||||
camera->StartGrabbing();
|
||||
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) {
|
||||
GenApi::INodeMap &nodemap = getNodemap( camindex );
|
||||
int64_t dfltWidth = 2048;
|
||||
int64_t dfltHeight = 1536;
|
||||
qDebug() << "resetting camera to default ROI (" << dfltWidth << ", " << dfltHeight << ")";
|
||||
try {
|
||||
// std::cerr << "MaxWidth: " << Pylon::CIntegerParameter(nodemap, "WidthMax").GetValue() << std::endl;
|
||||
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, "OffsetX").SetValue(0);
|
||||
Pylon::CIntegerParameter(nodemap, "OffsetY").SetValue(0);
|
||||
@@ -213,7 +223,6 @@ void DualcamWrapper::resetCamera(int camindex) {
|
||||
|
||||
bool DualcamWrapper::openCameras(std::string &message) {
|
||||
qDebug() << "opening cameras";
|
||||
bool valid = true;
|
||||
Pylon::CTlFactory& tlFactory = Pylon::CTlFactory::GetInstance();
|
||||
cameras.Initialize(2);
|
||||
try {
|
||||
@@ -230,8 +239,9 @@ bool DualcamWrapper::openCameras(std::string &message) {
|
||||
valid = false;
|
||||
return valid;
|
||||
}
|
||||
resetCamera(0);
|
||||
resetCamera(1);
|
||||
// resetCamera(0);
|
||||
// resetCamera(1);
|
||||
setROI();
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ public:
|
||||
DualcamWrapper(const CameraLayout &layout);
|
||||
~DualcamWrapper();
|
||||
|
||||
|
||||
ImageSettings getImageSettings(int camindex);
|
||||
bool isOpen();
|
||||
void terminate();
|
||||
@@ -30,12 +29,12 @@ public:
|
||||
double gain(int camindex);
|
||||
bool gain(double gain_db, int camindex=-1);
|
||||
Pylon::CInstantCameraArray &getCameraArray();
|
||||
// Pylon::CInstantCamera getCamera(int camindex);
|
||||
|
||||
private:
|
||||
void resetCamera(int camindex);
|
||||
Pylon::CInstantCameraArray cameras;
|
||||
GenApi::INodeMap& getNodemap(int camindex);
|
||||
void setROI();
|
||||
bool valid, withLayout;
|
||||
CameraLayout layout;
|
||||
|
||||
|
||||
@@ -72,7 +72,6 @@ void ImageBuffer::push(MyImage *img) {
|
||||
buffer[head_idx] = img;
|
||||
framecounts[head_idx] = framecount;
|
||||
load = load < buffer_size ? load +=1 : buffer_size;
|
||||
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
@@ -111,6 +110,6 @@ MyImage* ImageBuffer::readLast(size_t &framecount) {
|
||||
}
|
||||
|
||||
ImageBuffer::~ImageBuffer(){
|
||||
std::cerr << "Image buffer destructor" << std::endl;
|
||||
qDebug() << "Image buffer destructor";
|
||||
clear();
|
||||
}
|
||||
12
myimage.cpp
12
myimage.cpp
@@ -21,6 +21,18 @@ bool MyImage::setFrame(Pylon::CGrabResultPtr ptr) {
|
||||
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() {
|
||||
return static_cast<int>(img_width);
|
||||
}
|
||||
|
||||
@@ -16,13 +16,14 @@ public:
|
||||
void* data();
|
||||
time_t timestamp();
|
||||
bool setFrame(Pylon::CGrabResultPtr ptr);
|
||||
bool setFrame(Pylon::CPylonImage &img);
|
||||
|
||||
private:
|
||||
uint32_t img_width = 0;
|
||||
uint32_t img_height = 0;
|
||||
int64_t img_index = 0;
|
||||
time_t img_timestamp;
|
||||
static const int max_width = 2048;
|
||||
static const int max_width = 4096;
|
||||
static const int max_height = 1536;
|
||||
char buffer[max_width * max_height];
|
||||
};
|
||||
|
||||
@@ -34,8 +34,7 @@
|
||||
PylonRecorder::PylonRecorder(QWidget *parent)
|
||||
: QMainWindow(parent), imageLabel(new QLabel), scrollArea(new QScrollArea),
|
||||
singlecamgrabber(nullptr), dualcamgrabber(nullptr),
|
||||
writer0(nullptr), writer1(nullptr),
|
||||
buffer0(nullptr), buffer1(nullptr),
|
||||
writer(nullptr), buffer(nullptr),
|
||||
singlecam(nullptr), dualcam(nullptr),
|
||||
dryRun(false), cameraOpened(false), camsconfigured(false)
|
||||
{
|
||||
@@ -62,8 +61,8 @@ PylonRecorder::PylonRecorder(QWidget *parent)
|
||||
QPalette progressPalette = pressureBar->palette();
|
||||
progressPalette.setBrush(QPalette::Highlight, QBrush(color));
|
||||
pressureBar->setPalette(progressPalette);
|
||||
QLabel *preassureLabel = new QLabel("Buffer preassure:", this);
|
||||
preassureLabel->setStyleSheet("QLabel{font-size: 11pt;font-family: Arial;font-weight: Bold}");
|
||||
QLabel *pressureLabel = new QLabel("Buffer pressure:", this);
|
||||
pressureLabel->setStyleSheet("QLabel{font-size: 11pt;font-family: Arial;font-weight: Bold}");
|
||||
loadBar = new QProgressBar(this);
|
||||
loadBar->setRange(0, defaultBufferSize);
|
||||
loadBar->setFixedSize(200, 25);
|
||||
@@ -90,7 +89,7 @@ PylonRecorder::PylonRecorder(QWidget *parent)
|
||||
fileHeader->setStyleSheet("QLabel{font-size: 11pt;font-family: Arial; font-weight: Bold}");
|
||||
statusBar()->addWidget(camHeader);
|
||||
statusBar()->addWidget(cameraConnectedLabel);
|
||||
statusBar()->addWidget(preassureLabel);
|
||||
statusBar()->addWidget(pressureLabel);
|
||||
statusBar()->addWidget(pressureBar);
|
||||
statusBar()->addWidget(loadLabel);
|
||||
statusBar()->addWidget(loadBar);
|
||||
@@ -119,9 +118,9 @@ PylonRecorder::~PylonRecorder(){
|
||||
singlecamgrabber->requestStop();
|
||||
singlecamgrabber->wait(1000);
|
||||
}
|
||||
if (writer0 != nullptr && writer0->isRunning()) {
|
||||
writer0->forceStop();
|
||||
writer0->wait(1000);
|
||||
if (writer != nullptr && writer->isRunning()) {
|
||||
writer->forceStop();
|
||||
writer->wait(1000);
|
||||
}
|
||||
storeSettings();
|
||||
if (singlecam != nullptr) {
|
||||
@@ -135,16 +134,12 @@ PylonRecorder::~PylonRecorder(){
|
||||
dualcam = nullptr;
|
||||
}
|
||||
|
||||
if (buffer0 != nullptr) {
|
||||
if (buffer != nullptr) {
|
||||
qDebug() << "Deleting buffer";
|
||||
delete buffer0;
|
||||
buffer0 = nullptr;
|
||||
}
|
||||
if (buffer1 != nullptr) {
|
||||
qDebug() << "Deleting buffer";
|
||||
delete buffer1;
|
||||
buffer1 = nullptr;
|
||||
delete buffer;
|
||||
buffer = nullptr;
|
||||
}
|
||||
|
||||
if (singlecamgrabber != nullptr) {
|
||||
qDebug() << "Deleting grabber";
|
||||
delete singlecamgrabber;
|
||||
@@ -155,15 +150,10 @@ PylonRecorder::~PylonRecorder(){
|
||||
delete dualcamgrabber;
|
||||
dualcamgrabber = nullptr;
|
||||
}
|
||||
if (writer0 != nullptr) {
|
||||
if (writer != nullptr) {
|
||||
qDebug() << "Deleting writer";
|
||||
delete writer0;
|
||||
writer0 = nullptr;
|
||||
}
|
||||
if (writer1 != nullptr) {
|
||||
qDebug() << "Deleting writer";
|
||||
delete writer1;
|
||||
writer1 = nullptr;
|
||||
delete writer;
|
||||
writer = nullptr;
|
||||
}
|
||||
qDebug() << "Deleting setting";
|
||||
delete settings;
|
||||
@@ -206,11 +196,8 @@ bool PylonRecorder::loadFile(const QString &fileName) {
|
||||
.arg(QDir::toNativeSeparators(fileName), reader.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
setImage(newImage);
|
||||
|
||||
setWindowFilePath(fileName);
|
||||
|
||||
const QString message = tr("Opened \"%1\", %2x%3, Depth: %4")
|
||||
.arg(QDir::toNativeSeparators(fileName)).arg(image.width()).arg(image.height()).arg(image.depth());
|
||||
statusBar()->showMessage(message);
|
||||
@@ -293,8 +280,8 @@ void PylonRecorder::saveAs() {
|
||||
|
||||
|
||||
void PylonRecorder::print() {
|
||||
QPixmap map = imageLabel->pixmap(Qt::ReturnByValue);
|
||||
Q_ASSERT(!map.isNull());
|
||||
const QPixmap *map = imageLabel->pixmap();
|
||||
Q_ASSERT(!map->isNull());
|
||||
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog)
|
||||
|
||||
QPrintDialog dialog(&printer, this);
|
||||
@@ -302,11 +289,11 @@ void PylonRecorder::print() {
|
||||
if (dialog.exec()) {
|
||||
QPainter painter(&printer);
|
||||
QRect rect = painter.viewport();
|
||||
QSize size = map.size();
|
||||
QSize size = map->size();
|
||||
size.scale(rect.size(), Qt::KeepAspectRatio);
|
||||
painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
|
||||
painter.setWindow(map.rect());
|
||||
painter.drawPixmap(0, 0, map);
|
||||
painter.setWindow(map->rect());
|
||||
painter.drawPixmap(0, 0, *map);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -447,6 +434,7 @@ void PylonRecorder::createActions() {
|
||||
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->setStatusTip(tr("Disconnect from the camera device"));
|
||||
disconnect_camera_action->setEnabled(false);
|
||||
camera_menu->addSeparator();
|
||||
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"));
|
||||
@@ -455,6 +443,9 @@ void PylonRecorder::createActions() {
|
||||
grab_continuous_action->setShortcut(tr("Ctrl+Enter"));
|
||||
grab_stop_action = camera_menu->addAction(stop_icon, tr("&stop grabbing"), this, &PylonRecorder::stopRecording);
|
||||
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->setStatusTip(tr("Select a storage location for the recorded videos"));
|
||||
@@ -547,20 +538,42 @@ void PylonRecorder::updateActions() {
|
||||
zoomInAct->setEnabled(!fitToWindowAct->isChecked());
|
||||
zoomOutAct->setEnabled(!fitToWindowAct->isChecked());
|
||||
normalSizeAct->setEnabled(!fitToWindowAct->isChecked());
|
||||
disconnect_camera_action->setEnabled(deviceList.size() > 0);
|
||||
disconnect_camera_action->setEnabled(cameraOpened);
|
||||
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(!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) {
|
||||
QPixmap map = imageLabel->pixmap(Qt::ReturnByValue);
|
||||
Q_ASSERT(!map.isNull());
|
||||
const QPixmap *map = imageLabel->pixmap();
|
||||
Q_ASSERT(!map->isNull());
|
||||
scaleFactor *= factor;
|
||||
imageLabel->resize(scaleFactor * map.size());
|
||||
imageLabel->resize(scaleFactor * map->size());
|
||||
|
||||
adjustScrollBar(scrollArea->horizontalScrollBar(), factor);
|
||||
adjustScrollBar(scrollArea->verticalScrollBar(), factor);
|
||||
@@ -571,7 +584,7 @@ void PylonRecorder::scaleImage(double factor) {
|
||||
|
||||
|
||||
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(){
|
||||
d = new CamConfigurator(deviceList, this);
|
||||
connect(d, SIGNAL(accepted()), SLOT(cameraConfigurationAccepted()));
|
||||
connect(d, SIGNAL(rejected()), SLOT(cameraConfigurationAborted()));
|
||||
cameraConfigDialog = new CamConfigurator(deviceList, this);
|
||||
connect(cameraConfigDialog, SIGNAL(accepted()), SLOT(cameraConfigurationAccepted()));
|
||||
connect(cameraConfigDialog, SIGNAL(rejected()), SLOT(cameraConfigurationAborted()));
|
||||
// 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() {
|
||||
qDebug() << "Cameras setting " << ((d->result()) ? "Accepted" : "Discarded");
|
||||
this->layout = d->layout();
|
||||
qDebug() << "Cameras setting " << ((cameraConfigDialog->result()) ? "Accepted" : "Discarded");
|
||||
this->layout = cameraConfigDialog->layout();
|
||||
camsconfigured = true;
|
||||
delete d;
|
||||
delete cameraConfigDialog;
|
||||
}
|
||||
|
||||
|
||||
@@ -619,7 +632,6 @@ void PylonRecorder::cameraConfigurationAborted() {
|
||||
|
||||
void PylonRecorder::connectCamera() {
|
||||
this->layout = CameraLayout();
|
||||
std::cerr << this->layout.rois.size() << " " << this->layout.devices.size() << std::endl;
|
||||
qDebug() << "connecting camera(s)";
|
||||
if (deviceList.size() == 0) {
|
||||
detectCameras();
|
||||
@@ -640,7 +652,7 @@ void PylonRecorder::connectCamera() {
|
||||
std::string cname = layout.devices[0];
|
||||
std::string message;
|
||||
qDebug() << "connecting to camera " << cname.c_str();
|
||||
singlecam = new PylonWrapper(layout);
|
||||
singlecam = new SingleCamWrapper(layout);
|
||||
bool success = singlecam->openCamera(message);
|
||||
if (success) {
|
||||
cameraConnectedLabel->setText("connected");
|
||||
@@ -657,10 +669,8 @@ void PylonRecorder::connectCamera() {
|
||||
updateActions();
|
||||
}
|
||||
if (layout.mode == CameraMode::dual && layout.devices.size() == 2) {
|
||||
std::cerr << "Dual MODE" << std::endl;
|
||||
qDebug() << "dual camera mode";
|
||||
std::string message;
|
||||
qDebug() << "creating dual cam wrapper";
|
||||
dualcam = new DualcamWrapper(layout);
|
||||
bool success = dualcam->openCameras(message);
|
||||
if (success) {
|
||||
@@ -700,20 +710,22 @@ void PylonRecorder::disconnectCamera() {
|
||||
|
||||
VideoSpecs PylonRecorder::getVideoSpecs(const ImageSettings &settings) {
|
||||
VideoSpecs s = VideoSpecs();
|
||||
if (this->layout.mode == CameraMode::single && this->layout.devices.size() > 0) {
|
||||
s.fps = framerateSpinner->value();
|
||||
s.exposureTime = static_cast<double>(exposureSpinner->value());
|
||||
s.detectorGain = static_cast<double>(gainSpinner->value());
|
||||
if (!this->layout.devices.size() > 0) {
|
||||
return s;
|
||||
}
|
||||
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.height = static_cast<uint32_t>(this->layout.rois[0].height);
|
||||
s.xoffset = static_cast<uint32_t>(this->layout.rois[0].x);
|
||||
s.yoffset = static_cast<uint32_t>(this->layout.rois[0].y);
|
||||
|
||||
s.pixelType = settings.pixelType;
|
||||
s.orientation = settings.orientation;
|
||||
s.quality = 95;
|
||||
} else {
|
||||
qWarning() << "Dual camera mode not supported yet!";
|
||||
} else if (layout.mode == CameraMode::dual) {
|
||||
s.width = static_cast<uint32_t>(this->layout.rois[0].width * 2);
|
||||
s.height = static_cast<uint32_t>(this->layout.rois[0].height);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -721,7 +733,7 @@ VideoSpecs PylonRecorder::getVideoSpecs(const ImageSettings &settings) {
|
||||
|
||||
void PylonRecorder::startSinglecamRecording() {
|
||||
qDebug() << "start single-camera recording!";
|
||||
std::string filename = createFilename(".mp4");
|
||||
std::string filename = createFilename("", ".mp4");
|
||||
fileLabel->setText(QString::fromStdString(filename));
|
||||
qDebug() << "storing to file " << filename.c_str();
|
||||
|
||||
@@ -733,15 +745,15 @@ void PylonRecorder::startSinglecamRecording() {
|
||||
specs.format = VideoFormat::mp4;
|
||||
qDebug() << "got video specifications";
|
||||
|
||||
if (buffer0 != nullptr) {
|
||||
buffer0->clear();
|
||||
delete buffer0;
|
||||
buffer0 = nullptr;
|
||||
if (buffer != nullptr) {
|
||||
buffer->clear();
|
||||
delete buffer;
|
||||
buffer = nullptr;
|
||||
}
|
||||
qDebug() << "setting image buffer to size " << buffersizeSpinner->value();
|
||||
buffer0 = new ImageBuffer(defaultBufferSize);
|
||||
if (buffersizeSpinner->value() != static_cast<int>(buffer0->capacity())) {
|
||||
buffer0->resize(static_cast<size_t>(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());
|
||||
}
|
||||
|
||||
@@ -750,7 +762,7 @@ void PylonRecorder::startSinglecamRecording() {
|
||||
delete singlecamgrabber;
|
||||
singlecamgrabber = nullptr;
|
||||
}
|
||||
singlecamgrabber = new Grabber(singlecam, buffer0, defaultFrameRate);
|
||||
singlecamgrabber = new SinglecamGrabber(singlecam, buffer, defaultFrameRate);
|
||||
|
||||
if (framerateSpinner->value() != singlecamgrabber->currentFramerate())
|
||||
singlecamgrabber->setFrameRate(framerateSpinner->value());
|
||||
@@ -760,22 +772,21 @@ void PylonRecorder::startSinglecamRecording() {
|
||||
singlecamgrabber->setGain(static_cast<double>(gainSpinner->value()));
|
||||
|
||||
qDebug() << "setup writer";
|
||||
if (writer0 != nullptr) {
|
||||
delete writer0;
|
||||
writer0 = nullptr;
|
||||
if (writer != nullptr) {
|
||||
delete writer;
|
||||
writer = nullptr;
|
||||
}
|
||||
writer0 = new Writer(buffer0, 0);
|
||||
connect(writer0, SLOT(writingDone( int)), this, SLOT(writerDone( int )));
|
||||
writer0->setVideoSpecs(specs);
|
||||
writer = new Writer(buffer);
|
||||
connect(writer, SIGNAL(writingDone()), this, SLOT(writerDone()));
|
||||
writer->setVideoSpecs(specs);
|
||||
|
||||
QSettings s;
|
||||
this->mdata.read(s);
|
||||
writer0->setProjectMetadata(mdata);
|
||||
writer->setProjectMetadata(mdata);
|
||||
|
||||
buffer0->clear();
|
||||
buffer->clear();
|
||||
if (!dryRunCheckBox->isChecked()) {
|
||||
writer0->start();
|
||||
iswriting[0] = true;
|
||||
writer->start();
|
||||
writing = true;
|
||||
}
|
||||
dryRun = dryRunCheckBox->isChecked();
|
||||
@@ -787,51 +798,35 @@ void PylonRecorder::startSinglecamRecording() {
|
||||
|
||||
void PylonRecorder::startDualcamRecording() {
|
||||
qDebug() << "start dual-camera recording!";
|
||||
std::string filenamea = createFilename("a", ".mp4");
|
||||
std::string filenameb = createFilename("b", ".mp4");
|
||||
fileLabel->setText(QString::fromStdString(filenamea + " & " + filenameb));
|
||||
qDebug() << "storing to files " << filenamea.c_str() << ", " << filenameb.c_str();
|
||||
std::string filename = createFilename("", ".mp4");
|
||||
fileLabel->setText(QString::fromStdString(filename));
|
||||
qDebug() << "storing to file " << filename.c_str();
|
||||
|
||||
ImageSettings settings = dualcam->getImageSettings(0);
|
||||
ImageSettings settings = dualcam->getImageSettings(0); //FIXME!
|
||||
qDebug() << "got image settings";
|
||||
|
||||
VideoSpecs specsa = getVideoSpecs(settings);
|
||||
specsa.filename = filenamea;
|
||||
specsa.format = VideoFormat::mp4;
|
||||
|
||||
VideoSpecs specsb = getVideoSpecs(settings);
|
||||
specsb.filename = filenameb;
|
||||
specsb.format = VideoFormat::mp4;
|
||||
qDebug() << "got video specifications";
|
||||
|
||||
if (buffer0 != nullptr) {
|
||||
buffer0->clear();
|
||||
delete buffer0;
|
||||
buffer0 = nullptr;
|
||||
}
|
||||
if (buffer1 != nullptr) {
|
||||
buffer1->clear();
|
||||
delete buffer1;
|
||||
buffer1 = nullptr;
|
||||
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();
|
||||
buffer0 = new ImageBuffer(defaultBufferSize);
|
||||
if (buffersizeSpinner->value() != static_cast<int>(buffer0->capacity())) {
|
||||
buffer0->resize(static_cast<size_t>(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());
|
||||
}
|
||||
buffer1 = new ImageBuffer(defaultBufferSize);
|
||||
if (buffersizeSpinner->value() != static_cast<int>(buffer1->capacity())) {
|
||||
buffer1->resize(static_cast<size_t>(buffersizeSpinner->value()));
|
||||
}
|
||||
|
||||
qDebug() << "setting up grabber";
|
||||
if (dualcamgrabber != nullptr) {
|
||||
delete dualcamgrabber;
|
||||
dualcamgrabber = nullptr;
|
||||
}
|
||||
dualcamgrabber = new DualcamGrabber(dualcam, buffer0, buffer1, defaultFrameRate);
|
||||
dualcamgrabber = new DualcamGrabber(dualcam, buffer, defaultFrameRate);
|
||||
if (framerateSpinner->value() != dualcamgrabber->currentFramerate())
|
||||
dualcamgrabber->setFrameRate(framerateSpinner->value());
|
||||
if (exposureSpinner->value() != int(dualcamgrabber->currentExposureTime()))
|
||||
@@ -840,42 +835,26 @@ void PylonRecorder::startDualcamRecording() {
|
||||
dualcamgrabber->setGain(static_cast<double>(gainSpinner->value()));
|
||||
|
||||
qDebug() << "setting up writers";
|
||||
if (writer0 != nullptr) {
|
||||
delete writer0;
|
||||
writer0 = nullptr;
|
||||
if (writer != nullptr) {
|
||||
delete writer;
|
||||
writer = nullptr;
|
||||
}
|
||||
writer0 = new Writer(buffer0, 0);
|
||||
connect(writer0, SIGNAL(writingDone(int)), this, SLOT(writerDone( int )));
|
||||
writer0->setVideoSpecs(specsa);
|
||||
|
||||
if (writer1 != nullptr) {
|
||||
delete writer1;
|
||||
writer1 = nullptr;
|
||||
}
|
||||
writer1 = new Writer(buffer1, 1);
|
||||
connect(writer1, SIGNAL(writingDone(int)), this, SLOT(writerDone( int )));
|
||||
writer1->setVideoSpecs(specsb);
|
||||
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);
|
||||
writer0->setProjectMetadata(mdata);
|
||||
|
||||
buffer0->clear();
|
||||
if (!dryRunCheckBox->isChecked()) {
|
||||
writer0->start();
|
||||
writing = true;
|
||||
iswriting[0] = true;
|
||||
}
|
||||
|
||||
buffer1->clear();
|
||||
if (!dryRunCheckBox->isChecked()) {
|
||||
writer1->start();
|
||||
writing = true;
|
||||
iswriting[1] = true;
|
||||
}
|
||||
writer->setProjectMetadata(mdata);
|
||||
|
||||
dryRun = dryRunCheckBox->isChecked();
|
||||
buffer->clear();
|
||||
if (!dryRun) {
|
||||
writer->start();
|
||||
writing = true;
|
||||
}
|
||||
|
||||
dualcamgrabber->start();
|
||||
grabbing = true;
|
||||
stopRequest = false;
|
||||
@@ -906,37 +885,27 @@ void PylonRecorder::stopRecording() {
|
||||
qDebug() << "StopRecording: stop grabber!";
|
||||
if (singlecamgrabber !=nullptr)
|
||||
singlecamgrabber->requestStop();
|
||||
qDebug() << "StopRecording: stop writer!";
|
||||
if (writer0 != nullptr)
|
||||
writer0->requestStop();
|
||||
if (writer1 != nullptr)
|
||||
writer1->requestStop();
|
||||
if (dualcamgrabber !=nullptr)
|
||||
dualcamgrabber->requestStop();
|
||||
|
||||
qDebug() << "StopRecording: stop writer!";
|
||||
if (writer != nullptr)
|
||||
writer->requestStop();
|
||||
grabbing = false;
|
||||
stopRequest = true;
|
||||
grab_stop_action->setEnabled(false);
|
||||
qDebug() << "StopRecording: clear buffer!";
|
||||
if(buffer0 != nullptr) {
|
||||
buffer0->clear();
|
||||
// writerDone( 0 ); // Needed? or even dangerous?
|
||||
}
|
||||
qDebug() << "StopRecording: clear buffer!";
|
||||
if(buffer1 != nullptr) {
|
||||
buffer1->clear();
|
||||
// writerDone( 1 );
|
||||
if(buffer != nullptr) {
|
||||
buffer->clear();
|
||||
if (dryRun)
|
||||
writerDone();
|
||||
}
|
||||
}
|
||||
qDebug() << "StopRecording done!";
|
||||
}
|
||||
|
||||
|
||||
void PylonRecorder::writerDone(int cam) {
|
||||
std::cerr << "writer " << cam << "is Done!!!" << std::endl;
|
||||
iswriting[cam] = false;
|
||||
if (iswriting[0] + iswriting[1] > 0) {
|
||||
qDebug() << "waiting for the other writer to finish";
|
||||
return;
|
||||
}
|
||||
void PylonRecorder::writerDone() {
|
||||
pressureTimer->stop();
|
||||
pressureBar->reset();
|
||||
loadBar->reset();
|
||||
@@ -948,13 +917,9 @@ void PylonRecorder::writerDone(int cam) {
|
||||
} else {
|
||||
dualcamgrabber->wait(10000);
|
||||
}
|
||||
if (writer0 != nullptr)
|
||||
writer0->wait(10000);
|
||||
if (writer1 != nullptr)
|
||||
writer1->wait(10000);
|
||||
if (writer != nullptr)
|
||||
writer->wait(10000);
|
||||
writing = false;
|
||||
iswriting[0] = false;
|
||||
iswriting[1] = false;
|
||||
updateActions();
|
||||
qInfo() << "writer is Done!";
|
||||
}
|
||||
@@ -970,9 +935,8 @@ void PylonRecorder::displayActivity() {
|
||||
void PylonRecorder::displaySingleFrame() {
|
||||
MyImage *img;
|
||||
size_t fc = 0;
|
||||
img = buffer0->readLast(fc);
|
||||
img = buffer->readLast(fc);
|
||||
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);
|
||||
setImage(qimg);
|
||||
}else {
|
||||
@@ -1008,13 +972,13 @@ std::string PylonRecorder::createFilename(const std::string &suffix, const std::
|
||||
|
||||
|
||||
void PylonRecorder::displayBufferPressure() {
|
||||
int value = static_cast<int>(round(buffer0->bufferPressure()));
|
||||
int value = static_cast<int>(round(buffer->bufferPressure()));
|
||||
pressureBar->setValue(value);
|
||||
QColor color = progressColor(value);
|
||||
progressPalette.setBrush(QPalette::Highlight, QBrush(color));
|
||||
pressureBar->setPalette(progressPalette);
|
||||
|
||||
int load = static_cast<int>(buffer0->bufferLoad());
|
||||
int load = static_cast<int>(buffer->bufferLoad());
|
||||
loadBar->setValue(load);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,14 +7,15 @@
|
||||
#include <QCheckBox>
|
||||
#include <QSettings>
|
||||
#include <pylon/PylonIncludes.h>
|
||||
#include "pylonwrapper.h"
|
||||
#include "singlecamwrapper.h"
|
||||
#include "dualcamwrapper.h"
|
||||
#include "imagebuffer.h"
|
||||
#include "grabber.h"
|
||||
#include "singlecamgrabber.h"
|
||||
#include "dualcamgrabber.h"
|
||||
#include "writer.h"
|
||||
#include "projectsettings.h"
|
||||
#include "camconfig.h"
|
||||
#include "camids.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <QImage>
|
||||
@@ -66,10 +67,12 @@ private slots:
|
||||
void displaySingleFrame();
|
||||
void displayBufferPressure();
|
||||
void displayActivity();
|
||||
void writerDone(int cam);
|
||||
void writerDone();
|
||||
void selectStorageLocation();
|
||||
void cameraConfigurationAccepted();
|
||||
void cameraConfigurationAborted();
|
||||
void setCameraIDs();
|
||||
void cameraIDAccepted();
|
||||
|
||||
private:
|
||||
void createActions();
|
||||
@@ -86,7 +89,6 @@ private:
|
||||
VideoSpecs getVideoSpecs(const ImageSettings &settings);
|
||||
void startSinglecamRecording();
|
||||
void startDualcamRecording();
|
||||
|
||||
bool saveFile(const QString &fileName);
|
||||
void setImage(const QImage &newImage);
|
||||
void scaleImage(double factor);
|
||||
@@ -103,15 +105,14 @@ private:
|
||||
QProgressBar *loadBar;
|
||||
QScrollArea *scrollArea;
|
||||
double scaleFactor = 1;
|
||||
PylonWrapper *singlecam;
|
||||
SingleCamWrapper *singlecam;
|
||||
DualcamWrapper *dualcam;
|
||||
ImageBuffer *buffer0, *buffer1;
|
||||
Grabber *singlecamgrabber;
|
||||
ImageBuffer *buffer;
|
||||
SinglecamGrabber *singlecamgrabber;
|
||||
DualcamGrabber *dualcamgrabber;
|
||||
Writer *writer0, *writer1;
|
||||
Writer *writer;
|
||||
CameraLayout layout;
|
||||
bool grabbing, stopRequest, writing, labelSwitch, dryRun, cameraOpened, camsconfigured;
|
||||
bool iswriting[2] = {0, 0};
|
||||
QPalette progressPalette;
|
||||
QString activeLabelStyleHigh = "QLabel { font-size: 10pt;font-family: Arial; color : red; }";
|
||||
QString activeLabelStyleLow = "QLabel { font-size: 10pt;font-family: Arial; color : cmyk(0, 255, 255, 0, 50); }";
|
||||
@@ -122,8 +123,9 @@ private:
|
||||
QString storageLocation = "";
|
||||
ProjectMetadata mdata;
|
||||
Pylon::DeviceInfoList_t deviceList;
|
||||
CamConfigurator *d;
|
||||
Pylon::PylonAutoInitTerm autoInitTerm;
|
||||
CamConfigurator *cameraConfigDialog;
|
||||
CameraID *cameraIdDialog;
|
||||
|
||||
|
||||
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer)
|
||||
@@ -142,6 +144,7 @@ private:
|
||||
QAction *grab_stop_action;
|
||||
QAction *connect_camera_action;
|
||||
QAction *disconnect_camera_action;
|
||||
QAction *set_cam_identifier_action;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "grabber.h"
|
||||
#include "singlecamgrabber.h"
|
||||
#include <iostream>
|
||||
#include <pylon/PylonIncludes.h>
|
||||
|
||||
void Grabber::run() {
|
||||
void SinglecamGrabber::run() {
|
||||
stop_request = false;
|
||||
int count = 0;
|
||||
if (camera->isOpen()) {
|
||||
@@ -1,16 +1,16 @@
|
||||
#ifndef GRABBER_H
|
||||
#define GRABBER_H
|
||||
#ifndef SINGLECAMGRABBER_H
|
||||
#define SINGLECAMGRABBER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include "pylonwrapper.h"
|
||||
#include "singlecamwrapper.h"
|
||||
#include "imagebuffer.h"
|
||||
|
||||
class Grabber : public QThread
|
||||
class SinglecamGrabber : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
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) {}
|
||||
|
||||
void run() override;
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
|
||||
private:
|
||||
bool stop_request = false;
|
||||
PylonWrapper *camera;
|
||||
SingleCamWrapper *camera;
|
||||
ImageBuffer *buffer;
|
||||
int framerate;
|
||||
double exposure, gain;
|
||||
@@ -51,4 +51,4 @@ signals:
|
||||
void terminated();
|
||||
};
|
||||
|
||||
#endif // GRABBER_H
|
||||
#endif // SINGLECAMGRABBER_H
|
||||
@@ -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) {
|
||||
qDebug() << "Constructor with name";
|
||||
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";
|
||||
this->fullName = layout.devices[0];
|
||||
this->layout = layout;
|
||||
Pylon::PylonInitialize();
|
||||
}
|
||||
|
||||
PylonWrapper::~PylonWrapper() {
|
||||
SingleCamWrapper::~SingleCamWrapper() {
|
||||
qDebug() << "wrapper destructor";
|
||||
if (camera != nullptr){
|
||||
if (camera->IsOpen()) {
|
||||
@@ -27,7 +27,7 @@ PylonWrapper::~PylonWrapper() {
|
||||
qDebug() << "Successfully deleted camera";
|
||||
}
|
||||
|
||||
void PylonWrapper::terminate() {
|
||||
void SingleCamWrapper::terminate() {
|
||||
qDebug() << "Terminate";
|
||||
try {
|
||||
Pylon::PylonTerminate();
|
||||
@@ -36,11 +36,11 @@ void PylonWrapper::terminate() {
|
||||
}
|
||||
}
|
||||
|
||||
bool PylonWrapper::isOpen() {
|
||||
bool SingleCamWrapper::isOpen() {
|
||||
return valid;
|
||||
}
|
||||
|
||||
double PylonWrapper::maxFrameRate() {
|
||||
double SingleCamWrapper::maxFrameRate() {
|
||||
double max_rate = -1;
|
||||
if (valid) {
|
||||
GenApi::INodeMap& nodemap = camera->GetNodeMap();
|
||||
@@ -51,7 +51,7 @@ double PylonWrapper::maxFrameRate() {
|
||||
return max_rate;
|
||||
}
|
||||
|
||||
bool PylonWrapper::frameRate(uint new_framerate) {
|
||||
bool SingleCamWrapper::frameRate(uint new_framerate) {
|
||||
if (valid) {
|
||||
GenApi::INodeMap& nodemap = camera->GetNodeMap();
|
||||
GenApi::INode* n = nodemap.GetNode( "AcquisitionFrameRateEnable" );
|
||||
@@ -66,7 +66,7 @@ bool PylonWrapper::frameRate(uint new_framerate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double PylonWrapper::frameRate() {
|
||||
double SingleCamWrapper::frameRate() {
|
||||
double rate = -1.;
|
||||
if (valid) {
|
||||
GenApi::INodeMap& nodemap = camera->GetNodeMap();
|
||||
@@ -77,7 +77,7 @@ double PylonWrapper::frameRate() {
|
||||
return rate;
|
||||
}
|
||||
|
||||
double PylonWrapper::exposureTime() {
|
||||
double SingleCamWrapper::exposureTime() {
|
||||
double time = -1.;
|
||||
if (valid) {
|
||||
GenApi::INodeMap& nodemap = camera->GetNodeMap();
|
||||
@@ -88,7 +88,7 @@ double PylonWrapper::exposureTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
bool PylonWrapper::exposureTime(double exposure_time) {
|
||||
bool SingleCamWrapper::exposureTime(double exposure_time) {
|
||||
if (valid) {
|
||||
GenApi::INodeMap& nodemap = camera->GetNodeMap();
|
||||
double d = GenApi::CFloatPtr(nodemap.GetNode("ExposureTime"))->GetValue();
|
||||
@@ -105,7 +105,7 @@ bool PylonWrapper::exposureTime(double exposure_time) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double PylonWrapper::gain() {
|
||||
double SingleCamWrapper::gain() {
|
||||
double gain = -1.;
|
||||
if (valid) {
|
||||
GenApi::INodeMap& nodemap = camera->GetNodeMap();
|
||||
@@ -116,7 +116,7 @@ double PylonWrapper::gain() {
|
||||
return gain;
|
||||
}
|
||||
|
||||
bool PylonWrapper::gain(double gain_db) {
|
||||
bool SingleCamWrapper::gain(double gain_db) {
|
||||
if (valid) {
|
||||
GenApi::INodeMap& nodemap = camera->GetNodeMap();
|
||||
GenApi::CFloatPtr(nodemap.GetNode("Gain"))->SetValue(gain_db);
|
||||
@@ -125,7 +125,7 @@ bool PylonWrapper::gain(double gain_db) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ImageSettings PylonWrapper::getImageSettings() {
|
||||
ImageSettings SingleCamWrapper::getImageSettings() {
|
||||
ImageSettings settings;
|
||||
if (valid) {
|
||||
Pylon::CEnumParameter pixelFormat( camera->GetNodeMap(), "PixelFormat" );
|
||||
@@ -141,7 +141,7 @@ ImageSettings PylonWrapper::getImageSettings() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
bool PylonWrapper::grabFrame(MyImage &img) {
|
||||
bool SingleCamWrapper::grabFrame(MyImage &img) {
|
||||
Pylon::CGrabResultPtr frame;
|
||||
qDebug() << "grabFrame";
|
||||
if (valid) {
|
||||
@@ -162,7 +162,7 @@ bool PylonWrapper::grabFrame(MyImage &img) {
|
||||
return frame.IsValid();
|
||||
}
|
||||
|
||||
void PylonWrapper::resetCamera() {
|
||||
void SingleCamWrapper::resetCamera() {
|
||||
int64_t dfltWidth = 2048;
|
||||
int64_t dfltHeight = 1536;
|
||||
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";
|
||||
try {
|
||||
camera = new Pylon::CInstantCamera();
|
||||
@@ -215,7 +215,7 @@ bool PylonWrapper::openCamera(std::string &message) {
|
||||
return valid;
|
||||
}
|
||||
|
||||
void PylonWrapper::closeCamera() {
|
||||
void SingleCamWrapper::closeCamera() {
|
||||
qDebug() << "Close camera!";
|
||||
if (camera->IsOpen()) {
|
||||
try {
|
||||
@@ -229,6 +229,12 @@ void PylonWrapper::closeCamera() {
|
||||
}
|
||||
}
|
||||
|
||||
Pylon::CInstantCamera *PylonWrapper::getCamera() {
|
||||
Pylon::CInstantCamera *SingleCamWrapper::getCamera() {
|
||||
return camera;
|
||||
}
|
||||
|
||||
QString SingleCamWrapper::userName() {
|
||||
GenApi::INodeMap& nodemap = camera->GetNodeMap();
|
||||
QString username = Pylon::CStringParameter(nodemap, "DeviceUserID").GetValue().c_str();
|
||||
return username;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef PYLONWRAPPER_H
|
||||
#define PYLONWRAPPER_H
|
||||
#ifndef SINGLECAMWRAPPER_H
|
||||
#define SINGLECAMWRAPPER_H
|
||||
|
||||
#include <pylon/PylonIncludes.h>
|
||||
#include <pylon/BaslerUniversalInstantCamera.h>
|
||||
@@ -7,12 +7,12 @@
|
||||
#include "util.h"
|
||||
#include "myimage.h"
|
||||
|
||||
class PylonWrapper
|
||||
class SingleCamWrapper
|
||||
{
|
||||
public:
|
||||
PylonWrapper(const std::string &name);
|
||||
PylonWrapper(const CameraLayout &layout);
|
||||
~PylonWrapper();
|
||||
SingleCamWrapper(const std::string &name);
|
||||
SingleCamWrapper(const CameraLayout &layout);
|
||||
~SingleCamWrapper();
|
||||
|
||||
ImageSettings getImageSettings();
|
||||
bool isOpen();
|
||||
@@ -27,6 +27,7 @@ public:
|
||||
bool exposureTime(double exposure_time);
|
||||
double gain();
|
||||
bool gain(double gain_db);
|
||||
QString userName();
|
||||
Pylon::CInstantCamera *getCamera();
|
||||
void resetCamera();
|
||||
|
||||
@@ -40,4 +41,4 @@ private:
|
||||
|
||||
};
|
||||
|
||||
#endif // PYLONWRAPPER_H
|
||||
#endif // SINGLECAMWRAPPER_H
|
||||
605
stitchimage.h
Normal file
605
stitchimage.h
Normal 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
12
util.h
@@ -37,4 +37,16 @@ struct ImageSettings {
|
||||
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*/
|
||||
23
writer.cpp
23
writer.cpp
@@ -1,9 +1,7 @@
|
||||
#include "writer.h"
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
|
||||
#include <pylon/VideoWriter.h>
|
||||
using namespace std::chrono;
|
||||
|
||||
void Writer::setVideoSpecs(VideoSpecs specs) {
|
||||
videoSpecs = specs;
|
||||
@@ -27,6 +25,7 @@ void Writer::writeMetadata(nix::Section &s){
|
||||
}
|
||||
|
||||
void Writer::run() {
|
||||
qDebug() << "writer running!";
|
||||
size_t count = 0;
|
||||
size_t chunksize = 256;
|
||||
// size_t framecount = 0;
|
||||
@@ -36,9 +35,11 @@ void Writer::run() {
|
||||
// Releases all pylon resources.
|
||||
// PylonTerminate();
|
||||
// Return with error code 1.
|
||||
emit writingDone(this->cam_number);
|
||||
emit writingDone();
|
||||
return;
|
||||
}
|
||||
qDebug() << "checks done!";
|
||||
|
||||
Pylon::CVideoWriter videoWriter;
|
||||
if (specs_valid) {
|
||||
stop_request = false;
|
||||
@@ -48,7 +49,8 @@ void Writer::run() {
|
||||
myFile.write((char*)&videoSpecs.width, 4);
|
||||
myFile.write((char*)&videoSpecs.height, 4);
|
||||
} 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());
|
||||
}
|
||||
|
||||
@@ -91,6 +93,8 @@ void Writer::run() {
|
||||
nix::NDSize offset(1, 0);
|
||||
nix::NDSize current_shape(initial_shape);
|
||||
nix::NDSize chunk_shape(1, chunksize);
|
||||
|
||||
qDebug() << "preparations done, starting loop!";
|
||||
while ((!stop_request || buffer->bufferLoad() > 0) && !stopNow) {
|
||||
if (buffer->bufferLoad() > 0 ) {
|
||||
size_t framecount = 0;
|
||||
@@ -108,7 +112,12 @@ void Writer::run() {
|
||||
}
|
||||
}
|
||||
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();
|
||||
count ++;
|
||||
} else {
|
||||
@@ -132,11 +141,11 @@ void Writer::run() {
|
||||
frametimes.setData(nix::DataType::String, stamps_buffer.data(), chunk_shape, offset);
|
||||
frameindices.setData(nix::DataType::Int64, ids_buffer.data(), chunk_shape, offset);
|
||||
}
|
||||
// videoWriter.Close();
|
||||
videoWriter.Close();
|
||||
myFile.close();
|
||||
nix_file.close();
|
||||
} else {
|
||||
std::cerr << "Got no video specifications, not writing!" << std::endl;
|
||||
}
|
||||
emit writingDone(cam_number);
|
||||
emit writingDone();
|
||||
}
|
||||
|
||||
21
writer.h
21
writer.h
@@ -6,29 +6,17 @@
|
||||
#include <pylon/PylonIncludes.h>
|
||||
#include <nix.hpp>
|
||||
|
||||
#include "pylonwrapper.h"
|
||||
#include "singlecamwrapper.h"
|
||||
#include "imagebuffer.h"
|
||||
#include "projectsettings.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
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Writer(ImageBuffer*buffer, int number, QObject *parent = nullptr) :
|
||||
QThread(parent), buffer(buffer), cam_number(number) {}
|
||||
explicit Writer(ImageBuffer*buffer, QObject *parent = nullptr) :
|
||||
QThread(parent), buffer(buffer) {}
|
||||
|
||||
void setVideoSpecs(VideoSpecs specs);
|
||||
void setProjectMetadata(ProjectMetadata mdata);
|
||||
@@ -37,10 +25,9 @@ public:
|
||||
|
||||
signals:
|
||||
void terminated();
|
||||
void writingDone(int cam);
|
||||
void writingDone();
|
||||
|
||||
private:
|
||||
int cam_number;
|
||||
ImageBuffer *buffer;
|
||||
VideoSpecs videoSpecs;
|
||||
ProjectMetadata metadata;
|
||||
|
||||
Reference in New Issue
Block a user