Compare commits
51 Commits
7b1d79ad70
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| cd9bbcfa62 | |||
| 0fa532d59a | |||
| 4f2d45df6b | |||
| 12c2f6292f | |||
| 6ec776cd4e | |||
| 222c3a9ce1 | |||
| cb1c7772e8 | |||
| 63dbc21df8 | |||
| 6916899620 | |||
| b221a03d43 | |||
| f4231e281b | |||
| 6ef19c2375 | |||
| 767f8b7e42 | |||
| 2bed70b971 | |||
| dadce69944 | |||
| d78b9d8b02 | |||
| 23b0a9afcd | |||
| fe20326953 | |||
| f803854da3 | |||
| 155ac6b471 | |||
| 18f088c4fd | |||
| a3418bc25e | |||
| ec203ba1ad | |||
| 5263d04cac | |||
| 03e5cd70c7 | |||
| e394c346ed | |||
| aa265565f2 | |||
| e9b195674c | |||
| 555098cdba | |||
| 41272ce08e | |||
| 39fec831ff | |||
| f8304501ba | |||
| a013ab1153 | |||
| e259d668ad | |||
| 5a999fac54 | |||
| 8c26fb4829 | |||
| f22d3ef302 | |||
| 384aab9de4 | |||
| 4e617e9505 | |||
| b99ff19620 | |||
| cb9867eec0 | |||
| 97ca5aba51 | |||
| 37db983a2f | |||
| 7ad190513a | |||
| 47ea6fb27e | |||
| 29abd710e9 | |||
| 63231e5a1c | |||
| 96effc81c5 | |||
| adf48f3002 | |||
| 6a82c8d640 | |||
| 203063d83d |
@@ -5,7 +5,7 @@ message ("-------------------------------------------")
|
|||||||
cmake_minimum_required ( VERSION 3.7 )
|
cmake_minimum_required ( VERSION 3.7 )
|
||||||
set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake" )
|
set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake" )
|
||||||
|
|
||||||
project( recorder VERSION 0.1.0 LANGUAGES CXX )
|
project( recorder VERSION 0.2.0 LANGUAGES CXX )
|
||||||
|
|
||||||
configure_file( recorder_config.h.in recorder_config.h )
|
configure_file( recorder_config.h.in recorder_config.h )
|
||||||
|
|
||||||
@@ -41,21 +41,22 @@ message ("=> finding nix ...")
|
|||||||
find_package (NIX REQUIRED)
|
find_package (NIX REQUIRED)
|
||||||
include_directories (AFTER ${NIX_INCLUDE_DIR})
|
include_directories (AFTER ${NIX_INCLUDE_DIR})
|
||||||
|
|
||||||
#######################################
|
# #######################################
|
||||||
# OPENCV
|
# OPENCV
|
||||||
find_package(OpenCV REQUIRED opencv_highgui opencv_core)
|
# message ("=> finding opencv ...")
|
||||||
include_directories(AFTER ${OpenCV_INCLUDE_DIRS} )
|
# find_package(OpenCV REQUIRED opencv_highgui opencv_core)
|
||||||
set(LINK_LIBS ${LINK_LIBS} ${OpenCV_LIBRARIES})
|
# include_directories(AFTER ${OpenCV_INCLUDE_DIRS} )
|
||||||
|
# set(LINK_LIBS ${LINK_LIBS} ${OpenCV_LIBRARIES})
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Pylon
|
# Pylon
|
||||||
#include_directories ( AFTER "/opt/pylon/include" )
|
message ("=> finding pylon ...")
|
||||||
#file (GLOB PYLON_LIBRARIES "/opt/pylon/lib/*.so")
|
find_package(pylon 7.1.0 REQUIRED)
|
||||||
include_directories ( AFTER "/opt/pylon5/include" )
|
|
||||||
file (GLOB PYLON_LIBRARIES "/opt/pylon5/lib64/*.so")
|
|
||||||
file (GLOB RECORDER_SOURCES *.cpp)
|
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_LIBRARIES} ${OpenCV_LIBRARIES})
|
target_link_libraries ( recorder Qt5::PrintSupport Qt5::Core Qt5::Widgets Qt5::Gui ${NIX_LIBRARIES} pylon::pylon)
|
||||||
|
# ${PYLON_LIBRARIES} ${OpenCV_LIBRARIES})
|
||||||
@@ -3,8 +3,9 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
CamConfigurator::CamConfigurator(Pylon::DeviceInfoList_t &deviceList, QWidget *parent) :
|
CamConfigurator::CamConfigurator(Pylon::DeviceInfoList &deviceList, QWidget *parent) :
|
||||||
deviceList(deviceList), QDialog(parent), preview(nullptr) {
|
deviceList(deviceList), QDialog(parent), preview(nullptr) {
|
||||||
|
qDebug() << "CamConfig constructor";
|
||||||
mode_combo = new QComboBox(this);
|
mode_combo = new QComboBox(this);
|
||||||
mode_combo->addItem("camera mode");
|
mode_combo->addItem("camera mode");
|
||||||
mode_combo->addItem("single camera");
|
mode_combo->addItem("single camera");
|
||||||
@@ -45,6 +46,7 @@ CamConfigurator::CamConfigurator(Pylon::DeviceInfoList_t &deviceList, QWidget *p
|
|||||||
connect(buttonbox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
connect(buttonbox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||||
connect(buttonbox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
connect(buttonbox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
vbox->addWidget(buttonbox);
|
vbox->addWidget(buttonbox);
|
||||||
|
qDebug() << "CamConfig constructor done!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -71,6 +73,7 @@ CameraSetup* CamConfigurator::stereoCameraView() {
|
|||||||
|
|
||||||
|
|
||||||
void CamConfigurator::modeChanged(int idx) {
|
void CamConfigurator::modeChanged(int idx) {
|
||||||
|
qDebug() << "Mode changed!";
|
||||||
stack->setCurrentIndex(0);
|
stack->setCurrentIndex(0);
|
||||||
if (stack->count() > 1 && preview != nullptr) {
|
if (stack->count() > 1 && preview != nullptr) {
|
||||||
qDebug() << "removing previous widget from stack";
|
qDebug() << "removing previous widget from stack";
|
||||||
@@ -86,6 +89,7 @@ void CamConfigurator::modeChanged(int idx) {
|
|||||||
stack->setCurrentIndex(1);
|
stack->setCurrentIndex(1);
|
||||||
QString device = device_combo->currentText();
|
QString device = device_combo->currentText();
|
||||||
preview->setPrimaryCamera(device);
|
preview->setPrimaryCamera(device);
|
||||||
|
mode_combo->setEnabled(false);
|
||||||
} else if (idx == 2) {
|
} else if (idx == 2) {
|
||||||
qDebug() << "Mode changed to dual camera mode";
|
qDebug() << "Mode changed to dual camera mode";
|
||||||
preview = stereoCameraView();
|
preview = stereoCameraView();
|
||||||
@@ -100,6 +104,7 @@ void CamConfigurator::modeChanged(int idx) {
|
|||||||
}
|
}
|
||||||
QString device2 = device_combo->itemText(1 - i);
|
QString device2 = device_combo->itemText(1 - i);
|
||||||
preview->setSecondaryCamera(device2);
|
preview->setSecondaryCamera(device2);
|
||||||
|
mode_combo->setEnabled(false);
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Mode changed mode selection";
|
qDebug() << "Mode changed mode selection";
|
||||||
stack->setCurrentIndex(0);
|
stack->setCurrentIndex(0);
|
||||||
@@ -113,10 +118,11 @@ void CamConfigurator::modeChanged(int idx) {
|
|||||||
|
|
||||||
|
|
||||||
void CamConfigurator::primaryDeviceChanged(int idx) {
|
void CamConfigurator::primaryDeviceChanged(int idx) {
|
||||||
|
qDebug() << "Primary device changed!";
|
||||||
if (mode_combo->currentText() == "single camera") { // single camera setting
|
if (mode_combo->currentText() == "single camera") { // single camera setting
|
||||||
QString devicename = device_combo->currentText();
|
QString devicename = device_combo->currentText();
|
||||||
preview->setPrimaryCamera(devicename);
|
preview->setPrimaryCamera(devicename);
|
||||||
} else {
|
} else if (mode_combo->currentText() == "stereo camera") { // stereo camera setting
|
||||||
preview->switchArrangement();
|
preview->switchArrangement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,29 +9,33 @@ CameraPreview::CameraPreview(QWidget *parent):cameraname(""), camera(nullptr), Q
|
|||||||
this->setLayout(new QVBoxLayout(this));
|
this->setLayout(new QVBoxLayout(this));
|
||||||
this->layout()->addWidget(label);
|
this->layout()->addWidget(label);
|
||||||
imgLabel = new QLabel(this);
|
imgLabel = new QLabel(this);
|
||||||
imgLabel->setMinimumSize(QSize(1024, 768));
|
imgLabel->setMinimumSize(QSize(800, 600));
|
||||||
this->layout()->addWidget(imgLabel);
|
this->layout()->addWidget(imgLabel);
|
||||||
QWidget *controls = new QWidget(this);
|
QWidget *controls = new QWidget(this);
|
||||||
|
|
||||||
width = new QSpinBox(controls);
|
width = new QSpinBox(controls);
|
||||||
width->setMinimum(1);
|
width->setMinimum(32);
|
||||||
width->setMaximum(2048);
|
width->setMaximum(2048);
|
||||||
|
width->setSingleStep(32);
|
||||||
width->setValue(width->maximum());
|
width->setValue(width->maximum());
|
||||||
connect(width, SIGNAL(textChanged(QString)), SLOT(updateWidth(QString)));
|
connect(width, SIGNAL(textChanged(QString)), SLOT(updateWidth(QString)));
|
||||||
|
|
||||||
height = new QSpinBox(controls);
|
height = new QSpinBox(controls);
|
||||||
height->setMinimum(1);
|
height->setSingleStep(32);
|
||||||
|
height->setMinimum(32);
|
||||||
height->setMaximum(1536);
|
height->setMaximum(1536);
|
||||||
height->setValue(height->maximum());
|
height->setValue(height->maximum());
|
||||||
connect(height, SIGNAL(textChanged(QString)), SLOT(updateHeight(QString)));
|
connect(height, SIGNAL(textChanged(QString)), SLOT(updateHeight(QString)));
|
||||||
|
|
||||||
xoffs = new QSpinBox(controls);
|
xoffs = new QSpinBox(controls);
|
||||||
|
xoffs->setSingleStep(8);
|
||||||
xoffs->setMinimum(0);
|
xoffs->setMinimum(0);
|
||||||
xoffs->setMaximum(2047);
|
xoffs->setMaximum(2047);
|
||||||
xoffs->setValue(0);
|
xoffs->setValue(0);
|
||||||
connect(xoffs, SIGNAL(textChanged(QString)), SLOT(updateXoffs(QString)));
|
connect(xoffs, SIGNAL(textChanged(QString)), SLOT(updateXoffs(QString)));
|
||||||
|
|
||||||
yoffs = new QSpinBox(controls);
|
yoffs = new QSpinBox(controls);
|
||||||
|
yoffs->setSingleStep(8);
|
||||||
yoffs->setMinimum(0);
|
yoffs->setMinimum(0);
|
||||||
yoffs->setMaximum(1535);
|
yoffs->setMaximum(1535);
|
||||||
yoffs->setValue(0);
|
yoffs->setValue(0);
|
||||||
@@ -53,14 +57,13 @@ CameraPreview::CameraPreview(QWidget *parent):cameraname(""), camera(nullptr), Q
|
|||||||
this->layout()->addWidget(controls);
|
this->layout()->addWidget(controls);
|
||||||
//setPrimaryCamera(devicename);
|
//setPrimaryCamera(devicename);
|
||||||
qDebug() << "Camera preview constructor";
|
qDebug() << "Camera preview constructor";
|
||||||
takeStill();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CameraPreview::setCamera(QString &device){
|
void CameraPreview::setCamera(QString &device){
|
||||||
qDebug() << "update camera! ";// << device.toStdString();
|
qDebug() << "update camera! " << device;
|
||||||
cameraname = device;
|
cameraname = device;
|
||||||
label->setText(device);
|
if (camera != nullptr) {
|
||||||
if (camera != NULL) {
|
|
||||||
qDebug() << "camera is not nullptr! ";
|
qDebug() << "camera is not nullptr! ";
|
||||||
delete camera;
|
delete camera;
|
||||||
camera = nullptr;
|
camera = nullptr;
|
||||||
@@ -75,7 +78,28 @@ void CameraPreview::setCamera(QString &device){
|
|||||||
QString msg = "<p><b>Could not open camera device!</b><p><p>" + QString::fromStdString(message) + "</p>";
|
QString msg = "<p><b>Could not open camera device!</b><p><p>" + QString::fromStdString(message) + "</p>";
|
||||||
msgBox.setText(msg);
|
msgBox.setText(msg);
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
int64_t max_height = camera->sensorHeight();
|
||||||
|
int64_t max_width = camera->sensorWidth();
|
||||||
|
std::cerr << "set spin box values " << max_width << " " << max_height << std::endl;
|
||||||
|
width->blockSignals(true);
|
||||||
|
height->blockSignals(true);
|
||||||
|
xoffs->blockSignals(true);
|
||||||
|
yoffs->blockSignals(true);
|
||||||
|
width->setMaximum(max_width);
|
||||||
|
width->setValue(max_width);
|
||||||
|
height->setMaximum(max_height);
|
||||||
|
height->setValue(max_height);
|
||||||
|
xoffs->setMaximum(max_width - 1);
|
||||||
|
xoffs->setValue(0);
|
||||||
|
yoffs->setMaximum(max_height - 1);
|
||||||
|
yoffs->setValue(0);
|
||||||
|
label->setText(device + " - " + camera->userName());
|
||||||
|
width->blockSignals(false);
|
||||||
|
height->blockSignals(false);
|
||||||
|
xoffs->blockSignals(false);
|
||||||
|
yoffs->blockSignals(false);
|
||||||
takeStill();
|
takeStill();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,17 +107,19 @@ void CameraPreview::setCamera(QString &device){
|
|||||||
void CameraPreview::takeStill() {
|
void CameraPreview::takeStill() {
|
||||||
qDebug() << "Take Still image!";
|
qDebug() << "Take Still image!";
|
||||||
if (camera != nullptr && camera->isOpen()) {
|
if (camera != nullptr && camera->isOpen()) {
|
||||||
MyImage mimg;
|
ImageSettings s = camera->getImageSettings();
|
||||||
|
MyImage mimg(s.width, s.height);
|
||||||
bool valid = camera->grabFrame(mimg);
|
bool valid = camera->grabFrame(mimg);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
qWarning() << "Grabbing from camera failed!";
|
qWarning() << "Grabbing from camera failed!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
qDebug() << "Grabbed image from camera succeeded!";
|
||||||
QImage img(static_cast<uchar *>(mimg.data()), mimg.width(), mimg.height(),
|
QImage img(static_cast<uchar *>(mimg.data()), mimg.width(), mimg.height(),
|
||||||
QImage::Format::Format_Grayscale8);
|
QImage::Format::Format_Grayscale8);
|
||||||
QPixmap mpm = QPixmap::fromImage(img);
|
QPixmap mpm = QPixmap::fromImage(img);
|
||||||
this->pm = mpm;
|
this->pm = mpm;
|
||||||
mpm = mpm.scaledToWidth(1024);
|
mpm = mpm.scaledToWidth(800);
|
||||||
setImage(mpm);
|
setImage(mpm);
|
||||||
updateROI();
|
updateROI();
|
||||||
} else {
|
} else {
|
||||||
@@ -109,7 +135,7 @@ void CameraPreview::updateWidth(QString s) {
|
|||||||
// if (xoffs->value() + width->value() > 2048) {
|
// if (xoffs->value() + width->value() > 2048) {
|
||||||
// xoffs->setValue(2048 - width->value());
|
// xoffs->setValue(2048 - width->value());
|
||||||
// }
|
// }
|
||||||
validate(width, xoffs, 2048);
|
validate(width, xoffs, camera->sensorWidth());
|
||||||
updateROI();
|
updateROI();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +143,7 @@ void CameraPreview::updateXoffs(QString s) {
|
|||||||
// if (xoffs->value() + width->value() > 2048) {
|
// if (xoffs->value() + width->value() > 2048) {
|
||||||
// width->setValue(2048 - xoffs->value());
|
// width->setValue(2048 - xoffs->value());
|
||||||
// }
|
// }
|
||||||
validate(xoffs, width, 2048);
|
validate(xoffs, width, camera->sensorHeight());
|
||||||
updateROI();
|
updateROI();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +151,7 @@ void CameraPreview::updateHeight(QString s) {
|
|||||||
// if (height->value() + yoffs->value() > 1536) {
|
// if (height->value() + yoffs->value() > 1536) {
|
||||||
// yoffs->setValue(1536 - height->value());
|
// yoffs->setValue(1536 - height->value());
|
||||||
// }
|
// }
|
||||||
validate(height, yoffs, 1536);
|
validate(height, yoffs, camera->sensorHeight());
|
||||||
updateROI();
|
updateROI();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,20 +159,33 @@ void CameraPreview::updateYoffs(QString s) {
|
|||||||
// if (height->value() + yoffs->value() > 1536) {
|
// if (height->value() + yoffs->value() > 1536) {
|
||||||
// height->setValue(1536 - yoffs->value());
|
// height->setValue(1536 - yoffs->value());
|
||||||
// }
|
// }
|
||||||
validate(yoffs, height, 1536);
|
validate(yoffs, height, camera->sensorWidth());
|
||||||
updateROI();
|
updateROI();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CameraPreview::validate(QSpinBox *origin, QSpinBox *dest, int limit){
|
void CameraPreview::validate(QSpinBox *origin, QSpinBox *dest, int limit){
|
||||||
|
qDebug() << "validate";
|
||||||
|
int val = ensureDivbyfour(origin->value());
|
||||||
|
origin->setValue(val);
|
||||||
if (origin->value() + dest->value() > limit) {
|
if (origin->value() + dest->value() > limit) {
|
||||||
dest->setValue(limit - origin->value());
|
dest->setValue(limit - origin->value());
|
||||||
}
|
}
|
||||||
|
qDebug() << "validate done";
|
||||||
|
}
|
||||||
|
|
||||||
|
int CameraPreview::ensureDivbyfour(int val) {
|
||||||
|
// if (val % 4 != 0) {
|
||||||
|
// int divisor = floor(val / 4);
|
||||||
|
// val = divisor * 4;
|
||||||
|
// }
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CameraPreview::updateROI(bool emitSignal) {
|
void CameraPreview::updateROI(bool emitSignal) {
|
||||||
|
qDebug() << "Update roi with signal: " << emitSignal;
|
||||||
QImage img = pm.toImage();
|
QImage img = pm.toImage();
|
||||||
double scaling = 1024.0 / img.width();
|
double scaling = 800.0 / img.width();
|
||||||
img = img.scaledToWidth(1024);
|
img = img.scaledToWidth(800);
|
||||||
QPainter qPainter(&img);
|
QPainter qPainter(&img);
|
||||||
qPainter.setBrush(Qt::NoBrush);
|
qPainter.setBrush(Qt::NoBrush);
|
||||||
qPainter.setPen(Qt::red);
|
qPainter.setPen(Qt::red);
|
||||||
@@ -160,20 +199,24 @@ void CameraPreview::updateROI(bool emitSignal) {
|
|||||||
int rheight = round(height->value() * scaling);
|
int rheight = round(height->value() * scaling);
|
||||||
qPainter.drawRect(rxoffs, ryoffs, rwidth, rheight);
|
qPainter.drawRect(rxoffs, ryoffs, rwidth, rheight);
|
||||||
bool bEnd = qPainter.end();
|
bool bEnd = qPainter.end();
|
||||||
|
|
||||||
QPixmap npm = QPixmap::fromImage(img);
|
QPixmap npm = QPixmap::fromImage(img);
|
||||||
setImage(npm);
|
setImage(npm);
|
||||||
if (emitSignal) {
|
if (emitSignal) {
|
||||||
emit roiUpdated(xoffs->value(), yoffs->value(), width->value(), height->value());
|
emit roiUpdated(xoffs->value(), yoffs->value(), width->value(), height->value());
|
||||||
}
|
}
|
||||||
|
qDebug() << "update ROI done";
|
||||||
}
|
}
|
||||||
|
|
||||||
void CameraPreview::setSize(int w, int h) {
|
void CameraPreview::setSize(int w, int h) {
|
||||||
|
qDebug() << "set size " << w << " " << h;
|
||||||
width->setValue(w);
|
width->setValue(w);
|
||||||
height->setValue(h);
|
height->setValue(h);
|
||||||
validate(width, xoffs, 2048);
|
if (camera != nullptr && camera->isOpen()) {
|
||||||
validate(height, yoffs, 1536);
|
validate(width, xoffs, camera->sensorWidth());
|
||||||
|
validate(height, yoffs, camera->sensorHeight());
|
||||||
|
}
|
||||||
updateROI(false);
|
updateROI(false);
|
||||||
|
qDebug() << "set size done";
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CameraPreview::device(){
|
QString CameraPreview::device(){
|
||||||
@@ -182,12 +225,14 @@ QString CameraPreview::device(){
|
|||||||
|
|
||||||
ROI CameraPreview::getRoi() {
|
ROI CameraPreview::getRoi() {
|
||||||
ROI r;
|
ROI r;
|
||||||
|
uint32_t max_height = camera->sensorHeight();
|
||||||
|
uint32_t max_width = camera->sensorWidth();
|
||||||
r.x = xoffs->value();
|
r.x = xoffs->value();
|
||||||
r.y = yoffs->value();
|
r.y = yoffs->value();
|
||||||
r.width = width->value();
|
r.width = width->value();
|
||||||
r.height = height->value();
|
r.height = height->value();
|
||||||
r.height = r.height > 1536 ? 1536 - r.y : r.height;
|
r.height = r.height > max_height ? max_height - r.y : r.height;
|
||||||
r.width = r.width > 2048 ? 2048 - r.x : r.width;
|
r.width = r.width > max_width ? max_width - r.x : r.width;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,6 +244,6 @@ CameraPreview::~CameraPreview(){
|
|||||||
delete camera;
|
delete camera;
|
||||||
camera = nullptr;
|
camera = nullptr;
|
||||||
}
|
}
|
||||||
qDebug() << "preview: deleted camera";
|
qDebug() << "deleted camera";
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ private:
|
|||||||
void takeStill();
|
void takeStill();
|
||||||
void setImage(const QPixmap &img);
|
void setImage(const QPixmap &img);
|
||||||
void validate(QSpinBox *origin, QSpinBox *dest, int limit);
|
void validate(QSpinBox *origin, QSpinBox *dest, int limit);
|
||||||
|
int ensureDivbyfour(int value);
|
||||||
PylonWrapper *camera;
|
PylonWrapper *camera;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ SingleCamera::SingleCamera (QWidget *parent) :
|
|||||||
this->layout()->addWidget(camera1Preview);
|
this->layout()->addWidget(camera1Preview);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CameraLayout SingleCamera::cameraLayout(){
|
CameraLayout SingleCamera::cameraLayout(){
|
||||||
CameraLayout l;
|
CameraLayout l;
|
||||||
qDebug() << "Request layout";
|
qDebug() << "Request layout";
|
||||||
@@ -20,6 +21,7 @@ CameraLayout SingleCamera::cameraLayout(){
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SingleCamera::~SingleCamera(){
|
SingleCamera::~SingleCamera(){
|
||||||
if (camera1Preview != nullptr) {
|
if (camera1Preview != nullptr) {
|
||||||
delete camera1Preview;
|
delete camera1Preview;
|
||||||
@@ -33,7 +35,8 @@ DualCamera::DualCamera (QWidget *parent) :
|
|||||||
camera1Preview(nullptr),
|
camera1Preview(nullptr),
|
||||||
camera2Preview(nullptr),
|
camera2Preview(nullptr),
|
||||||
primary_device("") {
|
primary_device("") {
|
||||||
qDebug() << "DualCamera View ... ";
|
qDebug() << "DualCamera View constructor... ";
|
||||||
|
std::cerr << "DualCamera View constructor... " << std::endl;
|
||||||
this->setLayout(new QHBoxLayout(this));
|
this->setLayout(new QHBoxLayout(this));
|
||||||
camera1Preview = new CameraPreview();
|
camera1Preview = new CameraPreview();
|
||||||
camera2Preview = new CameraPreview();
|
camera2Preview = new CameraPreview();
|
||||||
@@ -46,11 +49,17 @@ DualCamera::DualCamera (QWidget *parent) :
|
|||||||
|
|
||||||
|
|
||||||
void DualCamera::updateROI1(int x, int y, int w, int h) {
|
void DualCamera::updateROI1(int x, int y, int w, int h) {
|
||||||
camera2Preview->setSize(w, h);
|
qDebug() << "Update ROI1: x " << x << " y " << y << " w " << w << " h " << h;
|
||||||
|
if (camera2Preview != nullptr) {
|
||||||
|
camera2Preview->setSize(w, h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DualCamera::updateROI2(int x, int y, int w, int h) {
|
void DualCamera::updateROI2(int x, int y, int w, int h) {
|
||||||
camera1Preview->setSize(w, h);
|
qDebug() << "Update ROI2: x " << x << " y " << y << " w " << w << " h " << h;
|
||||||
|
if (camera1Preview != nullptr) {
|
||||||
|
camera1Preview->setSize(w, h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DualCamera::switchArrangement() {
|
void DualCamera::switchArrangement() {
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
void setPrimaryCamera(QString &device) {
|
void setPrimaryCamera(QString &device) {
|
||||||
qDebug() << "Update primary camera";
|
qDebug() << "Update primary camera to " << device;
|
||||||
if (camera1Preview != nullptr) {
|
if (camera1Preview != nullptr) {
|
||||||
camera1Preview->setCamera(device);
|
camera1Preview->setCamera(device);
|
||||||
primary_device = device;
|
primary_device = device;
|
||||||
@@ -71,7 +71,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
void setSecondaryCamera(QString &device) {
|
void setSecondaryCamera(QString &device) {
|
||||||
qDebug()<< "Update secondary camera";
|
qDebug()<< "Update secondary camera to " << device;
|
||||||
if (camera2Preview != nullptr) {
|
if (camera2Preview != nullptr) {
|
||||||
camera2Preview->setCamera(device);
|
camera2Preview->setCamera(device);
|
||||||
}
|
}
|
||||||
|
|||||||
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
|
||||||
|
|
||||||
85
dualcamgrabber.cpp
Normal file
85
dualcamgrabber.cpp
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#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 counter = 0;
|
||||||
|
|
||||||
|
if (!wrapper->isOpen()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pylon::CInstantCameraArray &cameras = wrapper->getCameraArray();
|
||||||
|
wrapper->frameRate(static_cast<uint>(100), -1);
|
||||||
|
|
||||||
|
wrapper->exposureTime(exposure);
|
||||||
|
wrapper->gain(gain);
|
||||||
|
wrapper->enableSoftwareTrigger(0);
|
||||||
|
wrapper->enableSoftwareTrigger(1);
|
||||||
|
|
||||||
|
cameras.StartGrabbing();
|
||||||
|
Pylon::CGrabResultPtr frame0, frame1;
|
||||||
|
Pylon::CPylonImage leftImage;
|
||||||
|
Pylon::CPylonImage rightImage;
|
||||||
|
Pylon::CPylonImage stitchedImage;
|
||||||
|
std::string errorMessage = "";
|
||||||
|
bool failure = false;
|
||||||
|
|
||||||
|
auto before = high_resolution_clock::now();
|
||||||
|
auto done = high_resolution_clock::now();
|
||||||
|
auto total_duration = duration_cast<microseconds>(done - before);
|
||||||
|
int expected_usecs = (int)(1./framerate * 1000000);
|
||||||
|
|
||||||
|
while (cameras.IsGrabbing() && !stop_request && !failure) {
|
||||||
|
if (counter > 0) {
|
||||||
|
long delay = total_duration.count() - expected_usecs;
|
||||||
|
if (delay > 0) {
|
||||||
|
emit delayed(delay, counter-1);
|
||||||
|
} else {
|
||||||
|
usleep(-delay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
before = high_resolution_clock::now();
|
||||||
|
|
||||||
|
if (cameras[0].WaitForFrameTriggerReady(1000, Pylon::TimeoutHandling_ThrowException) &&
|
||||||
|
cameras[1].WaitForFrameTriggerReady(1000, Pylon::TimeoutHandling_ThrowException)) {
|
||||||
|
// std::cerr << "executing software triggers" << std::endl;
|
||||||
|
cameras[0].ExecuteSoftwareTrigger();
|
||||||
|
cameras[1].ExecuteSoftwareTrigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
cameras[0].RetrieveResult( 5000, frame0, Pylon::TimeoutHandling_ThrowException );
|
||||||
|
cameras[1].RetrieveResult( 5000, frame1, Pylon::TimeoutHandling_ThrowException );
|
||||||
|
leftImage.AttachGrabResultBuffer( frame0 );
|
||||||
|
rightImage.AttachGrabResultBuffer( frame1 );
|
||||||
|
} catch( const Pylon::GenericException &e ) {
|
||||||
|
qDebug() << "Grabbing frame failed! " << e.what();
|
||||||
|
failure = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!failure && leftImage.IsValid() && rightImage.IsValid()) {
|
||||||
|
try {
|
||||||
|
StitchImage::StitchToRight(leftImage, rightImage, &stitchedImage, errorMessage);
|
||||||
|
MyImage *img = new MyImage(stitchedImage.GetWidth(), stitchedImage.GetHeight());
|
||||||
|
img->setFrame(stitchedImage);
|
||||||
|
buffer->push(img);
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
std::cerr << e.what() << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
counter += 1;
|
||||||
|
done = high_resolution_clock::now();
|
||||||
|
total_duration = duration_cast<microseconds>(done - before);
|
||||||
|
}
|
||||||
|
cameras.StopGrabbing();
|
||||||
|
}
|
||||||
59
dualcamgrabber.h
Normal file
59
dualcamgrabber.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#ifndef DUALCAMGRABBER_H
|
||||||
|
#define DUALCAMGRABBER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QThread>
|
||||||
|
#include "dualcamwrapper.h"
|
||||||
|
#include "imagebuffer.h"
|
||||||
|
|
||||||
|
class DualcamGrabber : public QThread
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
DualcamGrabber(DualcamWrapper *wrapper, ImageBuffer *buffer, int framerate, QObject *parent = nullptr) :
|
||||||
|
QThread(parent), wrapper(wrapper), buffer(buffer), framerate(framerate) {}
|
||||||
|
|
||||||
|
void run() override;
|
||||||
|
void stop();
|
||||||
|
int currentFramerate() {
|
||||||
|
return framerate;
|
||||||
|
}
|
||||||
|
|
||||||
|
double currentExposureTime() {
|
||||||
|
return exposure;
|
||||||
|
}
|
||||||
|
|
||||||
|
double currentGain() {
|
||||||
|
return gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool stop_request = false;
|
||||||
|
DualcamWrapper *wrapper;
|
||||||
|
ImageBuffer *buffer;
|
||||||
|
int framerate;
|
||||||
|
double exposure, gain;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void requestStop() {
|
||||||
|
stop_request=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFrameRate(int newFramerate) {
|
||||||
|
framerate = newFramerate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setExposureTime(double newExposureTime) {
|
||||||
|
exposure = newExposureTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGain(double gain_db) {
|
||||||
|
gain = gain_db;
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void terminated();
|
||||||
|
void delayed(int, int);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DUALCAMGRABBER_H
|
||||||
324
dualcamwrapper.cpp
Normal file
324
dualcamwrapper.cpp
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
#include "dualcamwrapper.h"
|
||||||
|
|
||||||
|
DualcamWrapper::DualcamWrapper(const CameraLayout &layout): valid(false), withLayout(true) {
|
||||||
|
qDebug() << "Constructor with layout";
|
||||||
|
this->layout = layout;
|
||||||
|
Pylon::PylonInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DualcamWrapper::~DualcamWrapper() {
|
||||||
|
qDebug() << "wrapper destructor";
|
||||||
|
for (int i =0; i < cameras.GetSize(); ++i) {
|
||||||
|
if (cameras[i].IsOpen()) {
|
||||||
|
cameras[i].Close();
|
||||||
|
qDebug() << "Camera " << i << " is open, closing it!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
terminate();
|
||||||
|
qDebug() << "Successfully deleted cameras";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DualcamWrapper::terminate() {
|
||||||
|
qDebug() << "Terminate";
|
||||||
|
try {
|
||||||
|
Pylon::PylonTerminate();
|
||||||
|
} catch (const Pylon::GenericException &e) {
|
||||||
|
std::cerr << e.GetDescription() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DualcamWrapper::isOpen() {
|
||||||
|
return cameras.IsOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double DualcamWrapper::maxFrameRate(int camindex) {
|
||||||
|
assert(camindex >= 0 && camindex < 2);
|
||||||
|
double max_rate = -1;
|
||||||
|
if (valid) {
|
||||||
|
GenApi::INodeMap& nodemap = getNodemap(camindex);
|
||||||
|
GenApi::INode* n = nodemap.GetNode( "AcquisitionFrameRate" );
|
||||||
|
Pylon::CFloatParameter framerate( n );
|
||||||
|
return framerate.GetMax();
|
||||||
|
}
|
||||||
|
return max_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DualcamWrapper::frameRate(uint new_framerate, int camindex) {
|
||||||
|
qDebug() << "Setting FrameRate to " << new_framerate << " for camera " << camindex;
|
||||||
|
if (valid) {
|
||||||
|
if (camindex == -1) {
|
||||||
|
frameRate(new_framerate, 0);
|
||||||
|
frameRate(new_framerate, 1);
|
||||||
|
return true;
|
||||||
|
} else if (camindex >= 0 && camindex < 2) {
|
||||||
|
GenApi::INodeMap& nodemap = getNodemap(camindex);
|
||||||
|
GenApi::INode* n = nodemap.GetNode( "AcquisitionFrameRateEnable" );
|
||||||
|
Pylon::CBooleanParameter enableframerate(n);
|
||||||
|
enableframerate.SetValue(true);
|
||||||
|
n = nodemap.GetNode( "AcquisitionFrameRate" );
|
||||||
|
Pylon::CFloatParameter framerate( n );
|
||||||
|
framerate.SetValue( new_framerate );
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double DualcamWrapper::frameRate(int camindex) {
|
||||||
|
qDebug() << "Reading FrameRate from camera " << camindex;
|
||||||
|
assert(camindex >= 0 && camindex < 2);
|
||||||
|
double rate = -1.;
|
||||||
|
if (valid) {
|
||||||
|
GenApi::INodeMap& nodemap = getNodemap(camindex);
|
||||||
|
GenApi::INode* n = nodemap.GetNode( "AcquisitionFrameRate" );
|
||||||
|
Pylon::CFloatParameter framerate( n );
|
||||||
|
rate = framerate.GetValue();
|
||||||
|
}
|
||||||
|
return rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double DualcamWrapper::exposureTime(int camindex) {
|
||||||
|
qDebug() << "Reading ExposureTime from camera " << camindex;
|
||||||
|
assert(camindex > 0 && camindex < 2);
|
||||||
|
double time = -1.;
|
||||||
|
if (valid) {
|
||||||
|
GenApi::INodeMap& nodemap = getNodemap(camindex);
|
||||||
|
GenApi::INode* n = nodemap.GetNode( "ExposureTime" );
|
||||||
|
Pylon::CFloatParameter exposure_time( n );
|
||||||
|
time = exposure_time.GetValue();
|
||||||
|
}
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DualcamWrapper::exposureTime(double exposure_time, int camindex) {
|
||||||
|
qDebug() << "Setting exposure time to " << exposure_time << " for camera " << camindex;
|
||||||
|
if (valid) {
|
||||||
|
if (camindex == -1) {
|
||||||
|
exposureTime(exposure_time, 0);
|
||||||
|
exposureTime(exposure_time, 1);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
GenApi::INodeMap& nodemap = getNodemap(camindex);
|
||||||
|
GenApi::INode* n = nodemap.GetNode( "ExposureTime" );
|
||||||
|
Pylon::CFloatParameter exp_time( n );
|
||||||
|
exp_time.SetValue( exposure_time );
|
||||||
|
GenApi::CEnumerationPtr(nodemap.GetNode( "ExposureTimeMode" ))->FromString("Timed");;
|
||||||
|
} catch (...) {
|
||||||
|
|
||||||
|
qWarning() << "Could not set exposure for cam " << camindex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DualcamWrapper::sensorWidth(int camindex) {
|
||||||
|
qDebug() << "Reading SensorWidth from camera " << camindex;
|
||||||
|
assert(camindex >= 0 && camindex < 2);
|
||||||
|
uint32_t width = -1;
|
||||||
|
if (valid) {
|
||||||
|
GenApi::INodeMap &nodemap = getNodemap(camindex);
|
||||||
|
Pylon::CIntegerParameter pwidth( nodemap, "SensorWidth" );
|
||||||
|
width = (uint32_t)pwidth.GetValue();
|
||||||
|
}
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DualcamWrapper::sensorHeight(int camindex) {
|
||||||
|
qDebug() << "Reading SensorHeight from camera " << camindex;
|
||||||
|
assert(camindex >= 0 && camindex < 2);
|
||||||
|
uint32_t height = -1;
|
||||||
|
if (valid) {
|
||||||
|
GenApi::INodeMap &nodemap = getNodemap(camindex);
|
||||||
|
Pylon::CIntegerParameter pheight( nodemap, "SensorHeight" );
|
||||||
|
height = (uint32_t)pheight.GetValue();
|
||||||
|
}
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
double DualcamWrapper::gain(int camindex) {
|
||||||
|
qDebug() << "Reading Gain from camera " << camindex;
|
||||||
|
assert(camindex >= 0 && camindex < 2);
|
||||||
|
double gain = -1.;
|
||||||
|
if (valid) {
|
||||||
|
GenApi::INodeMap& nodemap = getNodemap(camindex);
|
||||||
|
GenApi::INode* n = nodemap.GetNode( "Gain" );
|
||||||
|
Pylon::CFloatParameter detector_gain( n );
|
||||||
|
gain = detector_gain.GetValue();
|
||||||
|
}
|
||||||
|
return gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DualcamWrapper::gain(double gain_db, int camindex) {
|
||||||
|
if (valid) {
|
||||||
|
if (camindex == -1) {
|
||||||
|
gain(gain_db, 0);
|
||||||
|
gain(gain_db, 1);
|
||||||
|
} else if (camindex >= 0 && camindex < 2) {
|
||||||
|
GenApi::INodeMap& nodemap = getNodemap(camindex);
|
||||||
|
GenApi::CFloatPtr(nodemap.GetNode("Gain"))->SetValue(gain_db);
|
||||||
|
return true;
|
||||||
|
} else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ImageSettings DualcamWrapper::getImageSettings(int camindex) {
|
||||||
|
ImageSettings settings;
|
||||||
|
if (valid) {
|
||||||
|
GenApi::INodeMap &nodemap = getNodemap(camindex);
|
||||||
|
Pylon::CEnumParameter pixelFormat( nodemap, "PixelFormat" );
|
||||||
|
Pylon::CPixelTypeMapper pixelTypeMapper( &pixelFormat );
|
||||||
|
Pylon::EPixelType pixelType = pixelTypeMapper.GetPylonPixelTypeFromNodeValue( pixelFormat.GetIntValue() );
|
||||||
|
Pylon::CIntegerParameter width( nodemap, "Width" );
|
||||||
|
Pylon::CIntegerParameter height( nodemap, "Height" );
|
||||||
|
settings.pixelType = pixelType;
|
||||||
|
settings.width = (uint32_t)width.GetValue();
|
||||||
|
settings.height = (uint32_t)height.GetValue();
|
||||||
|
settings.orientation = Pylon::EImageOrientation::ImageOrientation_TopDown;
|
||||||
|
}
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DualcamWrapper::grabFrame(MyImage &img, int camindex) {
|
||||||
|
Pylon::CGrabResultPtr frame;
|
||||||
|
Pylon::CInstantCamera* camera;
|
||||||
|
qDebug() << "grabFrame from camera " << camindex;
|
||||||
|
if (valid) {
|
||||||
|
GenApi::INodeMap &nodemap = getNodemap(camindex);
|
||||||
|
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[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);
|
||||||
|
camera->StopGrabbing();
|
||||||
|
}
|
||||||
|
img.setFrame(frame);
|
||||||
|
return frame.IsValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
try {
|
||||||
|
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);
|
||||||
|
} catch (const Pylon::GenericException &e) {
|
||||||
|
std::cerr << e.GetDescription() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DualcamWrapper::resetCamera(int camindex) {
|
||||||
|
GenApi::INodeMap &nodemap = getNodemap( camindex );
|
||||||
|
uint32_t width = sensorWidth(camindex);
|
||||||
|
uint32_t height = sensorHeight(camindex);
|
||||||
|
qDebug() << "resetting camera to default ROI (" << width << ", " << height << ")";
|
||||||
|
try {
|
||||||
|
Pylon::CIntegerParameter(nodemap, "Width").SetValue(width, false);
|
||||||
|
Pylon::CIntegerParameter(nodemap, "Height").SetValue(height, false);
|
||||||
|
Pylon::CIntegerParameter(nodemap, "OffsetX").SetValue(0);
|
||||||
|
Pylon::CIntegerParameter(nodemap, "OffsetY").SetValue(0);
|
||||||
|
} catch (const Pylon::GenericException &e) {
|
||||||
|
std::string message = e.GetDescription();
|
||||||
|
std::cerr << "An exception occurred." << std::endl << e.GetDescription() << std::endl;
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DualcamWrapper::openCameras(std::string &message) {
|
||||||
|
qDebug() << "opening cameras";
|
||||||
|
Pylon::CTlFactory& tlFactory = Pylon::CTlFactory::GetInstance();
|
||||||
|
cameras.Initialize(2);
|
||||||
|
try {
|
||||||
|
cameras[0].Attach( tlFactory.CreateDevice( layout.devices[0].c_str() ) );
|
||||||
|
cameras[0].Open();
|
||||||
|
cameras[1].Attach( tlFactory.CreateDevice( layout.devices[1].c_str() ) );
|
||||||
|
cameras[1].Open();
|
||||||
|
valid = cameras[0].IsOpen();
|
||||||
|
valid = valid & cameras[1].IsOpen();
|
||||||
|
message = "Successfully opened camera!";
|
||||||
|
} catch (const Pylon::GenericException &e) {
|
||||||
|
message = e.GetDescription();
|
||||||
|
std::cerr << "An exception occurred." << std::endl << e.GetDescription() << std::endl;
|
||||||
|
valid = false;
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
// resetCamera(0);
|
||||||
|
// resetCamera(1);
|
||||||
|
setROI();
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DualcamWrapper::closeCameras() {
|
||||||
|
qDebug() << "Close cameras!";
|
||||||
|
if (cameras[0].IsOpen()) {
|
||||||
|
cameras[0].Close();
|
||||||
|
}
|
||||||
|
if (cameras[1].IsOpen()) {
|
||||||
|
cameras[1].Close();
|
||||||
|
}
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pylon::CInstantCameraArray &DualcamWrapper::getCameraArray() {
|
||||||
|
return cameras;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pylon::CInstantCamera DualcamWrapper::getCamera(int camindex) {
|
||||||
|
// return this.cameras[camindex];
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
GenApi::INodeMap& DualcamWrapper::getNodemap(int camindex){
|
||||||
|
GenApi::INodeMap &nodemap = cameras[camindex].GetNodeMap();
|
||||||
|
return nodemap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DualcamWrapper::enableSoftwareTrigger(int camindex){
|
||||||
|
qDebug() << "Enabling software trigger for camera " << camindex;
|
||||||
|
GenApi::INodeMap &nodemap = getNodemap( camindex );
|
||||||
|
Pylon::CEnumParameter(nodemap, "TriggerMode").SetValue("On");
|
||||||
|
Pylon::CEnumParameter(nodemap, "TriggerSource").SetValue("Software");
|
||||||
|
// Pylon::CEnumParameter(nodemap, "TriggerActivation").SetValue("LevelHigh");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DualcamWrapper::disableSoftwareTrigger(int camindex){
|
||||||
|
qDebug() << "Disabling software trigger for camera " << camindex;
|
||||||
|
GenApi::INodeMap& nodemap = getNodemap(camindex);
|
||||||
|
Pylon::CEnumParameter(nodemap, "TriggerMode").SetValue("Off");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DualcamWrapper::softwareTriggerEnabeled(int camindex){
|
||||||
|
qDebug() << "Checking software trigger for camera " << camindex;
|
||||||
|
GenApi::INodeMap& nodemap = getNodemap(camindex);
|
||||||
|
return Pylon::CEnumParameter(nodemap, "TriggerMode").GetValue() == "On";
|
||||||
|
}
|
||||||
48
dualcamwrapper.h
Normal file
48
dualcamwrapper.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef DUALCAMWRAPPER_H
|
||||||
|
#define DUALCAMWRAPPER_H
|
||||||
|
|
||||||
|
#include <pylon/PylonIncludes.h>
|
||||||
|
#include <pylon/BaslerUniversalInstantCamera.h>
|
||||||
|
#include "mylogger.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "myimage.h"
|
||||||
|
|
||||||
|
|
||||||
|
class DualcamWrapper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// DualcamWrapper(const std::string &name);
|
||||||
|
DualcamWrapper(const CameraLayout &layout);
|
||||||
|
~DualcamWrapper();
|
||||||
|
|
||||||
|
ImageSettings getImageSettings(int camindex);
|
||||||
|
uint32_t sensorWidth(int camindex);
|
||||||
|
uint32_t sensorHeight(int camindex);
|
||||||
|
bool isOpen();
|
||||||
|
void terminate();
|
||||||
|
bool openCameras(std::string &message);
|
||||||
|
void closeCameras();
|
||||||
|
bool grabFrame(MyImage &img, int camindex=0);
|
||||||
|
bool frameRate(uint framerate, int camindex=-1);
|
||||||
|
double frameRate(int camindex);
|
||||||
|
double maxFrameRate(int camindex);
|
||||||
|
double exposureTime(int camindex);
|
||||||
|
bool exposureTime(double exposure_time, int camindex=-1);
|
||||||
|
double gain(int camindex);
|
||||||
|
bool gain(double gain_db, int camindex=-1);
|
||||||
|
void enableSoftwareTrigger(int camindex);
|
||||||
|
void disableSoftwareTrigger(int camindex);
|
||||||
|
bool softwareTriggerEnabeled(int camindex);
|
||||||
|
Pylon::CInstantCameraArray &getCameraArray();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void resetCamera(int camindex);
|
||||||
|
Pylon::CInstantCameraArray cameras;
|
||||||
|
GenApi::INodeMap& getNodemap(int camindex);
|
||||||
|
void setROI();
|
||||||
|
bool valid, withLayout;
|
||||||
|
CameraLayout layout;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DUALCAMWRAPPER_H
|
||||||
12
grabber.cpp
12
grabber.cpp
@@ -1,8 +1,6 @@
|
|||||||
#include "grabber.h"
|
#include "grabber.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <pylon/PylonIncludes.h>
|
#include <pylon/PylonIncludes.h>
|
||||||
#include <chrono>
|
|
||||||
using namespace std::chrono;
|
|
||||||
|
|
||||||
void Grabber::run() {
|
void Grabber::run() {
|
||||||
stop_request = false;
|
stop_request = false;
|
||||||
@@ -11,19 +9,15 @@ void Grabber::run() {
|
|||||||
camera->frameRate(static_cast<uint>(framerate));
|
camera->frameRate(static_cast<uint>(framerate));
|
||||||
camera->exposureTime(exposure);
|
camera->exposureTime(exposure);
|
||||||
camera->gain(gain);
|
camera->gain(gain);
|
||||||
Pylon::CGrabResultPtr frame;
|
ImageSettings settings = camera->getImageSettings();
|
||||||
Pylon::CInstantCamera *cam = camera->getCamera();
|
Pylon::CInstantCamera *cam = camera->getCamera();
|
||||||
|
Pylon::CGrabResultPtr frame;
|
||||||
cam->StartGrabbing();
|
cam->StartGrabbing();
|
||||||
while (camera->isOpen() && !stop_request) {
|
while (camera->isOpen() && !stop_request) {
|
||||||
MyImage *img = new MyImage();
|
MyImage *img = new MyImage(settings.width, settings.height);
|
||||||
auto start = high_resolution_clock::now();
|
|
||||||
cam->RetrieveResult( 5000, frame, Pylon::TimeoutHandling_ThrowException);
|
cam->RetrieveResult( 5000, frame, Pylon::TimeoutHandling_ThrowException);
|
||||||
auto stop1 = high_resolution_clock::now();
|
|
||||||
img->setFrame(frame);
|
img->setFrame(frame);
|
||||||
auto stop2 = high_resolution_clock::now();
|
|
||||||
buffer->push(img);
|
buffer->push(img);
|
||||||
auto duration1 = duration_cast<microseconds>(stop1 - start);
|
|
||||||
auto duration2 = duration_cast<microseconds>(stop2 - stop1);
|
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
cam->StopGrabbing();
|
cam->StopGrabbing();
|
||||||
|
|||||||
101
imagebuffer.cpp
101
imagebuffer.cpp
@@ -1,83 +1,77 @@
|
|||||||
#include "imagebuffer.h"
|
#include "imagebuffer.h"
|
||||||
|
#include "mylogger.h"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
ImageBuffer::ImageBuffer(size_t buffer_size, QObject *parent) : QObject(parent), buffer_size(buffer_size) {
|
ImageBuffer::ImageBuffer(size_t buffer_size, QObject *parent) : QObject(parent), buffer_size(buffer_size) {
|
||||||
buffer.resize(buffer_size, nullptr);
|
buffer.resize(buffer_size, nullptr);
|
||||||
std::cerr << "imagebuffer constructor!" << std::endl;
|
qDebug() << "Imagebuffer constructor!";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageBuffer::clear() {
|
void ImageBuffer::clear() {
|
||||||
std::cerr << "Clear Image buffer!" << std::endl;
|
qDebug() << "Clear Image buffer!";
|
||||||
|
|
||||||
for (auto & img: buffer) {
|
for (auto & img: buffer) {
|
||||||
std::cerr << "Clear Image buffer!" << std::endl;
|
|
||||||
|
|
||||||
if (img != nullptr)
|
if (img != nullptr)
|
||||||
delete(img);
|
delete(img);
|
||||||
img = nullptr;
|
img = nullptr;
|
||||||
}
|
}
|
||||||
std::cerr << "Clear Image buffer!" << std::endl;
|
|
||||||
|
|
||||||
resize(buffer_size);
|
resize(buffer_size);
|
||||||
std::cerr << "Clear Image buffer! done" << std::endl;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ImageBuffer::capacity() {
|
size_t ImageBuffer::capacity() {
|
||||||
return buffer.capacity();
|
return buffer.capacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
double ImageBuffer::bufferPreassure() {
|
double ImageBuffer::bufferPressure() {
|
||||||
double preassure;
|
double pressure;
|
||||||
|
size_t l = bufferLoad();
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
preassure = static_cast<double>(load)/static_cast<double>(buffer.capacity());
|
pressure = l / buffer_size * 100;
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
return preassure * 100;
|
return pressure;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ImageBuffer::bufferLoad() {
|
size_t ImageBuffer::bufferLoad() {
|
||||||
size_t l;
|
size_t l;
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
l = load;
|
if (read_idx > head_idx){
|
||||||
|
l = buffer_size - read_idx - head_idx;
|
||||||
|
} else {
|
||||||
|
l = head_idx - read_idx;
|
||||||
|
}
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageBuffer::resize(size_t new_size) {
|
void ImageBuffer::resize(size_t new_size) {
|
||||||
std::cerr << "Buffer Resize" << std::endl;
|
qDebug() << "Buffer Resize";
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
|
|
||||||
buffer_size = new_size;
|
buffer_size = new_size;
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
buffer.resize(new_size, nullptr);
|
buffer.resize(buffer_size, nullptr);
|
||||||
current_read_index = 0;
|
framecounts.clear();
|
||||||
current_write_index = 0;
|
framecounts.resize(buffer_size, 0);
|
||||||
|
read_idx = 0;
|
||||||
|
head_idx = 0;
|
||||||
load = 0;
|
load = 0;
|
||||||
|
framecount = 0;
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageBuffer::push(MyImage *img) {
|
void ImageBuffer::push(MyImage *img) {
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
if (buffer[current_write_index] != nullptr) {
|
head_idx += 1;
|
||||||
std::cerr << "possible frame drop detected!!" << std::endl;
|
framecount +=1;
|
||||||
std::cerr << "buffer.push write: " << current_write_index << " read: " << current_read_index << " load: " << load << std::endl;
|
if (head_idx >= buffer_size) {
|
||||||
|
head_idx = 0;
|
||||||
delete(buffer[current_write_index]);
|
|
||||||
}
|
}
|
||||||
buffer[current_write_index] = img;
|
if (buffer[head_idx] != nullptr) {
|
||||||
current_write_index += 1;
|
delete(buffer[head_idx]);
|
||||||
load += 1;
|
|
||||||
if (current_write_index >= buffer_size){
|
|
||||||
current_write_index = 0;
|
|
||||||
}
|
|
||||||
if (load >= buffer_size){
|
|
||||||
load = buffer_size;
|
|
||||||
if (current_read_index == current_write_index)
|
|
||||||
current_read_index = current_write_index < buffer_size - 1 ? current_write_index + 1 : 0;
|
|
||||||
}
|
}
|
||||||
// std::cout << "Buffer.afterpush: load = " << load << " write index =" << current_write_index << " read index = " << current_read_index << std::endl;
|
buffer[head_idx] = img;
|
||||||
|
framecounts[head_idx] = framecount;
|
||||||
|
load = load < buffer_size ? load +=1 : buffer_size;
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,38 +83,33 @@ bool ImageBuffer::bufferNotEmpty() {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
MyImage* ImageBuffer::pop() {
|
MyImage* ImageBuffer::read(size_t &framecount){
|
||||||
bool ret = false;
|
MyImage *img = nullptr;
|
||||||
MyImage * img;
|
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
if (load > 0) {
|
if (read_idx < head_idx) {
|
||||||
img = buffer[current_read_index];
|
read_idx += 1;
|
||||||
current_read_index < (buffer_size - 1) ? current_read_index += 1 : current_read_index = 0;
|
} else if (read_idx > head_idx) {
|
||||||
load -= 1;
|
read_idx < buffer_size ? read_idx += 1 : read_idx = 0;
|
||||||
|
} else {
|
||||||
|
framecount = 0;
|
||||||
|
return img;
|
||||||
}
|
}
|
||||||
|
img = buffer[read_idx];
|
||||||
|
framecount = framecounts[read_idx];
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
std::cerr << "buffer.pop write: " << current_write_index << " read: " << current_read_index << " load: " << load << std::endl;
|
|
||||||
|
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
MyImage* ImageBuffer::readLast() {
|
MyImage* ImageBuffer::readLast(size_t &framecount) {
|
||||||
MyImage *img;
|
MyImage *img = nullptr;
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
if (load > 0) {
|
img = buffer[head_idx];
|
||||||
size_t idx = current_write_index - 1;
|
framecount = framecounts[head_idx];
|
||||||
|
|
||||||
if (idx < 0) {
|
|
||||||
std::cerr << "Bank" << std::endl;
|
|
||||||
idx = buffer_size - 1;
|
|
||||||
}
|
|
||||||
img = buffer[idx];
|
|
||||||
}
|
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageBuffer::~ImageBuffer(){
|
ImageBuffer::~ImageBuffer(){
|
||||||
std::cerr << "Image buffer destructor" << std::endl;
|
qDebug() << "Image buffer destructor";
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
@@ -17,10 +17,10 @@ public:
|
|||||||
void clear();
|
void clear();
|
||||||
void resize(size_t new_size);
|
void resize(size_t new_size);
|
||||||
void push(MyImage *img);
|
void push(MyImage *img);
|
||||||
MyImage* pop();
|
MyImage* read(size_t &framecount);
|
||||||
MyImage* readLast();
|
MyImage* readLast(size_t &framecount);
|
||||||
size_t capacity();
|
size_t capacity();
|
||||||
double bufferPreassure();
|
double bufferPressure();
|
||||||
size_t bufferLoad();
|
size_t bufferLoad();
|
||||||
bool bufferNotEmpty();
|
bool bufferNotEmpty();
|
||||||
|
|
||||||
@@ -29,10 +29,12 @@ private:
|
|||||||
int numUsedBytes = 0;
|
int numUsedBytes = 0;
|
||||||
|
|
||||||
std::vector<MyImage*> buffer;
|
std::vector<MyImage*> buffer;
|
||||||
size_t current_write_index = 0;
|
std::vector<size_t> framecounts;
|
||||||
size_t current_read_index = 0;
|
size_t head_idx = 0;
|
||||||
|
size_t read_idx = 0;
|
||||||
size_t load = 0;
|
size_t load = 0;
|
||||||
size_t buffer_size;
|
size_t buffer_size;
|
||||||
|
size_t framecount = 0;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
|
|||||||
29
myimage.cpp
29
myimage.cpp
@@ -1,20 +1,41 @@
|
|||||||
#include "myimage.h"
|
#include "myimage.h"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include "mylogger.h"
|
||||||
|
|
||||||
MyImage::MyImage()
|
MyImage::MyImage(uint32_t width, uint32_t height): img_width(width), img_height(height)
|
||||||
{}
|
{
|
||||||
|
buffer = new char[width * height];
|
||||||
|
}
|
||||||
|
|
||||||
MyImage::MyImage(Pylon::CGrabResultPtr ptr) {
|
MyImage::MyImage(Pylon::CGrabResultPtr ptr) {
|
||||||
setFrame(ptr);
|
setFrame(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MyImage::~MyImage() {
|
||||||
|
delete[] buffer;
|
||||||
|
}
|
||||||
|
|
||||||
bool MyImage::setFrame(Pylon::CGrabResultPtr ptr) {
|
bool MyImage::setFrame(Pylon::CGrabResultPtr ptr) {
|
||||||
|
qDebug() << "Setting frame from pointer";
|
||||||
bool valid = ptr.IsValid() && ptr->GetWidth() <= max_width && ptr->GetHeight() <= max_height;
|
bool valid = ptr.IsValid() && ptr->GetWidth() <= max_width && ptr->GetHeight() <= max_height;
|
||||||
if (valid) {
|
if (valid) {
|
||||||
img_index = ptr->GetID();
|
img_index = ptr->GetID();
|
||||||
img_width = ptr->GetWidth();
|
img_width = ptr->GetWidth();
|
||||||
img_height = ptr->GetHeight();
|
img_height = ptr->GetHeight();
|
||||||
memcpy(&buffer, ptr->GetBuffer(), ptr->GetImageSize());
|
memcpy(buffer, ptr->GetBuffer(), ptr->GetImageSize());
|
||||||
|
auto t = std::chrono::system_clock::now();
|
||||||
|
img_timestamp = std::chrono::system_clock::to_time_t(t);
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MyImage::setFrame( Pylon::CPylonImage &img) {
|
||||||
|
qDebug() << "Setting frame from Pylon image (" << img.GetWidth() << "x" << img.GetHeight() << ")";
|
||||||
|
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();
|
auto t = std::chrono::system_clock::now();
|
||||||
img_timestamp = std::chrono::system_clock::to_time_t(t);
|
img_timestamp = std::chrono::system_clock::to_time_t(t);
|
||||||
}
|
}
|
||||||
@@ -38,7 +59,7 @@ int64_t MyImage::index() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *MyImage::data() {
|
void *MyImage::data() {
|
||||||
return &buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t MyImage::timestamp() {
|
time_t MyImage::timestamp() {
|
||||||
|
|||||||
10
myimage.h
10
myimage.h
@@ -6,8 +6,9 @@
|
|||||||
class MyImage
|
class MyImage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MyImage();
|
MyImage(uint32_t width, uint32_t height);
|
||||||
MyImage(Pylon::CGrabResultPtr ptr);
|
MyImage(Pylon::CGrabResultPtr ptr);
|
||||||
|
~MyImage();
|
||||||
|
|
||||||
int width();
|
int width();
|
||||||
int height();
|
int height();
|
||||||
@@ -16,15 +17,16 @@ public:
|
|||||||
void* data();
|
void* data();
|
||||||
time_t timestamp();
|
time_t timestamp();
|
||||||
bool setFrame(Pylon::CGrabResultPtr ptr);
|
bool setFrame(Pylon::CGrabResultPtr ptr);
|
||||||
|
bool setFrame(Pylon::CPylonImage &img);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t img_width = 0;
|
uint32_t img_width = 0;
|
||||||
uint32_t img_height = 0;
|
uint32_t img_height = 0;
|
||||||
int64_t img_index = 0;
|
int64_t img_index = 0;
|
||||||
time_t img_timestamp;
|
time_t img_timestamp;
|
||||||
static const int max_width = 2048;
|
static const int max_width = 5184;
|
||||||
static const int max_height = 1536;
|
static const int max_height = 2048;
|
||||||
char buffer[max_width * max_height];
|
char *buffer; //[max_width * max_height];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MYIMAGE_H
|
#endif // MYIMAGE_H
|
||||||
|
|||||||
30
notes.md
30
notes.md
@@ -3,12 +3,34 @@
|
|||||||
Recorder for up to two Basler cameras.
|
Recorder for up to two Basler cameras.
|
||||||
|
|
||||||
## TODOs
|
## TODOs
|
||||||
|
|
||||||
* implement grabbing from 2 joined cameras
|
* implement grabbing from 2 joined cameras
|
||||||
* set the region of interest
|
* set the region of interest
|
||||||
* save properly
|
* !!! dual cam writer!!! chgeck file opening!
|
||||||
|
|
||||||
## FIXMEs & improvements
|
## FIXMEs
|
||||||
|
|
||||||
|
* dualcamwrapper: remove hardcode
|
||||||
|
* dualcamwrapper: support setting exposure individually
|
||||||
|
* dualcamwrapper: support setting gain individually
|
||||||
|
* pylonrecorder somehow remembers the old layout:
|
||||||
|
* display of images during recording of both cameras.
|
||||||
|
*
|
||||||
|
|
||||||
|
## Improvements
|
||||||
|
|
||||||
* make the max image sizes depend on camera
|
* make the max image sizes depend on camera
|
||||||
|
* detect framedrops based on the framecounts
|
||||||
|
* support reading out camera health (temperature)
|
||||||
|
* add interface to change camera DeviceUserID to provided an user friendly name for the cameras
|
||||||
|
* code cleanup check import guards
|
||||||
|
* check private public
|
||||||
|
* add interface for single- dual- multi-camera support
|
||||||
|
* same for grabbing from single or multiple devices
|
||||||
|
* support handling of multiple buffers in GUI (load, pessure)
|
||||||
|
* remove the old open, save etc. functions.
|
||||||
|
* improve dry run to not create panik by showing the buffer lad to go up
|
||||||
|
* support buffer progress for two cams/buffers
|
||||||
|
* add functionality to adjust the gain per camera (automatically?)
|
||||||
|
* cleanup setter function on dual and single camera wrappers...
|
||||||
|
* remove full name from SinglecamWrapper
|
||||||
@@ -21,7 +21,6 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
#if defined(QT_PRINTSUPPORT_LIB)
|
#if defined(QT_PRINTSUPPORT_LIB)
|
||||||
# include <QtPrintSupport/qtprintsupportglobal.h>
|
# include <QtPrintSupport/qtprintsupportglobal.h>
|
||||||
@@ -33,9 +32,12 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
PylonRecorder::PylonRecorder(QWidget *parent)
|
PylonRecorder::PylonRecorder(QWidget *parent)
|
||||||
: QMainWindow(parent), imageLabel(new QLabel), scrollArea(new QScrollArea), grabber(nullptr), writer(nullptr), buffer(nullptr), pyloncam(nullptr)
|
: QMainWindow(parent), imageLabel(new QLabel), scrollArea(new QScrollArea),
|
||||||
|
singlecamgrabber(nullptr), dualcamgrabber(nullptr),
|
||||||
|
writer(nullptr), buffer(nullptr),
|
||||||
|
singlecam(nullptr), dualcam(nullptr),
|
||||||
|
dryRun(false), cameraOpened(false), camsconfigured(false)
|
||||||
{
|
{
|
||||||
dryRun = false;
|
|
||||||
imageLabel->setBackgroundRole(QPalette::Base);
|
imageLabel->setBackgroundRole(QPalette::Base);
|
||||||
imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
||||||
imageLabel->setScaledContents(true);
|
imageLabel->setScaledContents(true);
|
||||||
@@ -44,40 +46,23 @@ PylonRecorder::PylonRecorder(QWidget *parent)
|
|||||||
scrollArea->setWidget(imageLabel);
|
scrollArea->setWidget(imageLabel);
|
||||||
scrollArea->setVisible(false);
|
scrollArea->setVisible(false);
|
||||||
setCentralWidget(scrollArea);
|
setCentralWidget(scrollArea);
|
||||||
// Pylon::DeviceInfoList_t deviceList = detectCameras();
|
|
||||||
// for (auto dev : deviceList) {
|
|
||||||
// std::cout << dev.GetFullName() << " " << dev.GetFriendlyName() << std::endl;
|
|
||||||
// }
|
|
||||||
// std::cout << "peng\n";
|
|
||||||
// std::cout << deviceList.size() << std::endl;
|
|
||||||
// std::cout << "peng\n";
|
|
||||||
|
|
||||||
// if (deviceList.size() == 0) {
|
|
||||||
// QErrorMessage message(this);
|
|
||||||
// message.showMessage("No camera detected!");
|
|
||||||
// } else {
|
|
||||||
// std::cout << "peng\n";
|
|
||||||
// buffer = new ImageBuffer(defaultBufferSize);
|
|
||||||
// grabber = new Grabber(pyloncam, buffer, defaultFrameRate);
|
|
||||||
// writer = new Writer(buffer);
|
|
||||||
// connect(writer, &Writer::writingDone, this, &PylonRecorder::writerDone);
|
|
||||||
// }
|
|
||||||
frameTimer = new QTimer(this);
|
frameTimer = new QTimer(this);
|
||||||
connect(frameTimer, &QTimer::timeout, this, &PylonRecorder::displaySingleFrame);
|
connect(frameTimer, &QTimer::timeout, this, &PylonRecorder::displaySingleFrame);
|
||||||
preassureTimer = new QTimer(this);
|
pressureTimer = new QTimer(this);
|
||||||
connect(preassureTimer, &QTimer::timeout, this, &PylonRecorder::displayBufferPressure);
|
connect(pressureTimer, &QTimer::timeout, this, &PylonRecorder::displayBufferPressure);
|
||||||
labelTimer = new QTimer(this);
|
labelTimer = new QTimer(this);
|
||||||
connect(labelTimer, &QTimer::timeout, this, &PylonRecorder::displayActivity);
|
connect(labelTimer, &QTimer::timeout, this, &PylonRecorder::displayActivity);
|
||||||
preassureBar = new QProgressBar(this);
|
pressureBar = new QProgressBar(this);
|
||||||
preassureBar->setRange(0, 100);
|
pressureBar->setRange(0, 100);
|
||||||
preassureBar->setTextVisible(true);
|
pressureBar->setTextVisible(true);
|
||||||
preassureBar->setFixedSize(200, 25);
|
pressureBar->setFixedSize(200, 25);
|
||||||
QColor color = progressColor(0);
|
QColor color = progressColor(0);
|
||||||
QPalette progressPalette = preassureBar->palette();
|
QPalette progressPalette = pressureBar->palette();
|
||||||
progressPalette.setBrush(QPalette::Highlight, QBrush(color));
|
progressPalette.setBrush(QPalette::Highlight, QBrush(color));
|
||||||
preassureBar->setPalette(progressPalette);
|
pressureBar->setPalette(progressPalette);
|
||||||
QLabel *preassureLabel = new QLabel("Buffer preassure:", this);
|
QLabel *pressureLabel = new QLabel("Buffer pressure:", this);
|
||||||
preassureLabel->setStyleSheet("QLabel{font-size: 11pt;font-family: Arial;font-weight: Bold}");
|
pressureLabel->setStyleSheet("QLabel{font-size: 11pt;font-family: Arial;font-weight: Bold}");
|
||||||
loadBar = new QProgressBar(this);
|
loadBar = new QProgressBar(this);
|
||||||
loadBar->setRange(0, defaultBufferSize);
|
loadBar->setRange(0, defaultBufferSize);
|
||||||
loadBar->setFixedSize(200, 25);
|
loadBar->setFixedSize(200, 25);
|
||||||
@@ -102,10 +87,11 @@ PylonRecorder::PylonRecorder(QWidget *parent)
|
|||||||
statusHeader->setStyleSheet("QLabel{font-size: 11pt;font-family: Arial; font-weight: Bold}");
|
statusHeader->setStyleSheet("QLabel{font-size: 11pt;font-family: Arial; font-weight: Bold}");
|
||||||
QLabel *fileHeader = new QLabel("Output file:");
|
QLabel *fileHeader = new QLabel("Output file:");
|
||||||
fileHeader->setStyleSheet("QLabel{font-size: 11pt;font-family: Arial; font-weight: Bold}");
|
fileHeader->setStyleSheet("QLabel{font-size: 11pt;font-family: Arial; font-weight: Bold}");
|
||||||
|
|
||||||
statusBar()->addWidget(camHeader);
|
statusBar()->addWidget(camHeader);
|
||||||
statusBar()->addWidget(cameraConnectedLabel);
|
statusBar()->addWidget(cameraConnectedLabel);
|
||||||
statusBar()->addWidget(preassureLabel);
|
statusBar()->addWidget(pressureLabel);
|
||||||
statusBar()->addWidget(preassureBar);
|
statusBar()->addWidget(pressureBar);
|
||||||
statusBar()->addWidget(loadLabel);
|
statusBar()->addWidget(loadLabel);
|
||||||
statusBar()->addWidget(loadBar);
|
statusBar()->addWidget(loadBar);
|
||||||
statusBar()->addWidget(statusHeader);
|
statusBar()->addWidget(statusHeader);
|
||||||
@@ -113,6 +99,7 @@ PylonRecorder::PylonRecorder(QWidget *parent)
|
|||||||
statusBar()->addWidget(writingLabel);
|
statusBar()->addWidget(writingLabel);
|
||||||
statusBar()->addWidget(fileHeader);
|
statusBar()->addWidget(fileHeader);
|
||||||
statusBar()->addWidget(fileLabel);
|
statusBar()->addWidget(fileLabel);
|
||||||
|
|
||||||
resize(QGuiApplication::primaryScreen()->availableSize() * 3 / 5);
|
resize(QGuiApplication::primaryScreen()->availableSize() * 3 / 5);
|
||||||
detectCameras();
|
detectCameras();
|
||||||
createActions();
|
createActions();
|
||||||
@@ -120,50 +107,33 @@ PylonRecorder::PylonRecorder(QWidget *parent)
|
|||||||
applySettings();
|
applySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PylonRecorder::setupCameras(){
|
|
||||||
for (auto dev : deviceList) {
|
|
||||||
std::cout << dev.GetFullName() << " " << dev.GetFriendlyName() << std::endl;
|
|
||||||
}
|
|
||||||
std::cout << "peng\n";
|
|
||||||
std::cout << deviceList.size() << std::endl;
|
|
||||||
std::cout << "peng\n";
|
|
||||||
|
|
||||||
if (deviceList.size() == 0) {
|
|
||||||
qWarning() << "device list is empty!";
|
|
||||||
QErrorMessage message(this);
|
|
||||||
message.showMessage("No camera detected!");
|
|
||||||
} else {
|
|
||||||
std::cout << "peng\n";
|
|
||||||
// std::string cname = (std::string)deviceList[0].GetFullName();
|
|
||||||
// pyloncam = new PylonWrapper(cname);
|
|
||||||
qDebug() << "Creating buffer, grabber, and writer";
|
|
||||||
buffer = new ImageBuffer(defaultBufferSize);
|
|
||||||
grabber = new Grabber(pyloncam, buffer, defaultFrameRate);
|
|
||||||
writer = new Writer(buffer);
|
|
||||||
connect(writer, &Writer::writingDone, this, &PylonRecorder::writerDone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PylonRecorder::detectCameras() {
|
void PylonRecorder::detectCameras() {
|
||||||
|
qDebug() << "Detecting devices!";
|
||||||
Pylon::CTlFactory& TlFactory = Pylon::CTlFactory::GetInstance();
|
Pylon::CTlFactory& TlFactory = Pylon::CTlFactory::GetInstance();
|
||||||
TlFactory.EnumerateDevices(deviceList);
|
TlFactory.EnumerateDevices(deviceList);
|
||||||
|
qDebug() << "Found devices!" << deviceList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
PylonRecorder::~PylonRecorder(){
|
PylonRecorder::~PylonRecorder(){
|
||||||
qDebug() << "Destructing PylonRecorder";
|
qDebug() << "Destructing PylonRecorder";
|
||||||
if (grabber != nullptr && grabber->isRunning()) {
|
if (singlecamgrabber != nullptr && singlecamgrabber->isRunning()) {
|
||||||
grabber->requestStop();
|
singlecamgrabber->requestStop();
|
||||||
grabber->wait(1000);
|
singlecamgrabber->wait(1000);
|
||||||
}
|
}
|
||||||
if (writer != nullptr && writer->isRunning()) {
|
if (writer != nullptr && writer->isRunning()) {
|
||||||
writer->forceStop();
|
writer->forceStop();
|
||||||
writer->wait(1000);
|
writer->wait(1000);
|
||||||
}
|
}
|
||||||
storeSettings();
|
storeSettings();
|
||||||
if (pyloncam != nullptr) {
|
if (singlecam != nullptr) {
|
||||||
qDebug() << "Deleting pyloncam";
|
qDebug() << "Deleting singlecam";
|
||||||
delete pyloncam;
|
delete singlecam;
|
||||||
pyloncam = nullptr;
|
singlecam = nullptr;
|
||||||
|
}
|
||||||
|
if (dualcam != nullptr) {
|
||||||
|
qDebug() << "Deleting dualcam";
|
||||||
|
delete dualcam;
|
||||||
|
dualcam = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer != nullptr) {
|
if (buffer != nullptr) {
|
||||||
@@ -171,10 +141,22 @@ PylonRecorder::~PylonRecorder(){
|
|||||||
delete buffer;
|
delete buffer;
|
||||||
buffer = nullptr;
|
buffer = nullptr;
|
||||||
}
|
}
|
||||||
qDebug() << "Deleting grabber";
|
|
||||||
delete grabber;
|
if (singlecamgrabber != nullptr) {
|
||||||
qDebug() << "Deleting writer";
|
qDebug() << "Deleting grabber";
|
||||||
delete writer;
|
delete singlecamgrabber;
|
||||||
|
singlecamgrabber = nullptr;
|
||||||
|
}
|
||||||
|
if (dualcamgrabber != nullptr) {
|
||||||
|
qDebug() << "Deleting grabber";
|
||||||
|
delete dualcamgrabber;
|
||||||
|
dualcamgrabber = nullptr;
|
||||||
|
}
|
||||||
|
if (writer != nullptr) {
|
||||||
|
qDebug() << "Deleting writer";
|
||||||
|
delete writer;
|
||||||
|
writer = nullptr;
|
||||||
|
}
|
||||||
qDebug() << "Deleting setting";
|
qDebug() << "Deleting setting";
|
||||||
delete settings;
|
delete settings;
|
||||||
}
|
}
|
||||||
@@ -197,6 +179,7 @@ void PylonRecorder::applySettings() {
|
|||||||
|
|
||||||
|
|
||||||
void PylonRecorder::storeSettings() {
|
void PylonRecorder::storeSettings() {
|
||||||
|
// FIXME store cam layout to settings
|
||||||
settings->setValue("camera/exposure", exposureSpinner->value());
|
settings->setValue("camera/exposure", exposureSpinner->value());
|
||||||
settings->setValue("camera/framerate", framerateSpinner->value());
|
settings->setValue("camera/framerate", framerateSpinner->value());
|
||||||
settings->setValue("camera/gain", gainSpinner->value());
|
settings->setValue("camera/gain", gainSpinner->value());
|
||||||
@@ -215,11 +198,8 @@ bool PylonRecorder::loadFile(const QString &fileName) {
|
|||||||
.arg(QDir::toNativeSeparators(fileName), reader.errorString()));
|
.arg(QDir::toNativeSeparators(fileName), reader.errorString()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
setImage(newImage);
|
setImage(newImage);
|
||||||
|
|
||||||
setWindowFilePath(fileName);
|
setWindowFilePath(fileName);
|
||||||
|
|
||||||
const QString message = tr("Opened \"%1\", %2x%3, Depth: %4")
|
const QString message = tr("Opened \"%1\", %2x%3, Depth: %4")
|
||||||
.arg(QDir::toNativeSeparators(fileName)).arg(image.width()).arg(image.height()).arg(image.depth());
|
.arg(QDir::toNativeSeparators(fileName)).arg(image.width()).arg(image.height()).arg(image.depth());
|
||||||
statusBar()->showMessage(message);
|
statusBar()->showMessage(message);
|
||||||
@@ -228,6 +208,8 @@ bool PylonRecorder::loadFile(const QString &fileName) {
|
|||||||
|
|
||||||
|
|
||||||
void PylonRecorder::setImage(const QImage &newImage) {
|
void PylonRecorder::setImage(const QImage &newImage) {
|
||||||
|
qDebug() << "Setting image";
|
||||||
|
//FIXME figure out how to display both images. extract to extra class...
|
||||||
image = newImage;
|
image = newImage;
|
||||||
// (image.colorSpace().isValid())
|
// (image.colorSpace().isValid())
|
||||||
// image.convertToColorSpace(QColorSpace::SRgb);
|
// image.convertToColorSpace(QColorSpace::SRgb);
|
||||||
@@ -237,12 +219,14 @@ void PylonRecorder::setImage(const QImage &newImage) {
|
|||||||
scrollArea->setVisible(true);
|
scrollArea->setVisible(true);
|
||||||
printAct->setEnabled(true);
|
printAct->setEnabled(true);
|
||||||
fitToWindowAct->setEnabled(true);
|
fitToWindowAct->setEnabled(true);
|
||||||
updateActions();
|
//updateActions();
|
||||||
|
|
||||||
if (!fitToWindowAct->isChecked()) {
|
if (!fitToWindowAct->isChecked()) {
|
||||||
imageLabel->adjustSize();
|
imageLabel->adjustSize();
|
||||||
applyScaling();
|
applyScaling();
|
||||||
}
|
}
|
||||||
|
this->update();
|
||||||
|
qDebug() << "Setting image done";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -300,8 +284,8 @@ void PylonRecorder::saveAs() {
|
|||||||
|
|
||||||
|
|
||||||
void PylonRecorder::print() {
|
void PylonRecorder::print() {
|
||||||
QPixmap map = imageLabel->pixmap(Qt::ReturnByValue);
|
const QPixmap *map = imageLabel->pixmap();
|
||||||
Q_ASSERT(!map.isNull());
|
Q_ASSERT(!map->isNull());
|
||||||
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog)
|
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog)
|
||||||
|
|
||||||
QPrintDialog dialog(&printer, this);
|
QPrintDialog dialog(&printer, this);
|
||||||
@@ -309,11 +293,11 @@ void PylonRecorder::print() {
|
|||||||
if (dialog.exec()) {
|
if (dialog.exec()) {
|
||||||
QPainter painter(&printer);
|
QPainter painter(&printer);
|
||||||
QRect rect = painter.viewport();
|
QRect rect = painter.viewport();
|
||||||
QSize size = map.size();
|
QSize size = map->size();
|
||||||
size.scale(rect.size(), Qt::KeepAspectRatio);
|
size.scale(rect.size(), Qt::KeepAspectRatio);
|
||||||
painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
|
painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
|
||||||
painter.setWindow(map.rect());
|
painter.setWindow(map->rect());
|
||||||
painter.drawPixmap(0, 0, map);
|
painter.drawPixmap(0, 0, *map);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -454,6 +438,7 @@ void PylonRecorder::createActions() {
|
|||||||
connect_camera_action->setStatusTip(tr("Connect to to camera and open device"));
|
connect_camera_action->setStatusTip(tr("Connect to to camera and open device"));
|
||||||
disconnect_camera_action = camera_menu->addAction(disconnect_icon, tr("&disconnect"), this, &PylonRecorder::disconnectCamera);
|
disconnect_camera_action = camera_menu->addAction(disconnect_icon, tr("&disconnect"), this, &PylonRecorder::disconnectCamera);
|
||||||
disconnect_camera_action->setStatusTip(tr("Disconnect from the camera device"));
|
disconnect_camera_action->setStatusTip(tr("Disconnect from the camera device"));
|
||||||
|
disconnect_camera_action->setEnabled(false);
|
||||||
camera_menu->addSeparator();
|
camera_menu->addSeparator();
|
||||||
grab_still_action = camera_menu->addAction(snapshot_icon, tr("&grab still"), this, &PylonRecorder::grabStillFromPylon);
|
grab_still_action = camera_menu->addAction(snapshot_icon, tr("&grab still"), this, &PylonRecorder::grabStillFromPylon);
|
||||||
grab_still_action->setStatusTip(tr("Grab single image from Pylon camera"));
|
grab_still_action->setStatusTip(tr("Grab single image from Pylon camera"));
|
||||||
@@ -462,6 +447,9 @@ void PylonRecorder::createActions() {
|
|||||||
grab_continuous_action->setShortcut(tr("Ctrl+Enter"));
|
grab_continuous_action->setShortcut(tr("Ctrl+Enter"));
|
||||||
grab_stop_action = camera_menu->addAction(stop_icon, tr("&stop grabbing"), this, &PylonRecorder::stopRecording);
|
grab_stop_action = camera_menu->addAction(stop_icon, tr("&stop grabbing"), this, &PylonRecorder::stopRecording);
|
||||||
grab_stop_action->setShortcut(tr("Ctrl+Shift+Enter"));
|
grab_stop_action->setShortcut(tr("Ctrl+Shift+Enter"));
|
||||||
|
set_cam_identifier_action = camera_menu->addAction(tr("set identifier"), this, &PylonRecorder::setCameraIDs);
|
||||||
|
set_cam_identifier_action->setStatusTip(tr("Set human readable camera identifier or easier recognition."));
|
||||||
|
set_cam_identifier_action->setToolTip(tr("Set human readable camera identifier or easier recognition."));
|
||||||
|
|
||||||
selectStorageAction = new QAction(tr("storage location"), this);
|
selectStorageAction = new QAction(tr("storage location"), this);
|
||||||
selectStorageAction->setStatusTip(tr("Select a storage location for the recorded videos"));
|
selectStorageAction->setStatusTip(tr("Select a storage location for the recorded videos"));
|
||||||
@@ -554,19 +542,42 @@ void PylonRecorder::updateActions() {
|
|||||||
zoomInAct->setEnabled(!fitToWindowAct->isChecked());
|
zoomInAct->setEnabled(!fitToWindowAct->isChecked());
|
||||||
zoomOutAct->setEnabled(!fitToWindowAct->isChecked());
|
zoomOutAct->setEnabled(!fitToWindowAct->isChecked());
|
||||||
normalSizeAct->setEnabled(!fitToWindowAct->isChecked());
|
normalSizeAct->setEnabled(!fitToWindowAct->isChecked());
|
||||||
disconnect_camera_action->setEnabled(deviceList.size() > 0);
|
disconnect_camera_action->setEnabled(cameraOpened);
|
||||||
connect_camera_action->setEnabled(true);
|
connect_camera_action->setEnabled(true);
|
||||||
grab_still_action->setEnabled(deviceList.size() > 0);
|
grab_still_action->setEnabled(cameraOpened);
|
||||||
//grab_continuous_action->setEnabled(deviceList.size() > 0 && pyloncam->isOpen() && !grabbing);
|
grab_continuous_action->setEnabled(cameraOpened && !grabbing);
|
||||||
grab_stop_action->setEnabled(grabbing);
|
grab_stop_action->setEnabled(grabbing);
|
||||||
|
set_cam_identifier_action->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PylonRecorder::setCameraIDs() {
|
||||||
|
if (deviceList.size() == 0) {
|
||||||
|
QMessageBox msgBox;
|
||||||
|
QString msg = "<p><b>No camera device found!</b></p><br><p>Connect camera and try again!</p>";
|
||||||
|
msgBox.setText(msg);
|
||||||
|
msgBox.exec();
|
||||||
|
qWarning() << msg.toStdString().c_str();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cameraIdDialog = new CameraID(deviceList, this);
|
||||||
|
connect(cameraConfigDialog, SIGNAL(accepted()), SLOT(cameraIDAccepted()));
|
||||||
|
std::cerr <<"ping\n";
|
||||||
|
cameraIdDialog->exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PylonRecorder::cameraIDAccepted() {
|
||||||
|
QString newid = cameraIdDialog->newID();
|
||||||
|
int deviceindex = cameraIdDialog->cameraIndex();
|
||||||
|
std::cerr << "New camera id " << newid.toStdString() << " index: " << deviceindex << std::endl;
|
||||||
|
delete(cameraIdDialog);
|
||||||
|
}
|
||||||
|
|
||||||
void PylonRecorder::scaleImage(double factor) {
|
void PylonRecorder::scaleImage(double factor) {
|
||||||
QPixmap map = imageLabel->pixmap(Qt::ReturnByValue);
|
const QPixmap *map = imageLabel->pixmap();
|
||||||
Q_ASSERT(!map.isNull());
|
Q_ASSERT(!map->isNull());
|
||||||
scaleFactor *= factor;
|
scaleFactor *= factor;
|
||||||
imageLabel->resize(scaleFactor * map.size());
|
imageLabel->resize(scaleFactor * map->size());
|
||||||
|
|
||||||
adjustScrollBar(scrollArea->horizontalScrollBar(), factor);
|
adjustScrollBar(scrollArea->horizontalScrollBar(), factor);
|
||||||
adjustScrollBar(scrollArea->verticalScrollBar(), factor);
|
adjustScrollBar(scrollArea->verticalScrollBar(), factor);
|
||||||
@@ -577,19 +588,20 @@ void PylonRecorder::scaleImage(double factor) {
|
|||||||
|
|
||||||
|
|
||||||
void PylonRecorder::applyScaling(){
|
void PylonRecorder::applyScaling(){
|
||||||
imageLabel->resize(scaleFactor * imageLabel->pixmap(Qt::ReturnByValue).size());
|
imageLabel->resize(scaleFactor * imageLabel->pixmap()->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PylonRecorder::quitApplication() {
|
void PylonRecorder::quitApplication() {
|
||||||
qDebug() << "Quit Application!";
|
qDebug() << "QuitApplication: Quit Application!";
|
||||||
|
|
||||||
if (grabbing) {
|
if (grabbing) {
|
||||||
|
std::cerr << "QuitApplication: Stop grabbing\n";
|
||||||
qDebug() << "QuitApplication: Stop grabbing";
|
qDebug() << "QuitApplication: Stop grabbing";
|
||||||
stopRecording();
|
stopRecording();
|
||||||
}
|
}
|
||||||
qDebug() << "QuitApplication done!";
|
qDebug() << "QuitApplication done!";
|
||||||
this->close();
|
this->close();
|
||||||
|
std::cerr << "QuitApplication: done,\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -598,89 +610,187 @@ void PylonRecorder::adjustScrollBar(QScrollBar *scrollBar, double factor) {
|
|||||||
+ ((factor - 1) * scrollBar->pageStep()/2)));
|
+ ((factor - 1) * scrollBar->pageStep()/2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PylonRecorder::cameraConfiguration(){
|
void PylonRecorder::cameraConfiguration(){
|
||||||
d = new CamConfigurator(deviceList, this);
|
qDebug() << "Configuring camera(s)";
|
||||||
connect(d, SIGNAL(accepted()), SLOT(camerasetup()));
|
cameraConfigDialog = new CamConfigurator(deviceList, this);
|
||||||
// QObject::connect(&d, SIGNAL(column_visibility_changed(QString, QString,bool)), this, SLOT(visible_columns_update(QString, QString,bool)));
|
connect(cameraConfigDialog, SIGNAL(accepted()), SLOT(cameraConfigurationAccepted()));
|
||||||
d->exec();
|
connect(cameraConfigDialog, SIGNAL(rejected()), SLOT(cameraConfigurationAborted()));
|
||||||
|
// QObject::connect(&d, SIGNAL(column_visibility_changed(QString, QString,bool)), this, SLOT(visible_columns_update(QString, QString,bool)));
|
||||||
|
cameraConfigDialog->exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PylonRecorder::camerasetup() {
|
|
||||||
std::cerr << "camera settings accepted" << std::endl;
|
|
||||||
std::cerr << d->result() << std::endl;
|
|
||||||
std::cerr << "camera settings accepted" << std::endl;
|
|
||||||
CameraLayout l = d->layout();
|
|
||||||
std::cerr << l.rois.size() << l.devices.size() << std::endl;
|
|
||||||
std::cerr << "camera settings accepted" << std::endl;
|
|
||||||
|
|
||||||
delete d;
|
void PylonRecorder::cameraConfigurationAccepted() {
|
||||||
|
qDebug() << "Camera configuration " << ((cameraConfigDialog->result()) ? "Accepted" : "Discarded");
|
||||||
|
this->layout = cameraConfigDialog->layout();
|
||||||
|
camsconfigured = true;
|
||||||
|
delete cameraConfigDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PylonRecorder::cameraConfigurationAborted() {
|
||||||
|
qDebug() << "Camera configuration aborted!";
|
||||||
|
camsconfigured = false;
|
||||||
|
delete cameraConfigDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PylonRecorder::connectCamera() {
|
void PylonRecorder::connectCamera() {
|
||||||
|
qDebug() << "connecting camera(s)";
|
||||||
|
this->layout = CameraLayout();
|
||||||
if (deviceList.size() == 0) {
|
if (deviceList.size() == 0) {
|
||||||
detectCameras();
|
detectCameras();
|
||||||
QMessageBox msgBox;
|
QMessageBox msgBox;
|
||||||
QString msg = "<p><b>No camera device found!</b></p><br><p>Connect camera and try again!</p>";
|
QString msg = "<p><b>No camera device found!</b></p><br><p>Connect camera and try again!</p>";
|
||||||
msgBox.setText(msg);
|
msgBox.setText(msg);
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
} else {
|
qWarning() << msg.toStdString().c_str();
|
||||||
// std::string cname = (std::string)deviceList[0].GetFullName();
|
return;
|
||||||
// pyloncam = new PylonWrapper(cname);
|
|
||||||
// std::string message;
|
|
||||||
// bool success = pyloncam->openCamera(message);
|
|
||||||
// if (success) {
|
|
||||||
// cameraConnectedLabel->setText("connected");
|
|
||||||
// cameraConnectedLabel->setStyleSheet("QLabel { font-size: 10px;font-family: Arial;color: green;}");
|
|
||||||
// } else {
|
|
||||||
// QMessageBox msgBox;
|
|
||||||
// QString msg = "<p><b>Could not open camera device!</b><p><p>" + QString::fromStdString(message) + "</p>";
|
|
||||||
// msgBox.setText(msg);
|
|
||||||
// msgBox.exec();
|
|
||||||
// }
|
|
||||||
// statusBar()->showMessage(QString::fromStdString(message));
|
|
||||||
// updateActions();
|
|
||||||
cameraConfiguration();
|
|
||||||
}
|
}
|
||||||
|
cameraConfiguration();
|
||||||
|
if (!camsconfigured) {
|
||||||
|
qDebug() << "cameras have not been properly configured!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Single Camera mode
|
||||||
|
if (layout.mode == CameraMode::single && layout.devices.size() == 1) {
|
||||||
|
qDebug() << "single camera mode";
|
||||||
|
std::string cname = layout.devices[0];
|
||||||
|
std::string message;
|
||||||
|
qDebug() << "connecting to camera " << cname.c_str();
|
||||||
|
singlecam = new PylonWrapper(layout);
|
||||||
|
bool success = singlecam->openCamera(message);
|
||||||
|
if (success) {
|
||||||
|
cameraConnectedLabel->setText("connected");
|
||||||
|
cameraConnectedLabel->setStyleSheet("QLabel { font-size: 10px;font-family: Arial;color: green;}");
|
||||||
|
cameraOpened = true;
|
||||||
|
} else {
|
||||||
|
QMessageBox msgBox;
|
||||||
|
QString msg = "<p><b>Could not open camera device!</b><p><p>" + QString::fromStdString(message) + "</p>";
|
||||||
|
msgBox.setText(msg);
|
||||||
|
msgBox.exec();
|
||||||
|
cameraOpened = false;
|
||||||
|
}
|
||||||
|
statusBar()->showMessage(QString::fromStdString(message));
|
||||||
|
updateActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dual Camera mode
|
||||||
|
if (layout.mode == CameraMode::dual && layout.devices.size() == 2) {
|
||||||
|
qDebug() << "dual camera mode";
|
||||||
|
std::string message;
|
||||||
|
dualcam = new DualcamWrapper(layout);
|
||||||
|
bool success = dualcam->openCameras(message);
|
||||||
|
if (success) {
|
||||||
|
qDebug() << "Dual cameras connected";
|
||||||
|
cameraConnectedLabel->setText("connected");
|
||||||
|
cameraConnectedLabel->setStyleSheet("QLabel { font-size: 10px;font-family: Arial;color: green;}");
|
||||||
|
cameraOpened = true;
|
||||||
|
} else {
|
||||||
|
QMessageBox msgBox;
|
||||||
|
QString msg = "<p><b>Could not open camera device!</b><p><p>" + QString::fromStdString(message) + "</p>";
|
||||||
|
msgBox.setText(msg);
|
||||||
|
msgBox.exec();
|
||||||
|
cameraOpened = false;
|
||||||
|
}
|
||||||
|
statusBar()->showMessage(QString::fromStdString(message));
|
||||||
|
updateActions();
|
||||||
|
}
|
||||||
|
qDebug() << "connecting cam(s) done!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PylonRecorder::disconnectCamera() {
|
void PylonRecorder::disconnectCamera() {
|
||||||
if (pyloncam->isOpen()) {
|
qDebug() << "disconnecting camera";
|
||||||
pyloncam->closeCamera();
|
if (singlecam != nullptr && singlecam->isOpen()) {
|
||||||
statusBar()->showMessage(tr("Camera closed!"));
|
singlecam->closeCamera();
|
||||||
cameraConnectedLabel->setText("not connected");
|
|
||||||
cameraConnectedLabel->setStyleSheet("QLabel { font-size: 10px;font-family: Arial;color: red;}");
|
|
||||||
updateActions();
|
|
||||||
}
|
}
|
||||||
|
if (dualcam != nullptr && dualcam->isOpen()) {
|
||||||
|
dualcam->closeCameras();
|
||||||
|
}
|
||||||
|
statusBar()->showMessage(tr("Camera closed!"));
|
||||||
|
cameraConnectedLabel->setText("not connected");
|
||||||
|
cameraConnectedLabel->setStyleSheet("QLabel { font-size: 10px;font-family: Arial;color: red;}");
|
||||||
|
updateActions();
|
||||||
|
camsconfigured = false;
|
||||||
|
cameraOpened = false;
|
||||||
|
qDebug() << "disconnecting cameras done";
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoSpecs PylonRecorder::getVideoSpecs(const ImageSettings &settings) {
|
||||||
|
VideoSpecs s = VideoSpecs();
|
||||||
|
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);
|
||||||
|
} 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PylonRecorder::startRecording() {
|
void PylonRecorder::startSinglecamRecording() {
|
||||||
std::string filename = createFilename();
|
qDebug() << "start single-camera recording!";
|
||||||
|
std::string filename = createFilename("", ".mp4");
|
||||||
fileLabel->setText(QString::fromStdString(filename));
|
fileLabel->setText(QString::fromStdString(filename));
|
||||||
ImageSettings settings = pyloncam->getImageSettings();
|
qDebug() << "storing to file " << filename.c_str();
|
||||||
|
|
||||||
VideoSpecs specs;
|
ImageSettings settings = singlecam->getImageSettings();
|
||||||
specs.fps = framerateSpinner->value();
|
qDebug() << "got image settings";
|
||||||
|
|
||||||
|
VideoSpecs specs = getVideoSpecs(settings);
|
||||||
specs.filename = filename;
|
specs.filename = filename;
|
||||||
specs.exposureTime = static_cast<double>(exposureSpinner->value());
|
specs.format = VideoFormat::mp4;
|
||||||
specs.detectorGain = static_cast<double>(gainSpinner->value());
|
qDebug() << "got video specifications";
|
||||||
specs.width = static_cast<uint32_t>(settings.width);
|
|
||||||
specs.height= static_cast<uint32_t>(settings.height);
|
if (buffer != nullptr) {
|
||||||
specs.pixelType = settings.pixelType;
|
buffer->clear();
|
||||||
specs.orientation = settings.orientation;
|
delete buffer;
|
||||||
specs.quality = 95;
|
buffer = nullptr;
|
||||||
|
}
|
||||||
|
qDebug() << "setting image buffer to size " << buffersizeSpinner->value();
|
||||||
|
buffer = new ImageBuffer(defaultBufferSize);
|
||||||
if (buffersizeSpinner->value() != static_cast<int>(buffer->capacity())) {
|
if (buffersizeSpinner->value() != static_cast<int>(buffer->capacity())) {
|
||||||
buffer->resize(static_cast<size_t>(buffersizeSpinner->value()));
|
buffer->resize(static_cast<size_t>(buffersizeSpinner->value()));
|
||||||
loadBar->setRange(0, buffersizeSpinner->value());
|
loadBar->setRange(0, buffersizeSpinner->value());
|
||||||
}
|
}
|
||||||
if (framerateSpinner->value() != grabber->currentFramerate())
|
|
||||||
grabber->setFrameRate(framerateSpinner->value());
|
qDebug() << "setting up grabber";
|
||||||
if (exposureSpinner->value() != int(grabber->currentExposureTime()))
|
if (singlecamgrabber != nullptr) {
|
||||||
grabber->setExposureTime(static_cast<double>(exposureSpinner->value()));
|
delete singlecamgrabber;
|
||||||
if (gainSpinner->value() != int(grabber->currentGain()))
|
singlecamgrabber = nullptr;
|
||||||
grabber->setGain(static_cast<double>(gainSpinner->value()));
|
}
|
||||||
|
singlecamgrabber = new Grabber(singlecam, buffer, defaultFrameRate);
|
||||||
|
|
||||||
|
if (framerateSpinner->value() != singlecamgrabber->currentFramerate())
|
||||||
|
singlecamgrabber->setFrameRate(framerateSpinner->value());
|
||||||
|
if (exposureSpinner->value() != int(singlecamgrabber->currentExposureTime()))
|
||||||
|
singlecamgrabber->setExposureTime(static_cast<double>(exposureSpinner->value()));
|
||||||
|
if (gainSpinner->value() != int(singlecamgrabber->currentGain()))
|
||||||
|
singlecamgrabber->setGain(static_cast<double>(gainSpinner->value()));
|
||||||
|
|
||||||
|
qDebug() << "setup writer";
|
||||||
|
if (writer != nullptr) {
|
||||||
|
delete writer;
|
||||||
|
writer = nullptr;
|
||||||
|
}
|
||||||
|
writer = new Writer(buffer);
|
||||||
|
connect(writer, SIGNAL(writingDone()), this, SLOT(writerDone()));
|
||||||
writer->setVideoSpecs(specs);
|
writer->setVideoSpecs(specs);
|
||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
this->mdata.read(s);
|
this->mdata.read(s);
|
||||||
writer->setProjectMetadata(mdata);
|
writer->setProjectMetadata(mdata);
|
||||||
@@ -691,12 +801,88 @@ void PylonRecorder::startRecording() {
|
|||||||
writing = true;
|
writing = true;
|
||||||
}
|
}
|
||||||
dryRun = dryRunCheckBox->isChecked();
|
dryRun = dryRunCheckBox->isChecked();
|
||||||
grabber->start();
|
singlecamgrabber->start();
|
||||||
|
grabbing = true;
|
||||||
|
stopRequest = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PylonRecorder::startDualcamRecording() {
|
||||||
|
qDebug() << "start dual-camera recording!";
|
||||||
|
std::string filename = createFilename("", ".mp4");
|
||||||
|
fileLabel->setText(QString::fromStdString(filename));
|
||||||
|
qDebug() << "storing to file " << filename.c_str();
|
||||||
|
|
||||||
|
ImageSettings settings = dualcam->getImageSettings(0); //FIXME!
|
||||||
|
qDebug() << "got image settings";
|
||||||
|
VideoSpecs specs = getVideoSpecs(settings);
|
||||||
|
specs.filename = filename;
|
||||||
|
specs.format = VideoFormat::mp4;
|
||||||
|
qDebug() << "got video specifications " << specs.fps;
|
||||||
|
if (buffer != nullptr) {
|
||||||
|
buffer->clear();
|
||||||
|
delete buffer;
|
||||||
|
buffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "setting image buffer to size " << buffersizeSpinner->value();
|
||||||
|
buffer = new ImageBuffer(defaultBufferSize);
|
||||||
|
if (buffersizeSpinner->value() != static_cast<int>(buffer->capacity())) {
|
||||||
|
buffer->resize(static_cast<size_t>(buffersizeSpinner->value()));
|
||||||
|
loadBar->setRange(0, buffersizeSpinner->value());
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "setting up grabber";
|
||||||
|
if (dualcamgrabber != nullptr) {
|
||||||
|
delete dualcamgrabber;
|
||||||
|
dualcamgrabber = nullptr;
|
||||||
|
}
|
||||||
|
dualcamgrabber = new DualcamGrabber(dualcam, buffer, defaultFrameRate);
|
||||||
|
if (framerateSpinner->value() != dualcamgrabber->currentFramerate())
|
||||||
|
dualcamgrabber->setFrameRate(framerateSpinner->value());
|
||||||
|
if (exposureSpinner->value() != int(dualcamgrabber->currentExposureTime()))
|
||||||
|
dualcamgrabber->setExposureTime(static_cast<double>(exposureSpinner->value()));
|
||||||
|
if (gainSpinner->value() != int(dualcamgrabber->currentGain()))
|
||||||
|
dualcamgrabber->setGain(static_cast<double>(gainSpinner->value()));
|
||||||
|
|
||||||
|
qDebug() << "setting up writers";
|
||||||
|
if (writer != nullptr) {
|
||||||
|
delete writer;
|
||||||
|
writer = nullptr;
|
||||||
|
}
|
||||||
|
writer = new Writer(buffer);
|
||||||
|
connect(writer, SIGNAL(writingDone()), this, SLOT(writerDone()));
|
||||||
|
writer->setVideoSpecs(specs);
|
||||||
|
|
||||||
|
// qDebug() << "push metadata to writer";
|
||||||
|
// QSettings s;
|
||||||
|
// this->mdata.read(s);
|
||||||
|
// writer->setProjectMetadata(mdata);
|
||||||
|
|
||||||
|
dryRun = dryRunCheckBox->isChecked();
|
||||||
|
buffer->clear();
|
||||||
|
if (!dryRun) {
|
||||||
|
writer->start();
|
||||||
|
writing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dualcamgrabber->start();
|
||||||
grabbing = true;
|
grabbing = true;
|
||||||
stopRequest = false;
|
stopRequest = false;
|
||||||
|
}
|
||||||
|
|
||||||
preassureTimer->start(50);
|
|
||||||
frameTimer->start(50);
|
void PylonRecorder::startRecording() {
|
||||||
|
if (layout.mode == CameraMode::single) {
|
||||||
|
startSinglecamRecording();
|
||||||
|
} else if (layout.mode == CameraMode::dual){
|
||||||
|
startDualcamRecording();
|
||||||
|
} else {
|
||||||
|
qDebug() << "invalid camera mode!";
|
||||||
|
}
|
||||||
|
|
||||||
|
pressureTimer->start(50);
|
||||||
|
frameTimer->start(100);
|
||||||
labelTimer->start(650);
|
labelTimer->start(650);
|
||||||
updateActions();
|
updateActions();
|
||||||
}
|
}
|
||||||
@@ -708,8 +894,11 @@ void PylonRecorder::stopRecording() {
|
|||||||
qDebug() << "StopRecording: stop frame timer!";
|
qDebug() << "StopRecording: stop frame timer!";
|
||||||
frameTimer->stop();
|
frameTimer->stop();
|
||||||
qDebug() << "StopRecording: stop grabber!";
|
qDebug() << "StopRecording: stop grabber!";
|
||||||
if (grabber !=nullptr)
|
if (singlecamgrabber !=nullptr)
|
||||||
grabber->requestStop();
|
singlecamgrabber->requestStop();
|
||||||
|
if (dualcamgrabber !=nullptr)
|
||||||
|
dualcamgrabber->requestStop();
|
||||||
|
|
||||||
qDebug() << "StopRecording: stop writer!";
|
qDebug() << "StopRecording: stop writer!";
|
||||||
if (writer != nullptr)
|
if (writer != nullptr)
|
||||||
writer->requestStop();
|
writer->requestStop();
|
||||||
@@ -717,9 +906,8 @@ void PylonRecorder::stopRecording() {
|
|||||||
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 (dryRun){
|
||||||
buffer->clear();
|
writerDone();
|
||||||
writerDone();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qDebug() << "StopRecording done!";
|
qDebug() << "StopRecording done!";
|
||||||
@@ -727,16 +915,25 @@ void PylonRecorder::stopRecording() {
|
|||||||
|
|
||||||
|
|
||||||
void PylonRecorder::writerDone() {
|
void PylonRecorder::writerDone() {
|
||||||
preassureTimer->stop();
|
pressureTimer->stop();
|
||||||
preassureBar->reset();
|
pressureBar->reset();
|
||||||
loadBar->reset();
|
loadBar->reset();
|
||||||
labelTimer->stop();
|
labelTimer->stop();
|
||||||
writingLabel->setStyleSheet(inactiveLabelStyle);
|
writingLabel->setStyleSheet(inactiveLabelStyle);
|
||||||
grabbingLabel->setStyleSheet(inactiveLabelStyle);
|
grabbingLabel->setStyleSheet(inactiveLabelStyle);
|
||||||
grabber->wait(10000);
|
if (layout.mode == CameraMode::single) {
|
||||||
writer->wait(10000);
|
singlecamgrabber->wait(10000);
|
||||||
|
} else {
|
||||||
|
dualcamgrabber->wait(10000);
|
||||||
|
}
|
||||||
|
if (writer != nullptr)
|
||||||
|
writer->wait(10000);
|
||||||
|
if(buffer != nullptr) {
|
||||||
|
buffer->clear();
|
||||||
|
}
|
||||||
writing = false;
|
writing = false;
|
||||||
updateActions();
|
updateActions();
|
||||||
|
|
||||||
qInfo() << "writer is Done!";
|
qInfo() << "writer is Done!";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -749,14 +946,16 @@ void PylonRecorder::displayActivity() {
|
|||||||
|
|
||||||
|
|
||||||
void PylonRecorder::displaySingleFrame() {
|
void PylonRecorder::displaySingleFrame() {
|
||||||
MyImage *img = buffer->readLast();
|
qDebug() << "display single frame";
|
||||||
if (img != nullptr){
|
MyImage *img;
|
||||||
QImage qimg(static_cast<uchar *>(img->data()), img->width(), img->height(),
|
size_t fc = 0;
|
||||||
QImage::Format::Format_Grayscale8);
|
img = buffer->readLast(fc);
|
||||||
setImage(qimg);
|
if (img != nullptr){
|
||||||
}/* else {
|
QImage qimg(static_cast<uchar *>(img->data()), img->width(), img->height(), QImage::Format::Format_Grayscale8);
|
||||||
std::cerr << "Error reading last image" << std::endl;
|
setImage(qimg);
|
||||||
}*/
|
}else {
|
||||||
|
qDebug() << "Error reading last image";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -772,13 +971,12 @@ QColor PylonRecorder::progressColor(int value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string PylonRecorder::createFilename() {
|
std::string PylonRecorder::createFilename(const std::string &suffix, const std::string &extension) {
|
||||||
QDateTime dt(QDateTime::currentDateTimeUtc());
|
QDateTime dt(QDateTime::currentDateTimeUtc());
|
||||||
QDate date = dt.date();
|
QDate date = dt.date();
|
||||||
std::string base = (date.toString("yyyy.MM.dd") + "_").toStdString();
|
std::string base = (date.toString("yyyy.MM.dd") + "_").toStdString();
|
||||||
std::string extension = ".raw";
|
|
||||||
QString idx = QString::number(movieCount);
|
QString idx = QString::number(movieCount);
|
||||||
std::string fname = base + idx.toStdString() + extension;
|
std::string fname = base + idx.toStdString() + suffix + extension;
|
||||||
while (QFile::exists(QString::fromStdString(fname))) {
|
while (QFile::exists(QString::fromStdString(fname))) {
|
||||||
movieCount++;
|
movieCount++;
|
||||||
fname = base + QString::number(movieCount).toStdString() + extension;
|
fname = base + QString::number(movieCount).toStdString() + extension;
|
||||||
@@ -788,11 +986,11 @@ std::string PylonRecorder::createFilename() {
|
|||||||
|
|
||||||
|
|
||||||
void PylonRecorder::displayBufferPressure() {
|
void PylonRecorder::displayBufferPressure() {
|
||||||
int value = static_cast<int>(round(buffer->bufferPreassure()));
|
int value = static_cast<int>(round(buffer->bufferPressure()));
|
||||||
preassureBar->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));
|
||||||
preassureBar->setPalette(progressPalette);
|
pressureBar->setPalette(progressPalette);
|
||||||
|
|
||||||
int load = static_cast<int>(buffer->bufferLoad());
|
int load = static_cast<int>(buffer->bufferLoad());
|
||||||
loadBar->setValue(load);
|
loadBar->setValue(load);
|
||||||
@@ -800,9 +998,11 @@ void PylonRecorder::displayBufferPressure() {
|
|||||||
|
|
||||||
|
|
||||||
void PylonRecorder::grabStillFromPylon() {
|
void PylonRecorder::grabStillFromPylon() {
|
||||||
if (pyloncam->isOpen()) {
|
qDebug() << "Grab still image form camera!";
|
||||||
MyImage img;
|
if (singlecam != nullptr && singlecam->isOpen()) {
|
||||||
bool valid = pyloncam->grabFrame(img);
|
ImageSettings s = singlecam->getImageSettings();
|
||||||
|
MyImage img(s.width, s.height);
|
||||||
|
bool valid = singlecam->grabFrame(img);
|
||||||
if (valid) {
|
if (valid) {
|
||||||
QImage qimg(static_cast<uchar *>(img.data()), img.width(), img.height(),
|
QImage qimg(static_cast<uchar *>(img.data()), img.width(), img.height(),
|
||||||
QImage::Format::Format_Grayscale8);
|
QImage::Format::Format_Grayscale8);
|
||||||
@@ -811,6 +1011,8 @@ void PylonRecorder::grabStillFromPylon() {
|
|||||||
} else {
|
} else {
|
||||||
statusBar()->showMessage(tr("Camera is not open! Connect to camera first!"));
|
statusBar()->showMessage(tr("Camera is not open! Connect to camera first!"));
|
||||||
}
|
}
|
||||||
|
//FIXME does not work for stereo camera mode!
|
||||||
|
qDebug() << "grabbing still image done!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,11 +8,15 @@
|
|||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <pylon/PylonIncludes.h>
|
#include <pylon/PylonIncludes.h>
|
||||||
#include "pylonwrapper.h"
|
#include "pylonwrapper.h"
|
||||||
|
#include "dualcamwrapper.h"
|
||||||
#include "imagebuffer.h"
|
#include "imagebuffer.h"
|
||||||
#include "grabber.h"
|
#include "grabber.h"
|
||||||
|
#include "dualcamgrabber.h"
|
||||||
#include "writer.h"
|
#include "writer.h"
|
||||||
#include "projectsettings.h"
|
#include "projectsettings.h"
|
||||||
#include "camconfig.h"
|
#include "camconfig.h"
|
||||||
|
#include "camids.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#if defined(QT_PRINTSUPPORT_LIB)
|
#if defined(QT_PRINTSUPPORT_LIB)
|
||||||
@@ -65,7 +69,10 @@ private slots:
|
|||||||
void displayActivity();
|
void displayActivity();
|
||||||
void writerDone();
|
void writerDone();
|
||||||
void selectStorageLocation();
|
void selectStorageLocation();
|
||||||
void camerasetup();
|
void cameraConfigurationAccepted();
|
||||||
|
void cameraConfigurationAborted();
|
||||||
|
void setCameraIDs();
|
||||||
|
void cameraIDAccepted();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createActions();
|
void createActions();
|
||||||
@@ -77,31 +84,35 @@ private:
|
|||||||
void setExperimenterName();
|
void setExperimenterName();
|
||||||
void setSubjectID();
|
void setSubjectID();
|
||||||
QColor progressColor(int value);
|
QColor progressColor(int value);
|
||||||
std::string createFilename();
|
std::string createFilename(const std::string &suffix="", const std::string &extension=".raw");
|
||||||
void cameraConfiguration();
|
void cameraConfiguration();
|
||||||
|
VideoSpecs getVideoSpecs(const ImageSettings &settings);
|
||||||
|
void startSinglecamRecording();
|
||||||
|
void startDualcamRecording();
|
||||||
bool saveFile(const QString &fileName);
|
bool saveFile(const QString &fileName);
|
||||||
void setImage(const QImage &newImage);
|
void setImage(const QImage &newImage);
|
||||||
void scaleImage(double factor);
|
void scaleImage(double factor);
|
||||||
void applyScaling();
|
void applyScaling();
|
||||||
void adjustScrollBar(QScrollBar *scrollBar, double factor);
|
void adjustScrollBar(QScrollBar *scrollBar, double factor);
|
||||||
void detectCameras();
|
void detectCameras();
|
||||||
void setupCameras();
|
|
||||||
int defaultBufferSize = 3000, defaultFrameRate = 30, movieCount = 0, defaultExposureTime = 6000, defaultGain=13;
|
int defaultBufferSize = 3000, defaultFrameRate = 30, movieCount = 0, defaultExposureTime = 6000, defaultGain=13;
|
||||||
QSettings *settings = new QSettings;
|
QSettings *settings = new QSettings;
|
||||||
QImage image;
|
QImage image;
|
||||||
QTimer *frameTimer, *preassureTimer, *labelTimer;
|
QTimer *frameTimer, *pressureTimer, *labelTimer;
|
||||||
QLabel *imageLabel, *writingLabel, *grabbingLabel, *cameraConnectedLabel, *fileLabel;
|
QLabel *imageLabel, *writingLabel, *grabbingLabel, *cameraConnectedLabel, *fileLabel;
|
||||||
QCheckBox *dryRunCheckBox;
|
QCheckBox *dryRunCheckBox;
|
||||||
QProgressBar *preassureBar;
|
QProgressBar *pressureBar;
|
||||||
QProgressBar *loadBar;
|
QProgressBar *loadBar;
|
||||||
QScrollArea *scrollArea;
|
QScrollArea *scrollArea;
|
||||||
double scaleFactor = 1;
|
double scaleFactor = 1;
|
||||||
PylonWrapper *pyloncam;
|
PylonWrapper *singlecam;
|
||||||
|
DualcamWrapper *dualcam;
|
||||||
ImageBuffer *buffer;
|
ImageBuffer *buffer;
|
||||||
Grabber *grabber;
|
Grabber *singlecamgrabber;
|
||||||
|
DualcamGrabber *dualcamgrabber;
|
||||||
Writer *writer;
|
Writer *writer;
|
||||||
bool grabbing, stopRequest, writing, labelSwitch, dryRun;
|
CameraLayout layout;
|
||||||
|
bool grabbing, stopRequest, writing, labelSwitch, dryRun, cameraOpened, camsconfigured;
|
||||||
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); }";
|
||||||
@@ -112,8 +123,9 @@ private:
|
|||||||
QString storageLocation = "";
|
QString storageLocation = "";
|
||||||
ProjectMetadata mdata;
|
ProjectMetadata mdata;
|
||||||
Pylon::DeviceInfoList_t deviceList;
|
Pylon::DeviceInfoList_t deviceList;
|
||||||
CamConfigurator *d;
|
|
||||||
Pylon::PylonAutoInitTerm autoInitTerm;
|
Pylon::PylonAutoInitTerm autoInitTerm;
|
||||||
|
CamConfigurator *cameraConfigDialog;
|
||||||
|
CameraID *cameraIdDialog;
|
||||||
|
|
||||||
|
|
||||||
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer)
|
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer)
|
||||||
@@ -132,6 +144,7 @@ private:
|
|||||||
QAction *grab_stop_action;
|
QAction *grab_stop_action;
|
||||||
QAction *connect_camera_action;
|
QAction *connect_camera_action;
|
||||||
QAction *disconnect_camera_action;
|
QAction *disconnect_camera_action;
|
||||||
|
QAction *set_cam_identifier_action;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
143
pylonwrapper.cpp
143
pylonwrapper.cpp
@@ -1,32 +1,34 @@
|
|||||||
#include "pylonwrapper.h"
|
#include "pylonwrapper.h"
|
||||||
|
|
||||||
PylonWrapper::PylonWrapper(const std::string &fullName):
|
PylonWrapper::PylonWrapper(const std::string &fullName):
|
||||||
valid(false), fullName(fullName), camera(nullptr) {
|
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) {
|
||||||
|
qDebug() << "Constructor with layout";
|
||||||
|
this->fullName = layout.devices[0];
|
||||||
|
this->layout = layout;
|
||||||
Pylon::PylonInitialize();
|
Pylon::PylonInitialize();
|
||||||
// camera = new Pylon::CInstantCamera();
|
|
||||||
// std::cerr << "Wrapper:camera is open" << camera->IsOpen() << std::endl;
|
|
||||||
// std::cerr << "Wrapper:is valid" << valid << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PylonWrapper::~PylonWrapper() {
|
PylonWrapper::~PylonWrapper() {
|
||||||
std::cerr << "wrapper destructor" << std::endl;
|
qDebug() << "wrapper destructor";
|
||||||
if (camera != nullptr){
|
if (camera != nullptr){
|
||||||
std::cerr << "check camera!" << std::endl;
|
|
||||||
if (camera->IsOpen()) {
|
if (camera->IsOpen()) {
|
||||||
std::cerr << "close camera!" << std::endl;
|
qDebug() << "Camera open, closing it!";
|
||||||
camera->Close();
|
camera->Close();
|
||||||
// std::cerr << "terminate pylon" << std::endl;
|
|
||||||
// terminate();
|
|
||||||
}
|
}
|
||||||
std::cerr << "delete camera!" << std::endl;
|
|
||||||
|
|
||||||
delete camera;
|
delete camera;
|
||||||
camera = nullptr;
|
camera = nullptr;
|
||||||
}
|
}
|
||||||
std::cerr << "wrapper: deleted camera" << std::endl;
|
terminate();
|
||||||
|
qDebug() << "Successfully deleted camera";
|
||||||
}
|
}
|
||||||
|
|
||||||
void PylonWrapper::terminate() {
|
void PylonWrapper::terminate() {
|
||||||
|
qDebug() << "Terminate";
|
||||||
try {
|
try {
|
||||||
Pylon::PylonTerminate();
|
Pylon::PylonTerminate();
|
||||||
} catch (const Pylon::GenericException &e) {
|
} catch (const Pylon::GenericException &e) {
|
||||||
@@ -126,13 +128,14 @@ bool PylonWrapper::gain(double gain_db) {
|
|||||||
ImageSettings PylonWrapper::getImageSettings() {
|
ImageSettings PylonWrapper::getImageSettings() {
|
||||||
ImageSettings settings;
|
ImageSettings settings;
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
Pylon::CEnumParameter pixelFormat( camera->GetNodeMap(), "PixelFormat" );
|
||||||
|
Pylon::CPixelTypeMapper pixelTypeMapper( &pixelFormat );
|
||||||
|
Pylon::EPixelType pixelType = pixelTypeMapper.GetPylonPixelTypeFromNodeValue( pixelFormat.GetIntValue() );
|
||||||
Pylon::CIntegerParameter width( camera->GetNodeMap(), "Width");
|
Pylon::CIntegerParameter width( camera->GetNodeMap(), "Width");
|
||||||
Pylon::CIntegerParameter height( camera->GetNodeMap(), "Height");
|
Pylon::CIntegerParameter height( camera->GetNodeMap(), "Height");
|
||||||
Pylon::CEnumParameter pixelFormat( camera->GetNodeMap(), "PixelFormat");
|
settings.pixelType = pixelType;
|
||||||
Pylon::CPixelTypeMapper pixelTypeMapper(&pixelFormat);
|
settings.width = (uint32_t)width.GetValue();
|
||||||
settings.pixelType = pixelTypeMapper.GetPylonPixelTypeFromNodeValue(pixelFormat.GetIntValue());
|
settings.height = (uint32_t)height.GetValue();
|
||||||
settings.width = width.GetValue();
|
|
||||||
settings.height = height.GetValue();
|
|
||||||
settings.orientation = Pylon::EImageOrientation::ImageOrientation_TopDown;
|
settings.orientation = Pylon::EImageOrientation::ImageOrientation_TopDown;
|
||||||
}
|
}
|
||||||
return settings;
|
return settings;
|
||||||
@@ -140,21 +143,78 @@ ImageSettings PylonWrapper::getImageSettings() {
|
|||||||
|
|
||||||
bool PylonWrapper::grabFrame(MyImage &img) {
|
bool PylonWrapper::grabFrame(MyImage &img) {
|
||||||
Pylon::CGrabResultPtr frame;
|
Pylon::CGrabResultPtr frame;
|
||||||
|
qDebug() << "grabFrame";
|
||||||
if (valid) {
|
if (valid) {
|
||||||
camera->StartGrabbing();
|
qDebug() << "Setting width" << layout.rois[0].width;
|
||||||
camera->RetrieveResult( 5000, frame, Pylon::TimeoutHandling_ThrowException);
|
Pylon::CIntegerParameter(camera->GetNodeMap(), "Width").SetValue(layout.rois[0].width);
|
||||||
camera->StopGrabbing();
|
qDebug() << "Setting height" << layout.rois[0].height;
|
||||||
}
|
Pylon::CIntegerParameter(camera->GetNodeMap(), "Height").SetValue(layout.rois[0].height);
|
||||||
|
qDebug() << "Setting xoffset" << layout.rois[0].x;
|
||||||
|
Pylon::CIntegerParameter(camera->GetNodeMap(), "OffsetX").SetValue(layout.rois[0].x);
|
||||||
|
qDebug() << "Setting yoffset" << layout.rois[0].y;
|
||||||
|
Pylon::CIntegerParameter(camera->GetNodeMap(), "OffsetY").SetValue(layout.rois[0].y);
|
||||||
|
|
||||||
|
camera->StartGrabbing();
|
||||||
|
camera->RetrieveResult( 5000, frame, Pylon::TimeoutHandling_ThrowException);
|
||||||
|
camera->StopGrabbing();
|
||||||
|
qDebug() << "grabFrame done";
|
||||||
|
}
|
||||||
|
|
||||||
img.setFrame(frame);
|
img.setFrame(frame);
|
||||||
return frame.IsValid();
|
return frame.IsValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PylonWrapper::openCamera(std::string &message) {
|
uint32_t PylonWrapper::sensorWidth() {
|
||||||
|
qDebug() << "Reading SensorWidth";
|
||||||
|
uint32_t width = -1;
|
||||||
|
if (valid) {
|
||||||
|
qDebug() << "SensorWidth available";
|
||||||
|
GenApi::INodeMap &nodemap = camera->GetNodeMap();
|
||||||
|
if (GenApi::IsAvailable(nodemap.GetNode("SensorWidth"))) {
|
||||||
|
Pylon::CIntegerParameter pwidth( nodemap, "SensorWidth" );
|
||||||
|
width = (uint32_t)pwidth.GetValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t PylonWrapper::sensorHeight() {
|
||||||
|
qDebug() << "Reading SensorHeight";
|
||||||
|
uint32_t height = -1;
|
||||||
|
if (valid){
|
||||||
|
GenApi::INodeMap &nodemap = camera->GetNodeMap();
|
||||||
|
if (GenApi::IsAvailable(nodemap.GetNode("SensorHeight"))) {
|
||||||
|
Pylon::CIntegerParameter pheight( nodemap, "SensorHeight" );
|
||||||
|
height = (uint32_t)pheight.GetValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PylonWrapper::resetCamera() {
|
||||||
|
uint32_t dfltWidth = sensorWidth();
|
||||||
|
uint32_t dfltHeight = sensorHeight();
|
||||||
|
qDebug() << "resetting camera to default ROI (" << dfltWidth << ", " << dfltHeight << ")";
|
||||||
|
try {
|
||||||
|
GenApi::INodeMap& nodemap = camera->GetNodeMap();
|
||||||
|
// 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);
|
||||||
|
} catch (const Pylon::GenericException &e) {
|
||||||
|
std::string message = e.GetDescription();
|
||||||
|
std::cerr << "An exception occurred." << std::endl << e.GetDescription() << std::endl;
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
qDebug() << "resetting camera to default ROI done";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PylonWrapper::openCamera(std::string &message) {
|
||||||
|
qDebug() << "opening camera";
|
||||||
try {
|
try {
|
||||||
camera = new Pylon::CInstantCamera();
|
camera = new Pylon::CInstantCamera();
|
||||||
|
|
||||||
// Pylon::CInstantCamera camera( pTl->CreateDevice( lstDevices[0] );
|
|
||||||
// Pylon::IPylonDevice *pDevice = Pylon::CTlFactory::GetInstance().CreateFirstDevice();
|
|
||||||
Pylon::String_t fname(fullName.c_str());
|
Pylon::String_t fname(fullName.c_str());
|
||||||
Pylon::IPylonDevice *pDevice = Pylon::CTlFactory::GetInstance().CreateDevice(fname);
|
Pylon::IPylonDevice *pDevice = Pylon::CTlFactory::GetInstance().CreateDevice(fname);
|
||||||
camera->Attach(pDevice);
|
camera->Attach(pDevice);
|
||||||
@@ -165,12 +225,28 @@ bool PylonWrapper::openCamera(std::string &message) {
|
|||||||
message = e.GetDescription();
|
message = e.GetDescription();
|
||||||
std::cerr << "An exception occurred." << std::endl << e.GetDescription() << std::endl;
|
std::cerr << "An exception occurred." << std::endl << e.GetDescription() << std::endl;
|
||||||
valid = false;
|
valid = false;
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
resetCamera();
|
||||||
|
if (!withLayout) {
|
||||||
|
qDebug() << "opening camera without layout, creating a new one";
|
||||||
|
ImageSettings s = getImageSettings();
|
||||||
|
layout = CameraLayout();
|
||||||
|
layout.devices.push_back(fullName);
|
||||||
|
ROI r = ROI();
|
||||||
|
r.x = 0;
|
||||||
|
r.y = 0;
|
||||||
|
r.width = s.width;
|
||||||
|
r.height = s.height;
|
||||||
|
layout.rois.push_back(r);
|
||||||
|
layout.layout = Layout::horizontal;
|
||||||
|
layout.mode = CameraMode::single;
|
||||||
}
|
}
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PylonWrapper::closeCamera() {
|
void PylonWrapper::closeCamera() {
|
||||||
std::cerr << "camera close !" << std::endl;
|
qDebug() << "Close camera!";
|
||||||
if (camera->IsOpen()) {
|
if (camera->IsOpen()) {
|
||||||
try {
|
try {
|
||||||
camera->Close();
|
camera->Close();
|
||||||
@@ -178,7 +254,7 @@ void PylonWrapper::closeCamera() {
|
|||||||
delete camera;
|
delete camera;
|
||||||
camera = nullptr;
|
camera = nullptr;
|
||||||
} catch (const Pylon::GenericException &e) {
|
} catch (const Pylon::GenericException &e) {
|
||||||
std::cerr << "An exception occurred." << std::endl << e.GetDescription() << std::endl;
|
qWarning() << "An exception occurred." << e.GetDescription();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,3 +262,16 @@ void PylonWrapper::closeCamera() {
|
|||||||
Pylon::CInstantCamera *PylonWrapper::getCamera() {
|
Pylon::CInstantCamera *PylonWrapper::getCamera() {
|
||||||
return camera;
|
return camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString PylonWrapper::userName() {
|
||||||
|
GenApi::INodeMap& nodemap = camera->GetNodeMap();
|
||||||
|
QString username = Pylon::CStringParameter(nodemap, "DeviceUserID").GetValue().c_str();
|
||||||
|
if (username.length() == 0) {
|
||||||
|
username = Pylon::CStringParameter(nodemap, "DeviceModelName").GetValue().c_str();
|
||||||
|
}
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PylonWrapper::deviceName() {
|
||||||
|
return QString::fromStdString(fullName);
|
||||||
|
}
|
||||||
@@ -1,21 +1,17 @@
|
|||||||
#ifndef PYLONRECORDER_H
|
#ifndef PYLONWRAPPER_H
|
||||||
#define PYLONRECORDER_H
|
#define PYLONWRAPPER_H
|
||||||
|
|
||||||
#include <pylon/PylonIncludes.h>
|
#include <pylon/PylonIncludes.h>
|
||||||
#include <pylon/BaslerUniversalInstantCamera.h>
|
#include <pylon/BaslerUniversalInstantCamera.h>
|
||||||
|
#include "mylogger.h"
|
||||||
|
#include "util.h"
|
||||||
#include "myimage.h"
|
#include "myimage.h"
|
||||||
|
|
||||||
struct ImageSettings {
|
|
||||||
int64_t width = 0;
|
|
||||||
int64_t height = 0;
|
|
||||||
Pylon::EPixelType pixelType;
|
|
||||||
Pylon::EImageOrientation orientation;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PylonWrapper
|
class PylonWrapper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PylonWrapper(const std::string &fullName);
|
PylonWrapper(const std::string &name);
|
||||||
|
PylonWrapper(const CameraLayout &layout);
|
||||||
~PylonWrapper();
|
~PylonWrapper();
|
||||||
|
|
||||||
ImageSettings getImageSettings();
|
ImageSettings getImageSettings();
|
||||||
@@ -31,15 +27,21 @@ public:
|
|||||||
bool exposureTime(double exposure_time);
|
bool exposureTime(double exposure_time);
|
||||||
double gain();
|
double gain();
|
||||||
bool gain(double gain_db);
|
bool gain(double gain_db);
|
||||||
|
uint32_t sensorHeight();
|
||||||
|
uint32_t sensorWidth();
|
||||||
|
QString userName();
|
||||||
Pylon::CInstantCamera *getCamera();
|
Pylon::CInstantCamera *getCamera();
|
||||||
|
void resetCamera();
|
||||||
|
QString deviceName();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Pylon::CInstantCamera *camera;
|
Pylon::CInstantCamera *camera;
|
||||||
bool valid;
|
bool valid, withLayout;
|
||||||
std::string fullName;
|
std::string fullName;
|
||||||
|
CameraLayout layout;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PYLONRECORDER_H
|
#endif // PYLONWRAPPER_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;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// *********************************************************************************************************
|
||||||
24
util.h
24
util.h
@@ -25,4 +25,28 @@ struct CameraLayout {
|
|||||||
CameraMode mode;
|
CameraMode mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class VideoFormat {
|
||||||
|
raw,
|
||||||
|
mp4
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ImageSettings {
|
||||||
|
int64_t width = 0;
|
||||||
|
int64_t height = 0;
|
||||||
|
Pylon::EPixelType pixelType;
|
||||||
|
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*/
|
||||||
128
writer.cpp
128
writer.cpp
@@ -1,8 +1,13 @@
|
|||||||
#include "writer.h"
|
#include "writer.h"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <pylon/VideoWriter.h>
|
||||||
|
#include <chrono>
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
typedef high_resolution_clock Time;
|
||||||
|
typedef milliseconds ms;
|
||||||
|
typedef duration<float> fsec;
|
||||||
|
|
||||||
|
|
||||||
void Writer::setVideoSpecs(VideoSpecs specs) {
|
void Writer::setVideoSpecs(VideoSpecs specs) {
|
||||||
videoSpecs = specs;
|
videoSpecs = specs;
|
||||||
@@ -10,6 +15,7 @@ void Writer::setVideoSpecs(VideoSpecs specs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Writer::setProjectMetadata(ProjectMetadata mdata) {
|
void Writer::setProjectMetadata(ProjectMetadata mdata) {
|
||||||
|
qDebug() << "received metadata";
|
||||||
metadata = mdata;
|
metadata = mdata;
|
||||||
metadata_valid = true;
|
metadata_valid = true;
|
||||||
}
|
}
|
||||||
@@ -25,113 +31,51 @@ 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;
|
||||||
if (specs_valid) {
|
std::ofstream myFile;
|
||||||
|
if (videoSpecs.format == VideoFormat::mp4 && !Pylon::CVideoWriter::IsSupported()) {
|
||||||
|
qWarning() << "VideoWriter is not supported at the moment. Please install the pylon Supplementary Package for MPEG-4 which is available on the Basler website.";
|
||||||
|
// Releases all pylon resources.
|
||||||
|
// PylonTerminate();
|
||||||
|
// Return with error code 1.
|
||||||
|
emit writingDone();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qDebug() << "checks done!";
|
||||||
|
|
||||||
|
Pylon::CVideoWriter videoWriter;
|
||||||
|
if (specs_valid && videoSpecs.format != VideoFormat::raw) {
|
||||||
stop_request = false;
|
stop_request = false;
|
||||||
stopNow = false;
|
stopNow = false;
|
||||||
|
videoWriter.SetParameter((uint32_t)videoSpecs.width, (uint32_t)videoSpecs.height,
|
||||||
std::ofstream myFile;
|
videoSpecs.pixelType, (double)videoSpecs.fps, videoSpecs.quality);
|
||||||
myFile.open(videoSpecs.filename, std::ios::out | std::ios::binary);
|
videoWriter.Open(videoSpecs.filename.c_str());
|
||||||
myFile.write((char*)&videoSpecs.width, 4);
|
qDebug() << "preparations done, starting loop!";
|
||||||
myFile.write((char*)&videoSpecs.height, 4);
|
|
||||||
// Pylon::CVideoWriter videoWriter;
|
|
||||||
// videoWriter.SetParameter(videoSpecs.width, videoSpecs.height, videoSpecs.pixelType,
|
|
||||||
// videoSpecs.fps, videoSpecs.quality);
|
|
||||||
// std::cout << !Pylon::CVideoWriter::IsSupported() << std::endl;
|
|
||||||
// videoWriter.SetParameter();
|
|
||||||
// videoWriter.Open(videoSpecs.filename.c_str());
|
|
||||||
// std::cerr << "Video writer is open!" << videoWriter.IsOpen() << std::endl;
|
|
||||||
nix::File nix_file =nix::File::open(videoSpecs.filename + ".nix", nix::FileMode::Overwrite, "hdf5", nix::Compression::DeflateNormal);
|
|
||||||
nix::Block b = nix_file.createBlock("Recording", "nix.recording");
|
|
||||||
nix::Section s = nix_file.createSection("Recording", "nix.recording");
|
|
||||||
b.metadata(s);
|
|
||||||
nix::Value v(nix::util::timeToStr(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())));
|
|
||||||
s.createProperty("date", v);
|
|
||||||
|
|
||||||
nix::Value fn(videoSpecs.filename);
|
|
||||||
s.createProperty("moviefile", fn);
|
|
||||||
nix::Section sw_sec = s.createSection("PylonRecorder", "nix.software");
|
|
||||||
sw_sec.createProperty("version", nix::Value(1));
|
|
||||||
|
|
||||||
nix::Section hw_sec = s.createSection("Basler ACA2040-120um", "nix.hardware.camera");
|
|
||||||
hw_sec.createProperty("type", nix::Value("monochrome"));
|
|
||||||
hw_sec.createProperty("manufacturer", nix::Value("Basler AG"));
|
|
||||||
nix::Property p = hw_sec.createProperty("framerate", nix::Value(static_cast<int>(videoSpecs.fps)));
|
|
||||||
p.unit("Hz");
|
|
||||||
nix::Property p1 = hw_sec.createProperty("exposure time", nix::Value(static_cast<int>(videoSpecs.exposureTime)));
|
|
||||||
p1.unit("us");
|
|
||||||
nix::Property p2 = hw_sec.createProperty("detector gain", nix::Value(static_cast<int>(videoSpecs.detectorGain)));
|
|
||||||
p2.unit("dB");
|
|
||||||
|
|
||||||
if (metadata_valid) {
|
|
||||||
writeMetadata(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
nix::NDSize initial_shape(1, chunksize);
|
|
||||||
nix::DataArray frametimes = b.createDataArray("frametimes", "nix.imaging.frametimes", nix::DataType::String, initial_shape);
|
|
||||||
frametimes.label("time");
|
|
||||||
frametimes.appendSetDimension();
|
|
||||||
nix::DataArray frameindices = b.createDataArray("frameindex", "nix.imaging.frameid", nix::DataType::Int64, initial_shape);
|
|
||||||
frameindices.appendSetDimension();
|
|
||||||
|
|
||||||
std::vector<std::string> stamps_buffer(chunksize);
|
|
||||||
std::vector<int64_t> ids_buffer(chunksize);
|
|
||||||
|
|
||||||
nix::NDSize offset(1, 0);
|
|
||||||
nix::NDSize current_shape(initial_shape);
|
|
||||||
nix::NDSize chunk_shape(1, chunksize);
|
|
||||||
while ((!stop_request || buffer->bufferLoad() > 0) && !stopNow) {
|
while ((!stop_request || buffer->bufferLoad() > 0) && !stopNow) {
|
||||||
if (buffer->bufferLoad() > 0 ) {
|
if (buffer->bufferLoad() > 0 ) {
|
||||||
MyImage *img = buffer->pop();
|
size_t framecount = 0;
|
||||||
|
MyImage *img = buffer->read(framecount);
|
||||||
if (img != nullptr) {
|
if (img != nullptr) {
|
||||||
auto start = high_resolution_clock::now();
|
Pylon::CPylonImage pyImage;
|
||||||
// framecount += 1;
|
try {
|
||||||
myFile.write((char*)img->data(), img->size());
|
pyImage.AttachUserBuffer(img->data(), videoSpecs.width * videoSpecs.height, videoSpecs.pixelType, videoSpecs.width, videoSpecs.height, 0, videoSpecs.orientation);
|
||||||
|
videoWriter.Add(pyImage);
|
||||||
// Pylon::CPylonImage pyImage;
|
} catch (const Pylon::GenericException &e) {
|
||||||
// try {
|
std::cerr << "Writer::run: An exception occurred." << std::endl << e.GetDescription() << std::endl;
|
||||||
// pyImage.AttachUserBuffer(img->data(), videoSpecs.width * videoSpecs.height, videoSpecs.pixelType, videoSpecs.width, videoSpecs.height, 0, videoSpecs.orientation);
|
|
||||||
// // Test duration of writing...
|
|
||||||
// videoWriter.Add( pyImage );
|
|
||||||
|
|
||||||
// } catch (const Pylon::GenericException &e) {
|
|
||||||
// std::cerr << "Writer::run: An exception occurred." << std::endl << e.GetDescription() << std::endl;
|
|
||||||
// }
|
|
||||||
auto stop = high_resolution_clock::now();
|
|
||||||
auto duration = duration_cast<microseconds>(stop - start);
|
|
||||||
std::cerr << "wrote binary to file " << duration.count() << std::endl;
|
|
||||||
if (count < chunksize) {
|
|
||||||
stamps_buffer[count] = nix::util::timeToStr(img->timestamp());
|
|
||||||
ids_buffer[count] = img->index();
|
|
||||||
count ++;
|
|
||||||
} else {
|
|
||||||
frametimes.setData(nix::DataType::String, stamps_buffer.data(), chunk_shape, offset);
|
|
||||||
frameindices.setData(nix::DataType::Int64, ids_buffer.data(), chunk_shape, offset);
|
|
||||||
current_shape += initial_shape;
|
|
||||||
frametimes.dataExtent(current_shape);
|
|
||||||
frameindices.dataExtent(current_shape);
|
|
||||||
offset[0] += chunksize;
|
|
||||||
count = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (buffer->bufferLoad() < 1 && !stop_request) {
|
while (buffer->bufferLoad() < 1 && !stop_request) {
|
||||||
msleep(10);
|
msleep(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (count > 0) {
|
videoWriter.Close();
|
||||||
chunk_shape[0] = count;
|
|
||||||
frametimes.setData(nix::DataType::String, stamps_buffer.data(), chunk_shape, offset);
|
|
||||||
frameindices.setData(nix::DataType::Int64, ids_buffer.data(), chunk_shape, offset);
|
|
||||||
}
|
|
||||||
// videoWriter.Close();
|
|
||||||
myFile.close();
|
|
||||||
nix_file.close();
|
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Got no video specifications, not writing!" << std::endl;
|
qDebug() << "Got no video specifications, not writing!";
|
||||||
}
|
}
|
||||||
emit writingDone();
|
emit writingDone();
|
||||||
}
|
}
|
||||||
|
|||||||
12
writer.h
12
writer.h
@@ -9,17 +9,7 @@
|
|||||||
#include "pylonwrapper.h"
|
#include "pylonwrapper.h"
|
||||||
#include "imagebuffer.h"
|
#include "imagebuffer.h"
|
||||||
#include "projectsettings.h"
|
#include "projectsettings.h"
|
||||||
#include <opencv2/opencv.hpp>
|
#include "util.h"
|
||||||
|
|
||||||
struct VideoSpecs {
|
|
||||||
std::string filename;
|
|
||||||
uint32_t width, height, quality = 10 ;
|
|
||||||
int fps;
|
|
||||||
double exposureTime;
|
|
||||||
double detectorGain;
|
|
||||||
Pylon::EPixelType pixelType;
|
|
||||||
Pylon::EImageOrientation orientation;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Writer : public QThread
|
class Writer : public QThread
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user