diff --git a/notes.md b/notes.md index c5f6721..f6d2daf 100644 --- a/notes.md +++ b/notes.md @@ -3,12 +3,34 @@ Recorder for up to two Basler cameras. ## TODOs + * implement grabbing from 2 joined cameras * set the region of interest * save properly -## FIXMEs & improvements +## FIXMEs -* make the max image sizes depend on camera +* 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 +* 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 \ No newline at end of file diff --git a/pylonrecorder.cpp b/pylonrecorder.cpp index 298cfbc..9992c8e 100644 --- a/pylonrecorder.cpp +++ b/pylonrecorder.cpp @@ -32,7 +32,12 @@ #endif PylonRecorder::PylonRecorder(QWidget *parent) - : QMainWindow(parent), imageLabel(new QLabel), scrollArea(new QScrollArea), grabber(nullptr), writer(nullptr), buffer(nullptr), pyloncam(nullptr), dryRun(false), cameraOpened(false) + : QMainWindow(parent), imageLabel(new QLabel), scrollArea(new QScrollArea), + singlecamgrabber(nullptr), dualcamgrabber(nullptr), + writer0(nullptr), writer1(nullptr), + buffer0(nullptr), buffer1(nullptr), + singlecam(nullptr), dualcam(nullptr), + dryRun(false), cameraOpened(false), camsconfigured(false) { imageLabel->setBackgroundRole(QPalette::Base); imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); @@ -42,24 +47,7 @@ PylonRecorder::PylonRecorder(QWidget *parent) scrollArea->setWidget(imageLabel); scrollArea->setVisible(false); 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); connect(frameTimer, &QTimer::timeout, this, &PylonRecorder::displaySingleFrame); pressureTimer = new QTimer(this); @@ -118,34 +106,6 @@ PylonRecorder::PylonRecorder(QWidget *parent) applySettings(); } -// void PylonRecorder::setupCameras(){ -// std::cerr << "Setting up cameras!" << std::endl; -// qDebug() << "setting up cameras"; -// for (auto dev : deviceList) { -// std::cout << dev.GetFullName() << " " << dev.GetFriendlyName() << std::endl; -// } -// std::string s = "detected "; -// s += deviceList.size(); -// s += " devices"; -// qDebug() << s.c_str(); - -// 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(); -// // qDebug() << -// // 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() { qDebug() << "Detecting devices!"; Pylon::CTlFactory& TlFactory = Pylon::CTlFactory::GetInstance(); @@ -155,30 +115,56 @@ void PylonRecorder::detectCameras() { PylonRecorder::~PylonRecorder(){ qDebug() << "Destructing PylonRecorder"; - if (grabber != nullptr && grabber->isRunning()) { - grabber->requestStop(); - grabber->wait(1000); + if (singlecamgrabber != nullptr && singlecamgrabber->isRunning()) { + singlecamgrabber->requestStop(); + singlecamgrabber->wait(1000); } - if (writer != nullptr && writer->isRunning()) { - writer->forceStop(); - writer->wait(1000); + if (writer0 != nullptr && writer0->isRunning()) { + writer0->forceStop(); + writer0->wait(1000); } storeSettings(); - if (pyloncam != nullptr) { - qDebug() << "Deleting pyloncam"; - delete pyloncam; - pyloncam = nullptr; + if (singlecam != nullptr) { + qDebug() << "Deleting singlecam"; + delete singlecam; + singlecam = nullptr; + } + if (dualcam != nullptr) { + qDebug() << "Deleting dualcam"; + delete dualcam; + dualcam = nullptr; } - if (buffer != nullptr) { + if (buffer0 != nullptr) { + qDebug() << "Deleting buffer"; + delete buffer0; + buffer0 = nullptr; + } + if (buffer1 != nullptr) { qDebug() << "Deleting buffer"; - delete buffer; - buffer = nullptr; + delete buffer1; + buffer1 = nullptr; + } + if (singlecamgrabber != nullptr) { + qDebug() << "Deleting grabber"; + delete singlecamgrabber; + singlecamgrabber = nullptr; + } + if (dualcamgrabber != nullptr) { + qDebug() << "Deleting grabber"; + delete dualcamgrabber; + dualcamgrabber = nullptr; + } + if (writer0 != nullptr) { + qDebug() << "Deleting writer"; + delete writer0; + writer0 = nullptr; + } + if (writer1 != nullptr) { + qDebug() << "Deleting writer"; + delete writer1; + writer1 = nullptr; } - qDebug() << "Deleting grabber"; - delete grabber; - qDebug() << "Deleting writer"; - delete writer; qDebug() << "Deleting setting"; delete settings; } @@ -201,6 +187,7 @@ void PylonRecorder::applySettings() { void PylonRecorder::storeSettings() { + // FIXME store cam layout to settings settings->setValue("camera/exposure", exposureSpinner->value()); settings->setValue("camera/framerate", framerateSpinner->value()); settings->setValue("camera/gain", gainSpinner->value()); @@ -232,6 +219,7 @@ bool PylonRecorder::loadFile(const QString &fileName) { void PylonRecorder::setImage(const QImage &newImage) { + //FIXME figure out how to display both images. extract to extra class... image = newImage; // (image.colorSpace().isValid()) // image.convertToColorSpace(QColorSpace::SRgb); @@ -563,6 +551,7 @@ void PylonRecorder::updateActions() { connect_camera_action->setEnabled(true); grab_still_action->setEnabled(deviceList.size() > 0); grab_continuous_action->setEnabled(cameraOpened && !grabbing); + // grab_continuous_action->setEnabled(!grabbing); grab_stop_action->setEnabled(grabbing); } @@ -604,19 +593,30 @@ void PylonRecorder::adjustScrollBar(QScrollBar *scrollBar, double factor) { + ((factor - 1) * scrollBar->pageStep()/2))); } + void PylonRecorder::cameraConfiguration(){ d = new CamConfigurator(deviceList, this); - connect(d, SIGNAL(accepted()), SLOT(camerasetup())); + connect(d, SIGNAL(accepted()), SLOT(cameraConfigurationAccepted())); + connect(d, SIGNAL(rejected()), SLOT(cameraConfigurationAborted())); // QObject::connect(&d, SIGNAL(column_visibility_changed(QString, QString,bool)), this, SLOT(visible_columns_update(QString, QString,bool))); d->exec(); } -void PylonRecorder::camerasetup() { + +void PylonRecorder::cameraConfigurationAccepted() { qDebug() << "Cameras setting " << ((d->result()) ? "Accepted" : "Discarded"); this->layout = d->layout(); + camsconfigured = true; delete d; } + +void PylonRecorder::cameraConfigurationAborted() { + qDebug() << "Camera configuration aborted!"; + camsconfigured = false; +} + + void PylonRecorder::connectCamera() { this->layout = CameraLayout(); std::cerr << this->layout.rois.size() << " " << this->layout.devices.size() << std::endl; @@ -627,29 +627,54 @@ void PylonRecorder::connectCamera() { QString msg = "
No camera device found!
Connect camera and try again!
"; msgBox.setText(msg); msgBox.exec(); - } else { - cameraConfiguration(); - 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(); - pyloncam = new PylonWrapper(layout); - bool success = pyloncam->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 = "Could not open camera device!
" + QString::fromStdString(message) + "
"; - msgBox.setText(msg); - msgBox.exec(); - cameraOpened = false; - } - statusBar()->showMessage(QString::fromStdString(message)); - updateActions(); + qWarning() << msg.toStdString().c_str(); + return; + } + cameraConfiguration(); + if (!camsconfigured) { + qDebug() << "cameras have not been properly configured!"; + return; + } + 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 = "Could not open camera device!
" + QString::fromStdString(message) + "
"; + msgBox.setText(msg); + msgBox.exec(); + cameraOpened = false; } + statusBar()->showMessage(QString::fromStdString(message)); + updateActions(); + } + if (layout.mode == CameraMode::dual && layout.devices.size() == 2) { + qDebug() << "dual camera mode"; + std::string message; + qDebug() << "creating dual cam wrapper"; + dualcam = new DualcamWrapper(layout); + bool success = dualcam->openCameras(message); + if (success) { + cameraConnectedLabel->setText("connected"); + cameraConnectedLabel->setStyleSheet("QLabel { font-size: 10px;font-family: Arial;color: green;}"); + cameraOpened = true; + } else { + QMessageBox msgBox; + QString msg = "Could not open camera device!
" + QString::fromStdString(message) + "
"; + msgBox.setText(msg); + msgBox.exec(); + cameraOpened = false; + } + statusBar()->showMessage(QString::fromStdString(message)); + updateActions(); } qDebug() << "connecting cam(s) done!"; } @@ -657,13 +682,18 @@ void PylonRecorder::connectCamera() { void PylonRecorder::disconnectCamera() { qDebug() << "disconnecting camera"; - if (pyloncam != nullptr && pyloncam->isOpen()) { - pyloncam->closeCamera(); - statusBar()->showMessage(tr("Camera closed!")); - cameraConnectedLabel->setText("not connected"); - cameraConnectedLabel->setStyleSheet("QLabel { font-size: 10px;font-family: Arial;color: red;}"); - updateActions(); + if (singlecam != nullptr && singlecam->isOpen()) { + singlecam->closeCamera(); + } + 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"; } @@ -687,13 +717,14 @@ VideoSpecs PylonRecorder::getVideoSpecs(const ImageSettings &settings) { return s; } -void PylonRecorder::startRecording() { + +void PylonRecorder::startSinglecamRecording() { qDebug() << "start recording!"; std::string filename = createFilename(".mp4"); fileLabel->setText(QString::fromStdString(filename)); qDebug() << "storing to file " << filename.c_str(); - ImageSettings settings = pyloncam->getImageSettings(); + ImageSettings settings = singlecam->getImageSettings(); qDebug() << "got image settings"; VideoSpecs specs = getVideoSpecs(settings); @@ -701,54 +732,70 @@ void PylonRecorder::startRecording() { specs.format = VideoFormat::mp4; qDebug() << "got video specifications"; - if (buffer != nullptr) { - buffer->clear(); - delete buffer; - buffer = nullptr; + if (buffer0 != nullptr) { + buffer0->clear(); + delete buffer0; + buffer0 = nullptr; } qDebug() << "setting image buffer to size " << buffersizeSpinner->value(); - buffer = new ImageBuffer(defaultBufferSize); - if (buffersizeSpinner->value() != static_cast