Compare commits

..

21 Commits

Author SHA1 Message Date
39fec831ff add optional suffix to getFilename 2024-03-11 16:26:30 +01:00
f8304501ba some notes, infrastructure for dualcam grabbing 2024-03-11 16:25:06 +01:00
a013ab1153 simplify setter and support setting of indicidual values 2024-03-11 16:06:14 +01:00
e259d668ad add grabber for dual cam recordings 2024-03-11 15:53:44 +01:00
5a999fac54 reduce wait time 2024-03-11 15:52:22 +01:00
8c26fb4829 move ImageSettings to util 2024-03-11 14:34:53 +01:00
f22d3ef302 wrapper for dual camera recording 2024-03-11 14:34:06 +01:00
384aab9de4 some cleanup 2024-03-11 09:13:59 +01:00
4e617e9505 remove opencv dependency find pylon with cmake function 2024-03-08 16:49:35 +01:00
b99ff19620 properly use new ringbuffer methods 2024-03-08 16:10:25 +01:00
cb9867eec0 remove debug stuff 2024-03-08 16:09:24 +01:00
97ca5aba51 rewrite ringbuffer 2024-03-08 16:06:23 +01:00
37db983a2f grabbing and display are working again 2024-03-08 12:02:27 +01:00
7ad190513a support mp4 output 2024-03-08 10:14:45 +01:00
47ea6fb27e a bit of cleanup and x,y offset to VideoSpecs 2024-03-08 09:13:48 +01:00
29abd710e9 fix resetting resolutions, not fully working yet 2024-03-07 17:12:46 +01:00
63231e5a1c fix resetting resolutions, not fully working yet 2024-03-07 17:07:53 +01:00
96effc81c5 switch to pylon 7.4 2024-03-07 17:07:33 +01:00
adf48f3002 taking still image works with specified ROI 2024-03-06 09:18:43 +01:00
6a82c8d640 grabbing still in single camera mode works again 2024-03-04 18:13:45 +01:00
203063d83d fix nullptr exception on camera disconnect 2024-03-04 16:54:33 +01:00
18 changed files with 902 additions and 324 deletions

View File

@ -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,21 @@ 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) # find_package(OpenCV REQUIRED opencv_highgui opencv_core)
include_directories(AFTER ${OpenCV_INCLUDE_DIRS} ) # include_directories(AFTER ${OpenCV_INCLUDE_DIRS} )
set(LINK_LIBS ${LINK_LIBS} ${OpenCV_LIBRARIES}) # set(LINK_LIBS ${LINK_LIBS} ${OpenCV_LIBRARIES})
####################################### #######################################
# Pylon # Pylon
#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})

View File

@ -3,7 +3,7 @@
#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) {
mode_combo = new QComboBox(this); mode_combo = new QComboBox(this);
mode_combo->addItem("camera mode"); mode_combo->addItem("camera mode");

View File

@ -56,6 +56,7 @@ CameraPreview::CameraPreview(QWidget *parent):cameraname(""), camera(nullptr), Q
takeStill(); takeStill();
} }
void CameraPreview::setCamera(QString &device){ void CameraPreview::setCamera(QString &device){
qDebug() << "update camera! ";// << device.toStdString(); qDebug() << "update camera! ";// << device.toStdString();
cameraname = device; cameraname = device;
@ -199,6 +200,6 @@ CameraPreview::~CameraPreview(){
delete camera; delete camera;
camera = nullptr; camera = nullptr;
} }
qDebug() << "preview: deleted camera"; qDebug() << "deleted camera";
} }

29
dualcamgrabber.cpp Normal file
View File

@ -0,0 +1,29 @@
#include "dualcamgrabber.h"
#include <iostream>
#include <pylon/PylonIncludes.h>
void DualcamGrabber::run() {
stop_request = false;
size_t framecount = 0;
if (wrapper->isOpen()) {
Pylon::CInstantCameraArray &cameras = wrapper->getCameraArray();
wrapper->frameRate(static_cast<uint>(framerate));
wrapper->exposureTime(exposure);
wrapper->gain(gain);
cameras.StartGrabbing();
Pylon::CGrabResultPtr frame0, frame1;
while (cameras.IsGrabbing() && !stop_request) {
MyImage *img = new MyImage();
cameras.RetrieveResult( 5000, framecount % 2 == 0 ? frame0 : frame1, Pylon::TimeoutHandling_ThrowException );
img->setFrame(framecount % 2 == 0 ? frame0 : frame1);
if (framecount % 2 == 0) {
buffer0->push(img);
} else {
buffer1->push(img);
}
framecount += 1;
}
cameras.StopGrabbing();
}
}

58
dualcamgrabber.h Normal file
View File

@ -0,0 +1,58 @@
#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 *buffer0, ImageBuffer * buffer1, int framerate, QObject *parent = nullptr) :
QThread(parent), wrapper(wrapper), buffer0(buffer0), buffer1(buffer1), 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 *buffer0, *buffer1;
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();
};
#endif // DUALCAMGRABBER_H

262
dualcamwrapper.cpp Normal file
View File

@ -0,0 +1,262 @@
#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 valid;
}
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) {
if (valid) {
if (camindex == -1) {
frameRate(new_framerate, 0);
frameRate(new_framerate, 1);
return true;
} else if (camindex == 0 && camindex ==1) {
GenApi::INodeMap& nodemap = getNodemap(0);
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) {
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) {
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) {
if (valid) {
if (camindex == -1) {
exposureTime(exposure_time, 0);
exposureTime(exposure_time, 1);
} else {
GenApi::INodeMap& nodemap = getNodemap(camindex);
double d = GenApi::CFloatPtr(nodemap.GetNode("ExposureTime"))->GetValue();
GenApi::INode* n = nodemap.GetNode( "ExposureTime" );
try {
GenApi::CEnumerationPtr(nodemap.GetNode( "ExposureTimeMode" ))->FromString("Standard");
} catch (...) {
qWarning() << "Could not set exposure for cam0";
}
Pylon::CFloatParameter exp_time( n );
exp_time.SetValue( exposure_time );
}
}
return false;
}
double DualcamWrapper::gain(int 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[0].width;
Pylon::CIntegerParameter(nodemap, "Width").SetValue(layout.rois[0].width);
qDebug() << "Setting height" << layout.rois[0].height;
Pylon::CIntegerParameter(nodemap, "Height").SetValue(layout.rois[0].height);
qDebug() << "Setting xoffset" << layout.rois[0].x;
Pylon::CIntegerParameter(nodemap, "OffsetX").SetValue(layout.rois[0].x);
qDebug() << "Setting yoffset" << layout.rois[0].y;
Pylon::CIntegerParameter(nodemap, "OffsetY").SetValue(layout.rois[0].y);
camera->StartGrabbing();
camera->RetrieveResult( 5000, frame, Pylon::TimeoutHandling_ThrowException);
camera->StopGrabbing();
}
img.setFrame(frame);
return frame.IsValid();
}
void DualcamWrapper::resetCamera(int camindex) {
GenApi::INodeMap &nodemap = getNodemap( camindex );
int64_t dfltWidth = 2048;
int64_t dfltHeight = 1536;
qDebug() << "resetting camera to default ROI (" << dfltWidth << ", " << dfltHeight << ")";
try {
// std::cerr << "MaxWidth: " << Pylon::CIntegerParameter(nodemap, "WidthMax").GetValue() << std::endl;
Pylon::CIntegerParameter(nodemap, "Width").SetValue(dfltWidth, false);
// std::cerr << "MaxHeight: " << Pylon::CIntegerParameter(nodemap, "HeightMax").GetValue() << std::endl;
Pylon::CIntegerParameter(nodemap, "Height").SetValue(dfltHeight, false);
Pylon::CIntegerParameter(nodemap, "OffsetX").SetValue(0);
Pylon::CIntegerParameter(nodemap, "OffsetY").SetValue(0);
} 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";
bool valid = true;
Pylon::CTlFactory& tlFactory = Pylon::CTlFactory::GetInstance();
// Pylon::CInstantCameraArray cameras(2);
cameras.Initialize(2);
try {
cameras[0].Attach( tlFactory.CreateDevice( layout.devices[0].c_str() ) );
cameras[1].Attach( tlFactory.CreateDevice( layout.devices[1].c_str() ) );
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);
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;
}

44
dualcamwrapper.h Normal file
View File

@ -0,0 +1,44 @@
#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);
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);
Pylon::CInstantCameraArray &getCameraArray();
// Pylon::CInstantCamera getCamera(int camindex);
private:
void resetCamera(int camindex);
Pylon::CInstantCameraArray cameras;
GenApi::INodeMap& getNodemap(int camindex);
bool valid, withLayout;
CameraLayout layout;
};
#endif // DUALCAMWRAPPER_H

View File

@ -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,14 @@ 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;
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();
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();

View File

@ -1,82 +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){ buffer[head_idx] = img;
load = buffer_size; framecounts[head_idx] = framecount;
if (current_read_index == current_write_index) load = load < buffer_size ? load +=1 : buffer_size;
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;
mutex.unlock(); mutex.unlock();
} }
@ -89,33 +84,28 @@ 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;
} }

View File

@ -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:

View File

@ -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 * 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

View File

@ -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,13 @@
#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),
writer0(nullptr), writer1(nullptr),
buffer0(nullptr), buffer1(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,38 +47,21 @@ 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 *preassureLabel = new QLabel("Buffer preassure:", this);
preassureLabel->setStyleSheet("QLabel{font-size: 11pt;font-family: Arial;font-weight: Bold}"); preassureLabel->setStyleSheet("QLabel{font-size: 11pt;font-family: Arial;font-weight: Bold}");
loadBar = new QProgressBar(this); loadBar = new QProgressBar(this);
@ -105,7 +91,7 @@ PylonRecorder::PylonRecorder(QWidget *parent)
statusBar()->addWidget(camHeader); statusBar()->addWidget(camHeader);
statusBar()->addWidget(cameraConnectedLabel); statusBar()->addWidget(cameraConnectedLabel);
statusBar()->addWidget(preassureLabel); statusBar()->addWidget(preassureLabel);
statusBar()->addWidget(preassureBar); statusBar()->addWidget(pressureBar);
statusBar()->addWidget(loadLabel); statusBar()->addWidget(loadLabel);
statusBar()->addWidget(loadBar); statusBar()->addWidget(loadBar);
statusBar()->addWidget(statusHeader); statusBar()->addWidget(statusHeader);
@ -120,61 +106,65 @@ 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 (writer0 != nullptr && writer0->isRunning()) {
writer->forceStop(); writer0->forceStop();
writer->wait(1000); writer0->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 (buffer0 != nullptr) {
qDebug() << "Deleting buffer"; qDebug() << "Deleting buffer";
delete buffer; delete buffer0;
buffer = nullptr; buffer0 = nullptr;
} }
if (buffer1 != nullptr) {
qDebug() << "Deleting buffer";
delete buffer1;
buffer1 = nullptr;
}
if (singlecamgrabber != nullptr) {
qDebug() << "Deleting grabber";
delete singlecamgrabber;
singlecamgrabber = nullptr;
}
if (dualcamgrabber != nullptr) {
qDebug() << "Deleting grabber"; qDebug() << "Deleting grabber";
delete grabber; delete dualcamgrabber;
dualcamgrabber = nullptr;
}
if (writer0 != nullptr) {
qDebug() << "Deleting writer";
delete writer0;
writer0 = nullptr;
}
if (writer1 != nullptr) {
qDebug() << "Deleting writer"; qDebug() << "Deleting writer";
delete writer; delete writer1;
writer1 = nullptr;
}
qDebug() << "Deleting setting"; qDebug() << "Deleting setting";
delete settings; delete settings;
} }
@ -197,6 +187,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());
@ -228,6 +219,7 @@ bool PylonRecorder::loadFile(const QString &fileName) {
void PylonRecorder::setImage(const QImage &newImage) { void PylonRecorder::setImage(const QImage &newImage) {
//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 +229,13 @@ 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();
} }
@ -557,7 +550,8 @@ void PylonRecorder::updateActions() {
disconnect_camera_action->setEnabled(deviceList.size() > 0); disconnect_camera_action->setEnabled(deviceList.size() > 0);
connect_camera_action->setEnabled(true); connect_camera_action->setEnabled(true);
grab_still_action->setEnabled(deviceList.size() > 0); grab_still_action->setEnabled(deviceList.size() > 0);
//grab_continuous_action->setEnabled(deviceList.size() > 0 && pyloncam->isOpen() && !grabbing); grab_continuous_action->setEnabled(cameraOpened && !grabbing);
// grab_continuous_action->setEnabled(!grabbing);
grab_stop_action->setEnabled(grabbing); grab_stop_action->setEnabled(grabbing);
} }
@ -582,14 +576,15 @@ void PylonRecorder::applyScaling(){
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,105 +593,212 @@ 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); 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))); // QObject::connect(&d, SIGNAL(column_visibility_changed(QString, QString,bool)), this, SLOT(visible_columns_update(QString, QString,bool)));
d->exec(); d->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;
void PylonRecorder::cameraConfigurationAccepted() {
qDebug() << "Cameras setting " << ((d->result()) ? "Accepted" : "Discarded");
this->layout = d->layout();
camsconfigured = true;
delete d; delete d;
} }
void PylonRecorder::cameraConfigurationAborted() {
qDebug() << "Camera configuration aborted!";
camsconfigured = false;
}
void PylonRecorder::connectCamera() { void PylonRecorder::connectCamera() {
this->layout = CameraLayout();
std::cerr << this->layout.rois.size() << " " << this->layout.devices.size() << std::endl;
qDebug() << "connecting camera(s)";
if (deviceList.size() == 0) { 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;
}
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();
}
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 = "<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()) {
singlecam->closeCamera();
}
if (dualcam != nullptr && dualcam->isOpen()) {
dualcam->closeCameras();
}
statusBar()->showMessage(tr("Camera closed!")); statusBar()->showMessage(tr("Camera closed!"));
cameraConnectedLabel->setText("not connected"); cameraConnectedLabel->setText("not connected");
cameraConnectedLabel->setStyleSheet("QLabel { font-size: 10px;font-family: Arial;color: red;}"); cameraConnectedLabel->setStyleSheet("QLabel { font-size: 10px;font-family: Arial;color: red;}");
updateActions(); updateActions();
camsconfigured = false;
cameraOpened = false;
qDebug() << "disconnecting cameras done";
}
VideoSpecs PylonRecorder::getVideoSpecs(const ImageSettings &settings) {
VideoSpecs s = VideoSpecs();
if (this->layout.mode == CameraMode::single && this->layout.devices.size() > 0) {
s.fps = framerateSpinner->value();
s.exposureTime = static_cast<double>(exposureSpinner->value());
s.detectorGain = static_cast<double>(gainSpinner->value());
s.width = static_cast<uint32_t>(this->layout.rois[0].width);
s.height = static_cast<uint32_t>(this->layout.rois[0].height);
s.xoffset = static_cast<uint32_t>(this->layout.rois[0].x);
s.yoffset = static_cast<uint32_t>(this->layout.rois[0].y);
s.pixelType = settings.pixelType;
s.orientation = settings.orientation;
s.quality = 95;
} else {
qWarning() << "Dual camera mode not supported yet!";
} }
return s;
} }
void PylonRecorder::startRecording() { void PylonRecorder::startSinglecamRecording() {
std::string filename = createFilename(); qDebug() << "start 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 (buffer0 != nullptr) {
specs.pixelType = settings.pixelType; buffer0->clear();
specs.orientation = settings.orientation; delete buffer0;
specs.quality = 95; buffer0 = nullptr;
if (buffersizeSpinner->value() != static_cast<int>(buffer->capacity())) { }
buffer->resize(static_cast<size_t>(buffersizeSpinner->value())); qDebug() << "setting image buffer to size " << buffersizeSpinner->value();
buffer0 = new ImageBuffer(defaultBufferSize);
if (buffersizeSpinner->value() != static_cast<int>(buffer0->capacity())) {
buffer0->resize(static_cast<size_t>(buffersizeSpinner->value()));
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())); }
writer->setVideoSpecs(specs); singlecamgrabber = new Grabber(singlecam, buffer0, 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 (writer0 != nullptr) {
delete writer0;
writer0 = nullptr;
}
writer0 = new Writer(buffer0);
connect(writer0, &Writer::writingDone, this, &PylonRecorder::writerDone);
writer0->setVideoSpecs(specs);
QSettings s; QSettings s;
this->mdata.read(s); this->mdata.read(s);
writer->setProjectMetadata(mdata); writer0->setProjectMetadata(mdata);
buffer->clear(); buffer0->clear();
if (!dryRunCheckBox->isChecked()) { if (!dryRunCheckBox->isChecked()) {
writer->start(); writer0->start();
writing = true; writing = true;
} }
dryRun = dryRunCheckBox->isChecked(); dryRun = dryRunCheckBox->isChecked();
grabber->start(); singlecamgrabber->start();
grabbing = true; grabbing = true;
stopRequest = false; stopRequest = false;
}
void PylonRecorder::startDualcamRecording() {
}
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,17 +810,17 @@ 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();
qDebug() << "StopRecording: stop writer!"; qDebug() << "StopRecording: stop writer!";
if (writer != nullptr) if (writer0 != nullptr)
writer->requestStop(); writer0->requestStop();
grabbing = false; grabbing = false;
stopRequest = true; stopRequest = true;
grab_stop_action->setEnabled(false); grab_stop_action->setEnabled(false);
qDebug() << "StopRecording: clear buffer!"; qDebug() << "StopRecording: clear buffer!";
if(buffer != nullptr) { if(buffer0 != nullptr) {
buffer->clear(); buffer0->clear();
writerDone(); writerDone();
} }
} }
@ -727,14 +829,15 @@ void PylonRecorder::stopRecording() {
void PylonRecorder::writerDone() { void PylonRecorder::writerDone() {
preassureTimer->stop(); std::cerr << "writer is Done!!!" << std::endl;
preassureBar->reset(); pressureTimer->stop();
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); singlecamgrabber->wait(10000);
writer->wait(10000); writer0->wait(10000);
writing = false; writing = false;
updateActions(); updateActions();
qInfo() << "writer is Done!"; qInfo() << "writer is Done!";
@ -749,14 +852,16 @@ void PylonRecorder::displayActivity() {
void PylonRecorder::displaySingleFrame() { void PylonRecorder::displaySingleFrame() {
MyImage *img = buffer->readLast(); MyImage *img;
size_t fc = 0;
img = buffer0->readLast(fc);
if (img != nullptr){ if (img != nullptr){
QImage qimg(static_cast<uchar *>(img->data()), img->width(), img->height(), std::cerr << "display, last frame count " << fc << std::endl;
QImage::Format::Format_Grayscale8); QImage qimg(static_cast<uchar *>(img->data()), img->width(), img->height(), QImage::Format::Format_Grayscale8);
setImage(qimg); setImage(qimg);
}/* else { }else {
std::cerr << "Error reading last image" << std::endl; std::cerr << "Error reading last image" << std::endl;
}*/ }
} }
@ -772,13 +877,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,21 +892,22 @@ std::string PylonRecorder::createFilename() {
void PylonRecorder::displayBufferPressure() { void PylonRecorder::displayBufferPressure() {
int value = static_cast<int>(round(buffer->bufferPreassure())); int value = static_cast<int>(round(buffer0->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>(buffer0->bufferLoad());
loadBar->setValue(load); loadBar->setValue(load);
} }
void PylonRecorder::grabStillFromPylon() { void PylonRecorder::grabStillFromPylon() {
if (pyloncam->isOpen()) { qDebug() << "Grab still image form camera!";
if (singlecam != nullptr && singlecam->isOpen()) {
MyImage img; MyImage img;
bool valid = pyloncam->grabFrame(img); 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 +916,7 @@ void PylonRecorder::grabStillFromPylon() {
} else { } else {
statusBar()->showMessage(tr("Camera is not open! Connect to camera first!")); statusBar()->showMessage(tr("Camera is not open! Connect to camera first!"));
} }
qDebug() << "grabbing still image done!";
} }

View File

@ -8,11 +8,14 @@
#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 "util.h"
#include <QImage> #include <QImage>
#if defined(QT_PRINTSUPPORT_LIB) #if defined(QT_PRINTSUPPORT_LIB)
@ -65,7 +68,8 @@ private slots:
void displayActivity(); void displayActivity();
void writerDone(); void writerDone();
void selectStorageLocation(); void selectStorageLocation();
void camerasetup(); void cameraConfigurationAccepted();
void cameraConfigurationAborted();
private: private:
void createActions(); void createActions();
@ -77,8 +81,11 @@ 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);
@ -86,22 +93,24 @@ private:
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;
ImageBuffer *buffer; DualcamWrapper *dualcam;
Grabber *grabber; ImageBuffer *buffer0, *buffer1;
Writer *writer; Grabber *singlecamgrabber;
bool grabbing, stopRequest, writing, labelSwitch, dryRun; DualcamGrabber *dualcamgrabber;
Writer *writer0, *writer1;
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); }";

View File

@ -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::CIntegerParameter width( camera->GetNodeMap(), "Width");
Pylon::CIntegerParameter height( camera->GetNodeMap(), "Height");
Pylon::CEnumParameter pixelFormat( camera->GetNodeMap(), "PixelFormat" ); Pylon::CEnumParameter pixelFormat( camera->GetNodeMap(), "PixelFormat" );
Pylon::CPixelTypeMapper pixelTypeMapper( &pixelFormat ); Pylon::CPixelTypeMapper pixelTypeMapper( &pixelFormat );
settings.pixelType = pixelTypeMapper.GetPylonPixelTypeFromNodeValue(pixelFormat.GetIntValue()); Pylon::EPixelType pixelType = pixelTypeMapper.GetPylonPixelTypeFromNodeValue( pixelFormat.GetIntValue() );
settings.width = width.GetValue(); Pylon::CIntegerParameter width( camera->GetNodeMap(), "Width");
settings.height = height.GetValue(); Pylon::CIntegerParameter height( camera->GetNodeMap(), "Height");
settings.pixelType = pixelType;
settings.width = (uint32_t)width.GetValue();
settings.height = (uint32_t)height.GetValue();
settings.orientation = Pylon::EImageOrientation::ImageOrientation_TopDown; settings.orientation = Pylon::EImageOrientation::ImageOrientation_TopDown;
} }
return settings; return settings;
@ -140,7 +143,17 @@ 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) {
qDebug() << "Setting width" << layout.rois[0].width;
Pylon::CIntegerParameter(camera->GetNodeMap(), "Width").SetValue(layout.rois[0].width);
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->StartGrabbing();
camera->RetrieveResult( 5000, frame, Pylon::TimeoutHandling_ThrowException); camera->RetrieveResult( 5000, frame, Pylon::TimeoutHandling_ThrowException);
camera->StopGrabbing(); camera->StopGrabbing();
@ -149,12 +162,29 @@ bool PylonWrapper::grabFrame(MyImage &img) {
return frame.IsValid(); return frame.IsValid();
} }
void PylonWrapper::resetCamera() {
int64_t dfltWidth = 2048;
int64_t dfltHeight = 1536;
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;
}
}
bool PylonWrapper::openCamera(std::string &message) { 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 +195,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 +224,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();
} }
} }
} }

View File

@ -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();
@ -32,14 +28,16 @@ public:
double gain(); double gain();
bool gain(double gain_db); bool gain(double gain_db);
Pylon::CInstantCamera *getCamera(); Pylon::CInstantCamera *getCamera();
void resetCamera();
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

12
util.h
View File

@ -25,4 +25,16 @@ 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;
};
#endif /*UTIL_H*/ #endif /*UTIL_H*/

View File

@ -2,6 +2,7 @@
#include <chrono> #include <chrono>
#include <fstream> #include <fstream>
#include <pylon/VideoWriter.h>
using namespace std::chrono; using namespace std::chrono;
void Writer::setVideoSpecs(VideoSpecs specs) { void Writer::setVideoSpecs(VideoSpecs specs) {
@ -28,21 +29,28 @@ void Writer::run() {
size_t count = 0; size_t count = 0;
size_t chunksize = 256; size_t chunksize = 256;
// size_t framecount = 0; // size_t framecount = 0;
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;
}
Pylon::CVideoWriter videoWriter;
if (specs_valid) { if (specs_valid) {
stop_request = false; stop_request = false;
stopNow = false; stopNow = false;
if (videoSpecs.format == VideoFormat::raw) {
std::ofstream myFile;
myFile.open(videoSpecs.filename, std::ios::out | std::ios::binary); myFile.open(videoSpecs.filename, std::ios::out | std::ios::binary);
myFile.write((char*)&videoSpecs.width, 4); myFile.write((char*)&videoSpecs.width, 4);
myFile.write((char*)&videoSpecs.height, 4); myFile.write((char*)&videoSpecs.height, 4);
// Pylon::CVideoWriter videoWriter; } else {
// videoWriter.SetParameter(videoSpecs.width, videoSpecs.height, videoSpecs.pixelType, videoWriter.SetParameter(videoSpecs.width, videoSpecs.height, videoSpecs.pixelType, videoSpecs.fps, videoSpecs.quality);
// videoSpecs.fps, videoSpecs.quality); videoWriter.Open(videoSpecs.filename.c_str());
// 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::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::Block b = nix_file.createBlock("Recording", "nix.recording");
nix::Section s = nix_file.createSection("Recording", "nix.recording"); nix::Section s = nix_file.createSection("Recording", "nix.recording");
@ -84,24 +92,20 @@ void Writer::run() {
nix::NDSize chunk_shape(1, chunksize); 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(); if (videoSpecs.format == VideoFormat::raw) {
// framecount += 1;
myFile.write((char*)img->data(), img->size()); myFile.write((char*)img->data(), img->size());
} else {
// Pylon::CPylonImage pyImage; Pylon::CPylonImage pyImage;
// try { try {
// pyImage.AttachUserBuffer(img->data(), videoSpecs.width * videoSpecs.height, videoSpecs.pixelType, videoSpecs.width, videoSpecs.height, 0, videoSpecs.orientation); pyImage.AttachUserBuffer(img->data(), videoSpecs.width * videoSpecs.height, videoSpecs.pixelType, videoSpecs.width, videoSpecs.height, 0, videoSpecs.orientation);
// // Test duration of writing... videoWriter.Add(pyImage);
// videoWriter.Add( pyImage ); } catch (const Pylon::GenericException &e) {
std::cerr << "Writer::run: An exception occurred." << std::endl << e.GetDescription() << std::endl;
// } 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) { if (count < chunksize) {
stamps_buffer[count] = nix::util::timeToStr(img->timestamp()); stamps_buffer[count] = nix::util::timeToStr(img->timestamp());
ids_buffer[count] = img->index(); ids_buffer[count] = img->index();
@ -118,7 +122,7 @@ void Writer::run() {
} }
} else { } else {
while (buffer->bufferLoad() < 1 && !stop_request) { while (buffer->bufferLoad() < 1 && !stop_request) {
msleep(10); msleep(5);
} }
} }
} }

View File

@ -9,16 +9,18 @@
#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 { struct VideoSpecs {
std::string filename; std::string filename;
uint32_t width, height, quality = 10; uint32_t width, height, quality = 10;
uint32_t xoffset, yoffset = 0;
int fps; int fps;
double exposureTime; double exposureTime;
double detectorGain; double detectorGain;
Pylon::EPixelType pixelType; Pylon::EPixelType pixelType;
Pylon::EImageOrientation orientation; Pylon::EImageOrientation orientation;
VideoFormat format = VideoFormat::raw;
}; };
class Writer : public QThread class Writer : public QThread