Compare commits
No commits in common. "ec203ba1ada6f127dd8a9fbbd9ccbccbb4675655" and "41272ce08e45e7fe306d35487f182eb511585b01" have entirely different histories.
ec203ba1ad
...
41272ce08e
@ -42,11 +42,10 @@ 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})
|
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Pylon
|
# Pylon
|
||||||
@ -58,5 +57,5 @@ file (GLOB RECORDER_SOURCES *.cpp)
|
|||||||
file (GLOB RECORDER_INCLUDES *.hpp)
|
file (GLOB RECORDER_INCLUDES *.hpp)
|
||||||
add_executable ( recorder ${RECORDER_SOURCES} ${RECORDER_INCLUDES} ${RECORDER_RES_SOURCES} )
|
add_executable ( recorder ${RECORDER_SOURCES} ${RECORDER_INCLUDES} ${RECORDER_RES_SOURCES} )
|
||||||
target_include_directories ( recorder PUBLIC "${PROJECT_BINARY_DIR}" )
|
target_include_directories ( recorder PUBLIC "${PROJECT_BINARY_DIR}" )
|
||||||
target_link_libraries ( recorder Qt5::PrintSupport Qt5::Core Qt5::Widgets Qt5::Gui ${NIX_LIBRARIES} pylon::pylon ${OpenCV_LIBRARIES})
|
target_link_libraries ( recorder Qt5::PrintSupport Qt5::Core Qt5::Widgets Qt5::Gui ${NIX_LIBRARIES} pylon::pylon)
|
||||||
# ${PYLON_LIBRARIES} ${OpenCV_LIBRARIES})
|
# ${PYLON_LIBRARIES} ${OpenCV_LIBRARIES})
|
@ -1,12 +1,10 @@
|
|||||||
#include "dualcamgrabber.h"
|
#include "dualcamgrabber.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <pylon/PylonIncludes.h>
|
#include <pylon/PylonIncludes.h>
|
||||||
#include <stitchimage.h>
|
|
||||||
|
|
||||||
void DualcamGrabber::run() {
|
void DualcamGrabber::run() {
|
||||||
stop_request = false;
|
stop_request = false;
|
||||||
size_t counter = 0;
|
size_t framecount = 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));
|
||||||
@ -14,29 +12,17 @@ void DualcamGrabber::run() {
|
|||||||
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 = "";
|
|
||||||
|
|
||||||
while (cameras.IsGrabbing() && !stop_request) {
|
while (cameras.IsGrabbing() && !stop_request) {
|
||||||
MyImage *img = new MyImage();
|
MyImage *img = new MyImage();
|
||||||
cameras[0].RetrieveResult( 5000, frame0, Pylon::TimeoutHandling_ThrowException );
|
cameras.RetrieveResult( 5000, framecount % 2 == 0 ? frame0 : frame1, Pylon::TimeoutHandling_ThrowException );
|
||||||
cameras[1].RetrieveResult( 5000, frame1, Pylon::TimeoutHandling_ThrowException );
|
img->setFrame(framecount % 2 == 0 ? frame0 : frame1);
|
||||||
|
if (framecount % 2 == 0) {
|
||||||
leftImage.AttachGrabResultBuffer( frame0 );
|
buffer0->push(img);
|
||||||
rightImage.AttachGrabResultBuffer( frame1 );
|
} else {
|
||||||
|
buffer1->push(img);
|
||||||
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';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
counter += 1;
|
framecount += 1;
|
||||||
}
|
}
|
||||||
cameras.StopGrabbing();
|
cameras.StopGrabbing();
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,8 @@ class DualcamGrabber : public QThread
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
DualcamGrabber(DualcamWrapper *wrapper, ImageBuffer *buffer, int framerate, QObject *parent = nullptr) :
|
DualcamGrabber(DualcamWrapper *wrapper, ImageBuffer *buffer0, ImageBuffer * buffer1, int framerate, QObject *parent = nullptr) :
|
||||||
QThread(parent), wrapper(wrapper), buffer(buffer), framerate(framerate) {}
|
QThread(parent), wrapper(wrapper), buffer0(buffer0), buffer1(buffer1), 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 *buffer;
|
ImageBuffer *buffer0, *buffer1;
|
||||||
int framerate;
|
int framerate;
|
||||||
double exposure, gain;
|
double exposure, gain;
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ void DualcamWrapper::terminate() {
|
|||||||
|
|
||||||
|
|
||||||
bool DualcamWrapper::isOpen() {
|
bool DualcamWrapper::isOpen() {
|
||||||
return cameras.IsOpen();
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -213,6 +213,7 @@ 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();
|
||||||
cameras.Initialize(2);
|
cameras.Initialize(2);
|
||||||
try {
|
try {
|
||||||
|
@ -30,6 +30,7 @@ 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);
|
||||||
|
@ -72,6 +72,7 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +111,6 @@ MyImage* ImageBuffer::readLast(size_t &framecount) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImageBuffer::~ImageBuffer(){
|
ImageBuffer::~ImageBuffer(){
|
||||||
qDebug() << "Image buffer destructor";
|
std::cerr << "Image buffer destructor" << std::endl;
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
10
myimage.cpp
10
myimage.cpp
@ -21,16 +21,6 @@ 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());
|
|
||||||
}
|
|
||||||
return valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
int MyImage::width() {
|
int MyImage::width() {
|
||||||
return static_cast<int>(img_width);
|
return static_cast<int>(img_width);
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,13 @@ 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 = 4096;
|
static const int max_width = 2048;
|
||||||
static const int max_height = 1536;
|
static const int max_height = 1536;
|
||||||
char buffer[max_width * max_height];
|
char buffer[max_width * max_height];
|
||||||
};
|
};
|
||||||
|
@ -34,7 +34,8 @@
|
|||||||
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),
|
||||||
writer(nullptr), buffer(nullptr),
|
writer0(nullptr), writer1(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)
|
||||||
{
|
{
|
||||||
@ -118,9 +119,9 @@ PylonRecorder::~PylonRecorder(){
|
|||||||
singlecamgrabber->requestStop();
|
singlecamgrabber->requestStop();
|
||||||
singlecamgrabber->wait(1000);
|
singlecamgrabber->wait(1000);
|
||||||
}
|
}
|
||||||
if (writer != nullptr && writer->isRunning()) {
|
if (writer0 != nullptr && writer0->isRunning()) {
|
||||||
writer->forceStop();
|
writer0->forceStop();
|
||||||
writer->wait(1000);
|
writer0->wait(1000);
|
||||||
}
|
}
|
||||||
storeSettings();
|
storeSettings();
|
||||||
if (singlecam != nullptr) {
|
if (singlecam != nullptr) {
|
||||||
@ -134,12 +135,16 @@ PylonRecorder::~PylonRecorder(){
|
|||||||
dualcam = nullptr;
|
dualcam = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer != nullptr) {
|
if (buffer0 != nullptr) {
|
||||||
qDebug() << "Deleting buffer";
|
qDebug() << "Deleting buffer";
|
||||||
delete buffer;
|
delete buffer0;
|
||||||
buffer = nullptr;
|
buffer0 = 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;
|
||||||
@ -150,10 +155,15 @@ PylonRecorder::~PylonRecorder(){
|
|||||||
delete dualcamgrabber;
|
delete dualcamgrabber;
|
||||||
dualcamgrabber = nullptr;
|
dualcamgrabber = nullptr;
|
||||||
}
|
}
|
||||||
if (writer != nullptr) {
|
if (writer0 != nullptr) {
|
||||||
qDebug() << "Deleting writer";
|
qDebug() << "Deleting writer";
|
||||||
delete writer;
|
delete writer0;
|
||||||
writer = nullptr;
|
writer0 = nullptr;
|
||||||
|
}
|
||||||
|
if (writer1 != nullptr) {
|
||||||
|
qDebug() << "Deleting writer";
|
||||||
|
delete writer1;
|
||||||
|
writer1 = nullptr;
|
||||||
}
|
}
|
||||||
qDebug() << "Deleting setting";
|
qDebug() << "Deleting setting";
|
||||||
delete settings;
|
delete settings;
|
||||||
@ -196,8 +206,11 @@ 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);
|
||||||
@ -606,6 +619,7 @@ 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();
|
||||||
@ -643,8 +657,10 @@ void PylonRecorder::connectCamera() {
|
|||||||
updateActions();
|
updateActions();
|
||||||
}
|
}
|
||||||
if (layout.mode == CameraMode::dual && layout.devices.size() == 2) {
|
if (layout.mode == CameraMode::dual && layout.devices.size() == 2) {
|
||||||
|
std::cerr << "Dual MODE" << std::endl;
|
||||||
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) {
|
||||||
@ -684,22 +700,20 @@ void PylonRecorder::disconnectCamera() {
|
|||||||
|
|
||||||
VideoSpecs PylonRecorder::getVideoSpecs(const ImageSettings &settings) {
|
VideoSpecs PylonRecorder::getVideoSpecs(const ImageSettings &settings) {
|
||||||
VideoSpecs s = VideoSpecs();
|
VideoSpecs s = VideoSpecs();
|
||||||
if (!this->layout.devices.size() > 0) {
|
if (this->layout.mode == CameraMode::single && this->layout.devices.size() > 0) {
|
||||||
return s;
|
|
||||||
}
|
|
||||||
s.fps = framerateSpinner->value();
|
s.fps = framerateSpinner->value();
|
||||||
s.exposureTime = static_cast<double>(exposureSpinner->value());
|
s.exposureTime = static_cast<double>(exposureSpinner->value());
|
||||||
s.detectorGain = static_cast<double>(gainSpinner->value());
|
s.detectorGain = static_cast<double>(gainSpinner->value());
|
||||||
|
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.pixelType = settings.pixelType;
|
||||||
s.orientation = settings.orientation;
|
s.orientation = settings.orientation;
|
||||||
s.quality = 95;
|
s.quality = 95;
|
||||||
|
} else {
|
||||||
if (layout.mode == CameraMode::single) {
|
qWarning() << "Dual camera mode not supported yet!";
|
||||||
s.width = static_cast<uint32_t>(this->layout.rois[0].width);
|
|
||||||
s.height = static_cast<uint32_t>(this->layout.rois[0].height);
|
|
||||||
} 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;
|
return s;
|
||||||
}
|
}
|
||||||
@ -707,7 +721,7 @@ VideoSpecs PylonRecorder::getVideoSpecs(const ImageSettings &settings) {
|
|||||||
|
|
||||||
void PylonRecorder::startSinglecamRecording() {
|
void PylonRecorder::startSinglecamRecording() {
|
||||||
qDebug() << "start single-camera 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();
|
||||||
|
|
||||||
@ -719,15 +733,15 @@ void PylonRecorder::startSinglecamRecording() {
|
|||||||
specs.format = VideoFormat::mp4;
|
specs.format = VideoFormat::mp4;
|
||||||
qDebug() << "got video specifications";
|
qDebug() << "got video specifications";
|
||||||
|
|
||||||
if (buffer != nullptr) {
|
if (buffer0 != nullptr) {
|
||||||
buffer->clear();
|
buffer0->clear();
|
||||||
delete buffer;
|
delete buffer0;
|
||||||
buffer = nullptr;
|
buffer0 = nullptr;
|
||||||
}
|
}
|
||||||
qDebug() << "setting image buffer to size " << buffersizeSpinner->value();
|
qDebug() << "setting image buffer to size " << buffersizeSpinner->value();
|
||||||
buffer = new ImageBuffer(defaultBufferSize);
|
buffer0 = new ImageBuffer(defaultBufferSize);
|
||||||
if (buffersizeSpinner->value() != static_cast<int>(buffer->capacity())) {
|
if (buffersizeSpinner->value() != static_cast<int>(buffer0->capacity())) {
|
||||||
buffer->resize(static_cast<size_t>(buffersizeSpinner->value()));
|
buffer0->resize(static_cast<size_t>(buffersizeSpinner->value()));
|
||||||
loadBar->setRange(0, buffersizeSpinner->value());
|
loadBar->setRange(0, buffersizeSpinner->value());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -736,7 +750,7 @@ void PylonRecorder::startSinglecamRecording() {
|
|||||||
delete singlecamgrabber;
|
delete singlecamgrabber;
|
||||||
singlecamgrabber = nullptr;
|
singlecamgrabber = nullptr;
|
||||||
}
|
}
|
||||||
singlecamgrabber = new Grabber(singlecam, buffer, defaultFrameRate);
|
singlecamgrabber = new Grabber(singlecam, buffer0, defaultFrameRate);
|
||||||
|
|
||||||
if (framerateSpinner->value() != singlecamgrabber->currentFramerate())
|
if (framerateSpinner->value() != singlecamgrabber->currentFramerate())
|
||||||
singlecamgrabber->setFrameRate(framerateSpinner->value());
|
singlecamgrabber->setFrameRate(framerateSpinner->value());
|
||||||
@ -746,21 +760,22 @@ void PylonRecorder::startSinglecamRecording() {
|
|||||||
singlecamgrabber->setGain(static_cast<double>(gainSpinner->value()));
|
singlecamgrabber->setGain(static_cast<double>(gainSpinner->value()));
|
||||||
|
|
||||||
qDebug() << "setup writer";
|
qDebug() << "setup writer";
|
||||||
if (writer != nullptr) {
|
if (writer0 != nullptr) {
|
||||||
delete writer;
|
delete writer0;
|
||||||
writer = nullptr;
|
writer0 = nullptr;
|
||||||
}
|
}
|
||||||
writer = new Writer(buffer, 0);
|
writer0 = new Writer(buffer0, 0);
|
||||||
connect(writer, SLOT(writingDone()), this, SLOT(writerDone()));
|
connect(writer0, SLOT(writingDone( int)), this, SLOT(writerDone( int )));
|
||||||
writer->setVideoSpecs(specs);
|
writer0->setVideoSpecs(specs);
|
||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
this->mdata.read(s);
|
this->mdata.read(s);
|
||||||
writer->setProjectMetadata(mdata);
|
writer0->setProjectMetadata(mdata);
|
||||||
|
|
||||||
buffer->clear();
|
buffer0->clear();
|
||||||
if (!dryRunCheckBox->isChecked()) {
|
if (!dryRunCheckBox->isChecked()) {
|
||||||
writer->start();
|
writer0->start();
|
||||||
|
iswriting[0] = true;
|
||||||
writing = true;
|
writing = true;
|
||||||
}
|
}
|
||||||
dryRun = dryRunCheckBox->isChecked();
|
dryRun = dryRunCheckBox->isChecked();
|
||||||
@ -772,35 +787,51 @@ void PylonRecorder::startSinglecamRecording() {
|
|||||||
|
|
||||||
void PylonRecorder::startDualcamRecording() {
|
void PylonRecorder::startDualcamRecording() {
|
||||||
qDebug() << "start dual-camera recording!";
|
qDebug() << "start dual-camera recording!";
|
||||||
std::string filename = createFilename("", ".mp4");
|
std::string filenamea = createFilename("a", ".mp4");
|
||||||
fileLabel->setText(QString::fromStdString(filename));
|
std::string filenameb = createFilename("b", ".mp4");
|
||||||
qDebug() << "storing to file " << filename.c_str();
|
fileLabel->setText(QString::fromStdString(filenamea + " & " + filenameb));
|
||||||
|
qDebug() << "storing to files " << filenamea.c_str() << ", " << filenameb.c_str();
|
||||||
|
|
||||||
ImageSettings settings = dualcam->getImageSettings(0); //FIXME!
|
ImageSettings settings = dualcam->getImageSettings(0);
|
||||||
qDebug() << "got image settings";
|
qDebug() << "got image settings";
|
||||||
VideoSpecs specs = getVideoSpecs(settings);
|
|
||||||
specs.filename = filename;
|
VideoSpecs specsa = getVideoSpecs(settings);
|
||||||
specs.format = VideoFormat::mp4;
|
specsa.filename = filenamea;
|
||||||
|
specsa.format = VideoFormat::mp4;
|
||||||
|
|
||||||
|
VideoSpecs specsb = getVideoSpecs(settings);
|
||||||
|
specsb.filename = filenameb;
|
||||||
|
specsb.format = VideoFormat::mp4;
|
||||||
qDebug() << "got video specifications";
|
qDebug() << "got video specifications";
|
||||||
if (buffer != nullptr) {
|
|
||||||
buffer->clear();
|
if (buffer0 != nullptr) {
|
||||||
delete buffer;
|
buffer0->clear();
|
||||||
buffer = nullptr;
|
delete buffer0;
|
||||||
|
buffer0 = nullptr;
|
||||||
|
}
|
||||||
|
if (buffer1 != nullptr) {
|
||||||
|
buffer1->clear();
|
||||||
|
delete buffer1;
|
||||||
|
buffer1 = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "setting image buffer to size " << buffersizeSpinner->value();
|
qDebug() << "setting image buffer to size " << buffersizeSpinner->value();
|
||||||
buffer = new ImageBuffer(defaultBufferSize);
|
buffer0 = new ImageBuffer(defaultBufferSize);
|
||||||
if (buffersizeSpinner->value() != static_cast<int>(buffer->capacity())) {
|
if (buffersizeSpinner->value() != static_cast<int>(buffer0->capacity())) {
|
||||||
buffer->resize(static_cast<size_t>(buffersizeSpinner->value()));
|
buffer0->resize(static_cast<size_t>(buffersizeSpinner->value()));
|
||||||
loadBar->setRange(0, 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";
|
qDebug() << "setting up grabber";
|
||||||
if (dualcamgrabber != nullptr) {
|
if (dualcamgrabber != nullptr) {
|
||||||
delete dualcamgrabber;
|
delete dualcamgrabber;
|
||||||
dualcamgrabber = nullptr;
|
dualcamgrabber = nullptr;
|
||||||
}
|
}
|
||||||
dualcamgrabber = new DualcamGrabber(dualcam, buffer, defaultFrameRate);
|
dualcamgrabber = new DualcamGrabber(dualcam, buffer0, buffer1, defaultFrameRate);
|
||||||
if (framerateSpinner->value() != dualcamgrabber->currentFramerate())
|
if (framerateSpinner->value() != dualcamgrabber->currentFramerate())
|
||||||
dualcamgrabber->setFrameRate(framerateSpinner->value());
|
dualcamgrabber->setFrameRate(framerateSpinner->value());
|
||||||
if (exposureSpinner->value() != int(dualcamgrabber->currentExposureTime()))
|
if (exposureSpinner->value() != int(dualcamgrabber->currentExposureTime()))
|
||||||
@ -809,26 +840,42 @@ void PylonRecorder::startDualcamRecording() {
|
|||||||
dualcamgrabber->setGain(static_cast<double>(gainSpinner->value()));
|
dualcamgrabber->setGain(static_cast<double>(gainSpinner->value()));
|
||||||
|
|
||||||
qDebug() << "setting up writers";
|
qDebug() << "setting up writers";
|
||||||
if (writer != nullptr) {
|
if (writer0 != nullptr) {
|
||||||
delete writer;
|
delete writer0;
|
||||||
writer = nullptr;
|
writer0 = 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;
|
||||||
}
|
}
|
||||||
writer = new Writer(buffer, 0);
|
writer1 = new Writer(buffer1, 1);
|
||||||
connect(writer, SIGNAL(writingDone()), this, SLOT(writerDone()));
|
connect(writer1, SIGNAL(writingDone(int)), this, SLOT(writerDone( int )));
|
||||||
writer->setVideoSpecs(specs);
|
writer1->setVideoSpecs(specsb);
|
||||||
|
|
||||||
qDebug() << "push metadata to writer";
|
qDebug() << "push metadata to writer";
|
||||||
QSettings s;
|
QSettings s;
|
||||||
this->mdata.read(s);
|
this->mdata.read(s);
|
||||||
writer->setProjectMetadata(mdata);
|
writer0->setProjectMetadata(mdata);
|
||||||
|
|
||||||
dryRun = dryRunCheckBox->isChecked();
|
buffer0->clear();
|
||||||
buffer->clear();
|
if (!dryRunCheckBox->isChecked()) {
|
||||||
if (!dryRun) {
|
writer0->start();
|
||||||
writer->start();
|
|
||||||
writing = true;
|
writing = true;
|
||||||
|
iswriting[0] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buffer1->clear();
|
||||||
|
if (!dryRunCheckBox->isChecked()) {
|
||||||
|
writer1->start();
|
||||||
|
writing = true;
|
||||||
|
iswriting[1] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dryRun = dryRunCheckBox->isChecked();
|
||||||
dualcamgrabber->start();
|
dualcamgrabber->start();
|
||||||
grabbing = true;
|
grabbing = true;
|
||||||
stopRequest = false;
|
stopRequest = false;
|
||||||
@ -859,27 +906,37 @@ 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 (writer != nullptr)
|
if (writer0 != nullptr)
|
||||||
writer->requestStop();
|
writer0->requestStop();
|
||||||
|
if (writer1 != nullptr)
|
||||||
|
writer1->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(buffer != nullptr) {
|
if(buffer0 != nullptr) {
|
||||||
buffer->clear();
|
buffer0->clear();
|
||||||
if (dryRun)
|
// writerDone( 0 ); // Needed? or even dangerous?
|
||||||
writerDone();
|
}
|
||||||
|
qDebug() << "StopRecording: clear buffer!";
|
||||||
|
if(buffer1 != nullptr) {
|
||||||
|
buffer1->clear();
|
||||||
|
// writerDone( 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qDebug() << "StopRecording done!";
|
qDebug() << "StopRecording done!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PylonRecorder::writerDone() {
|
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;
|
||||||
|
}
|
||||||
pressureTimer->stop();
|
pressureTimer->stop();
|
||||||
pressureBar->reset();
|
pressureBar->reset();
|
||||||
loadBar->reset();
|
loadBar->reset();
|
||||||
@ -891,9 +948,13 @@ void PylonRecorder::writerDone() {
|
|||||||
} else {
|
} else {
|
||||||
dualcamgrabber->wait(10000);
|
dualcamgrabber->wait(10000);
|
||||||
}
|
}
|
||||||
if (writer != nullptr)
|
if (writer0 != nullptr)
|
||||||
writer->wait(10000);
|
writer0->wait(10000);
|
||||||
|
if (writer1 != nullptr)
|
||||||
|
writer1->wait(10000);
|
||||||
writing = false;
|
writing = false;
|
||||||
|
iswriting[0] = false;
|
||||||
|
iswriting[1] = false;
|
||||||
updateActions();
|
updateActions();
|
||||||
qInfo() << "writer is Done!";
|
qInfo() << "writer is Done!";
|
||||||
}
|
}
|
||||||
@ -909,8 +970,9 @@ void PylonRecorder::displayActivity() {
|
|||||||
void PylonRecorder::displaySingleFrame() {
|
void PylonRecorder::displaySingleFrame() {
|
||||||
MyImage *img;
|
MyImage *img;
|
||||||
size_t fc = 0;
|
size_t fc = 0;
|
||||||
img = buffer->readLast(fc);
|
img = buffer0->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 {
|
||||||
@ -946,13 +1008,13 @@ std::string PylonRecorder::createFilename(const std::string &suffix, const std::
|
|||||||
|
|
||||||
|
|
||||||
void PylonRecorder::displayBufferPressure() {
|
void PylonRecorder::displayBufferPressure() {
|
||||||
int value = static_cast<int>(round(buffer->bufferPressure()));
|
int value = static_cast<int>(round(buffer0->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>(buffer->bufferLoad());
|
int load = static_cast<int>(buffer0->bufferLoad());
|
||||||
loadBar->setValue(load);
|
loadBar->setValue(load);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
#include "grabber.h"
|
#include "grabber.h"
|
||||||
#include "dualcamgrabber.h"
|
#include "dualcamgrabber.h"
|
||||||
#include "writer.h"
|
#include "writer.h"
|
||||||
#include "opencvwriter.h"
|
|
||||||
#include "projectsettings.h"
|
#include "projectsettings.h"
|
||||||
#include "camconfig.h"
|
#include "camconfig.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -67,7 +66,7 @@ private slots:
|
|||||||
void displaySingleFrame();
|
void displaySingleFrame();
|
||||||
void displayBufferPressure();
|
void displayBufferPressure();
|
||||||
void displayActivity();
|
void displayActivity();
|
||||||
void writerDone();
|
void writerDone(int cam);
|
||||||
void selectStorageLocation();
|
void selectStorageLocation();
|
||||||
void cameraConfigurationAccepted();
|
void cameraConfigurationAccepted();
|
||||||
void cameraConfigurationAborted();
|
void cameraConfigurationAborted();
|
||||||
@ -106,12 +105,13 @@ private:
|
|||||||
double scaleFactor = 1;
|
double scaleFactor = 1;
|
||||||
PylonWrapper *singlecam;
|
PylonWrapper *singlecam;
|
||||||
DualcamWrapper *dualcam;
|
DualcamWrapper *dualcam;
|
||||||
ImageBuffer *buffer;
|
ImageBuffer *buffer0, *buffer1;
|
||||||
Grabber *singlecamgrabber;
|
Grabber *singlecamgrabber;
|
||||||
DualcamGrabber *dualcamgrabber;
|
DualcamGrabber *dualcamgrabber;
|
||||||
Writer *writer;
|
Writer *writer0, *writer1;
|
||||||
CameraLayout layout;
|
CameraLayout layout;
|
||||||
bool grabbing, stopRequest, writing, labelSwitch, dryRun, cameraOpened, camsconfigured;
|
bool grabbing, stopRequest, writing, labelSwitch, dryRun, cameraOpened, camsconfigured;
|
||||||
|
bool iswriting[2] = {0, 0};
|
||||||
QPalette progressPalette;
|
QPalette progressPalette;
|
||||||
QString activeLabelStyleHigh = "QLabel { font-size: 10pt;font-family: Arial; color : red; }";
|
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); }";
|
QString activeLabelStyleLow = "QLabel { font-size: 10pt;font-family: Arial; color : cmyk(0, 255, 255, 0, 50); }";
|
||||||
|
605
stitchimage.h
605
stitchimage.h
@ -1,605 +0,0 @@
|
|||||||
// 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,16 +37,4 @@ 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*/
|
@ -27,7 +27,6 @@ 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;
|
||||||
@ -40,8 +39,6 @@ void Writer::run() {
|
|||||||
emit writingDone(this->cam_number);
|
emit writingDone(this->cam_number);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
qDebug() << "checks done!";
|
|
||||||
|
|
||||||
Pylon::CVideoWriter videoWriter;
|
Pylon::CVideoWriter videoWriter;
|
||||||
if (specs_valid) {
|
if (specs_valid) {
|
||||||
stop_request = false;
|
stop_request = false;
|
||||||
@ -51,8 +48,7 @@ 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 {
|
||||||
qDebug() << "setting parameters for video";
|
videoWriter.SetParameter(videoSpecs.width, videoSpecs.height, videoSpecs.pixelType, videoSpecs.fps, videoSpecs.quality);
|
||||||
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,8 +91,6 @@ 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;
|
||||||
|
12
writer.h
12
writer.h
@ -11,6 +11,18 @@
|
|||||||
#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
|
||||||
|
Loading…
Reference in New Issue
Block a user