diff --git a/BrainATUMtome/BrainATUMtome.pro b/BrainATUMtome/BrainATUMtome.pro index 8631ba4..99a9f10 100644 --- a/BrainATUMtome/BrainATUMtome.pro +++ b/BrainATUMtome/BrainATUMtome.pro @@ -29,14 +29,22 @@ SOURCES += \ driverepos.cpp \ driverserialport.cpp \ driversyringe.cpp \ - drivermicrotome.cpp + drivermicrotome.cpp \ + videoproducer.cpp \ + videoconverter.cpp \ + videoviewer.cpp \ + videowriter.cpp HEADERS += \ mainwindow.h \ driverepos.h \ driverserialport.h \ driversyringe.h \ - drivermicrotome.h + drivermicrotome.h \ + videoproducer.h \ + videoconverter.h \ + videoviewer.h \ + videowriter.h FORMS += \ mainwindow.ui diff --git a/BrainATUMtome/mainwindow.cpp b/BrainATUMtome/mainwindow.cpp index 6b98bf4..c3a89e3 100644 --- a/BrainATUMtome/mainwindow.cpp +++ b/BrainATUMtome/mainwindow.cpp @@ -108,6 +108,36 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->pushButton_dsy_pump, &QPushButton::clicked, m_driverSyringe, &DriverSyringe::on_uirequest_pump); + /* --- configure VideoProducer --- */ + m_videoProducer = new VideoProducer(nullptr); + m_thread_videoProducer = new QThread(this); + m_videoProducer->moveToThread(m_thread_videoProducer); + connect(m_thread_videoProducer, &QThread::finished, m_videoProducer, &VideoProducer::deleteLater); + m_thread_videoProducer->start(); + + + /* --- configure VideoConverter --- */ + m_videoConverter = new VideoConverter(nullptr); + m_thread_videoConverter = new QThread(this); + m_videoConverter->moveToThread(m_thread_videoConverter); + connect(m_thread_videoConverter, &QThread::finished, m_videoConverter, &VideoConverter::deleteLater); + m_thread_videoConverter->start(); + + /* --- configure VideoWriter --- */ + m_videoWriter = new VideoWriter(nullptr); + m_thread_videoWriter = new QThread(this); + m_videoWriter->moveToThread(m_thread_videoWriter); + connect(m_thread_videoWriter, &QThread::finished, m_videoWriter, &VideoWriter::deleteLater); + m_thread_videoWriter->start(); + + /* --- connect Video Signal/Slots --- */ + connect(ui->pushButton_dvs_record, &QPushButton::clicked, m_videoProducer, &VideoProducer::start); + connect(ui->pushButton_dvs_snap, &QPushButton::clicked, m_videoProducer, &VideoProducer::stop); + connect(m_videoProducer, &VideoProducer::frameReady, m_videoConverter, &VideoConverter::on_convertFrame); + connect(m_videoConverter, &VideoConverter::pixmapReady, ui->widget_videoViewer, &VideoViewer::on_pixmapReady); + + //connect(m_videoProducer, &VideoProducer::error, this, &MainWindow::on_error_throw); + //connect(m_videoWriter, &VideoWriter::error, this, &MainWindow::on_error_throw); } @@ -125,6 +155,18 @@ MainWindow::~MainWindow() m_thread_driverSyringe->quit(); m_thread_driverSyringe->wait(); + // destroy VideoProducer thread + m_thread_videoProducer->quit(); + m_thread_videoProducer->wait(); + + // destroy VideoConverter thread + m_thread_videoConverter->quit(); + m_thread_videoConverter->wait(); + + // destroy VideoWriter thread + m_thread_videoWriter->quit(); + m_thread_videoWriter->wait(); + delete ui; } @@ -202,3 +244,9 @@ void MainWindow::on_lineEdit_dep_velocity_returnPressed() command_DriverEpos(true); } + + +void MainWindow::on_error_throw(const QString &errorSource, const QString &errorMessage) +{ + qDebug() << errorSource << "::Error, " << errorMessage; +} diff --git a/BrainATUMtome/mainwindow.h b/BrainATUMtome/mainwindow.h index 19591e9..fd91415 100644 --- a/BrainATUMtome/mainwindow.h +++ b/BrainATUMtome/mainwindow.h @@ -9,6 +9,10 @@ #include "driverepos.h" #include "drivermicrotome.h" #include "driversyringe.h" +#include "videoproducer.h" +#include "videoconverter.h" +#include "videowriter.h" +#include "videoviewer.h" namespace Ui { class MainWindow; @@ -28,20 +32,23 @@ class MainWindow : public QMainWindow DriverEpos *m_driverEpos; DriverMicrotome *m_driverMicrotome; DriverSyringe *m_driverSyringe; + VideoProducer *m_videoProducer; + VideoConverter *m_videoConverter; + VideoWriter *m_videoWriter; QThread *m_thread_driverEpos; QThread *m_thread_driverMicrotome; QThread *m_thread_driverSyringe; - - - + QThread *m_thread_videoProducer; + QThread *m_thread_videoConverter; + QThread *m_thread_videoWriter; void command_DriverEpos(bool state); private slots: + void on_error_throw(const QString &errorSource, const QString &errorMessage); void on_pushButton_dep_run_clicked(); void on_pushButton_dmt_cut_clicked(); - void on_lineEdit_dep_velocity_returnPressed(); signals: diff --git a/BrainATUMtome/mainwindow.ui b/BrainATUMtome/mainwindow.ui index a4890de..4b41879 100644 --- a/BrainATUMtome/mainwindow.ui +++ b/BrainATUMtome/mainwindow.ui @@ -191,7 +191,7 @@ - + @@ -481,6 +481,14 @@ + + + VideoViewer + QWidget +
videoviewer.h
+ 1 +
+
diff --git a/BrainATUMtome/videoconverter.cpp b/BrainATUMtome/videoconverter.cpp new file mode 100644 index 0000000..683e47e --- /dev/null +++ b/BrainATUMtome/videoconverter.cpp @@ -0,0 +1,26 @@ +#include "videoconverter.h" + +VideoConverter::VideoConverter(QObject *parent) : QObject(parent) +{ + +} + +void VideoConverter::on_convertFrame(const cv::Mat &frame) +{ + cv::Mat frame_cv = frame; + QPixmap pixmap; + + cv::resize(frame_cv, frame_cv, cv::Size(), 0.5, 0.5, cv::INTER_AREA); + cv::cvtColor(frame_cv, frame_cv, CV_BGR2RGB); + const QImage frame_qt(frame_cv.data, + frame_cv.cols, + frame_cv.rows, + static_cast(frame_cv.step), + QImage::Format_RGB888); + + + pixmap = QPixmap::fromImage(frame_qt); + + //emit imageReady(frame_qt); + emit pixmapReady(pixmap); +} diff --git a/BrainATUMtome/videoconverter.h b/BrainATUMtome/videoconverter.h new file mode 100644 index 0000000..2e88751 --- /dev/null +++ b/BrainATUMtome/videoconverter.h @@ -0,0 +1,25 @@ +#ifndef VIDEOCONVERTER_H +#define VIDEOCONVERTER_H + +#include +#include +#include +#include + +class VideoConverter : public QObject +{ + Q_OBJECT + +public: + explicit VideoConverter(QObject *parent = nullptr); + +public slots: + void on_convertFrame(const cv::Mat &frame); + +signals: + //void imageReady(const QImage &frame); + void pixmapReady(const QPixmap &pixmap); + +}; + +#endif // VIDEOCONVERTER_H diff --git a/BrainATUMtome/videoproducer.cpp b/BrainATUMtome/videoproducer.cpp new file mode 100644 index 0000000..ec86091 --- /dev/null +++ b/BrainATUMtome/videoproducer.cpp @@ -0,0 +1,69 @@ +#include "videoproducer.h" + +VideoProducer::VideoProducer(QObject *parent) : QObject(parent), + m_frameIndex(0), + m_frameWidth(0), + m_frameHeight(0), + m_fps(0.0) +{ + qRegisterMetaType(); + + // configure state machine + m_producer = new QStateMachine(this); + QState *state_idle = new QState(m_producer); + QState *state_acquire = new QState(m_producer); + state_idle->addTransition(this, &VideoProducer::start, state_acquire); + state_acquire->addTransition(this, &VideoProducer::stop, state_idle); + state_acquire->addTransition(this, &VideoProducer::frameReady, state_acquire); + connect(state_acquire, &QState::entered, this, &VideoProducer::on_readFrame); + m_producer->setInitialState(state_idle); + m_producer->start(); + + // configure video capture + m_videoCapture = new cv::VideoCapture(0); + if (!m_videoCapture->isOpened()) + { + m_producer->stop(); + error("VideoProducer", "failed to open video capture device"); + return; + } + + // share frame properties + m_fps = m_videoCapture->get(CV_CAP_PROP_FPS); + m_frameWidth = static_cast(m_videoCapture->get(CV_CAP_PROP_FRAME_WIDTH)); + m_frameHeight = static_cast(m_videoCapture->get(CV_CAP_PROP_FRAME_HEIGHT)); + connect(this, &VideoProducer::start, [this](){emit frameProperties(m_fps, m_frameWidth, m_frameHeight);}); +} + + + +VideoProducer::~VideoProducer() +{ + if (m_producer->isRunning()) + m_producer->stop(); + + if (m_videoCapture->isOpened()) + m_videoCapture->release(); + delete m_videoCapture; +} + + + +void VideoProducer::on_readFrame() +{ + cv::Mat frame; + + QCoreApplication::processEvents(); + + if (!m_videoCapture->read(frame)) + { + m_producer->stop(); + error("VideoProducer", "failed to read next frame"); + return; + } + + m_frameIndex++; + + emit frameIndex(m_frameIndex); + emit frameReady(frame); +} diff --git a/BrainATUMtome/videoproducer.h b/BrainATUMtome/videoproducer.h new file mode 100644 index 0000000..dd24bf3 --- /dev/null +++ b/BrainATUMtome/videoproducer.h @@ -0,0 +1,40 @@ +#ifndef VIDEOPRODUCER_H +#define VIDEOPRODUCER_H + +#include +#include +#include +#include +#include + +class VideoProducer : public QObject +{ + Q_OBJECT + +public: + explicit VideoProducer(QObject *parent = nullptr); + ~VideoProducer(); + +private: + quint32 m_frameIndex; + qint32 m_frameWidth; + qint32 m_frameHeight; + double m_fps; + cv::VideoCapture *m_videoCapture; + QStateMachine *m_producer; + +private slots: + void on_readFrame(); + +signals: + void start(); + void stop(); + void frameIndex(quint32 index); + void frameReady(const cv::Mat &frame); + void frameProperties(double fps, int width, int height); + void error(const QString &errorSource, const QString &errorMessage); +}; + +Q_DECLARE_METATYPE(cv::Mat) + +#endif // VIDEOPRODUCER_H diff --git a/BrainATUMtome/videoviewer.cpp b/BrainATUMtome/videoviewer.cpp new file mode 100644 index 0000000..b23896e --- /dev/null +++ b/BrainATUMtome/videoviewer.cpp @@ -0,0 +1,15 @@ +#include "videoviewer.h" + +VideoViewer::VideoViewer(QWidget *parent) : QGraphicsView (parent) +{ + m_scene = new QGraphicsScene(this); + m_pixmap = new QGraphicsPixmapItem(); + this->setScene(m_scene); + m_scene->addItem(m_pixmap); +} + +void VideoViewer::on_pixmapReady(const QPixmap &pixmap) +{ + m_pixmap->setPixmap(pixmap); + this->fitInView(m_pixmap, Qt::KeepAspectRatio); +} diff --git a/BrainATUMtome/videoviewer.h b/BrainATUMtome/videoviewer.h new file mode 100644 index 0000000..5b4a3f0 --- /dev/null +++ b/BrainATUMtome/videoviewer.h @@ -0,0 +1,26 @@ +#ifndef VIDEOVIEWER_H +#define VIDEOVIEWER_H + +#include +#include +#include +#include +#include + +class VideoViewer : public QGraphicsView +{ + Q_OBJECT + +public: + explicit VideoViewer(QWidget *parent = nullptr); + +private: + QGraphicsScene *m_scene; + QGraphicsPixmapItem *m_pixmap; + +public slots: + void on_pixmapReady(const QPixmap &image); + +}; + +#endif // VIDEOVIEWER_H diff --git a/BrainATUMtome/videowriter.cpp b/BrainATUMtome/videowriter.cpp new file mode 100644 index 0000000..746ba1c --- /dev/null +++ b/BrainATUMtome/videowriter.cpp @@ -0,0 +1,41 @@ +#include "videowriter.h" + +VideoWriter::VideoWriter(QObject *parent) : QObject(parent), + m_flag(false) +{ + m_videoWriter = new cv::VideoWriter(); + + // construct file name based on current date and time +} + +VideoWriter::~VideoWriter() +{ + if (m_videoWriter->isOpened()) + m_videoWriter->release(); + delete m_videoWriter; +} + + +void VideoWriter::on_open(double fps, int width, int height) +{ + if (!m_flag) + return; + + QString filePath = QStandardPaths::displayName(QStandardPaths::DataLocation); + QString fileName = QDateTime::currentDateTime().toString("BrainATUMtome_yyyyMMdd-hhmmss"); + + QString fileFull = QString("%1%2.%3").arg(filePath, fileName, "avi"); + qDebug() << "Export file name " << fileFull; + m_videoWriter->open(fileFull.toStdString(), CV_FOURCC('M','J','P','G'), fps, cv::Size(width, height)); +} + + +void VideoWriter::on_export(bool flag) +{ + m_flag = flag; +} + +void VideoWriter::on_write(const cv::Mat &frame) +{ + m_videoWriter->write(frame); +} diff --git a/BrainATUMtome/videowriter.h b/BrainATUMtome/videowriter.h new file mode 100644 index 0000000..79d3b13 --- /dev/null +++ b/BrainATUMtome/videowriter.h @@ -0,0 +1,32 @@ +#ifndef VIDEOWRITER_H +#define VIDEOWRITER_H + +#include +#include +#include +#include +#include + +class VideoWriter : public QObject +{ + Q_OBJECT + +public: + explicit VideoWriter(QObject *parent = nullptr); + ~VideoWriter(); + +private: + bool m_flag; + cv::VideoWriter *m_videoWriter; + +public slots: + void on_export(bool flag); + void on_open(double fps, qint32 width, qint32 height); + void on_write(const cv::Mat &frame); + +signals: + void error(const QString &errorSource, const QString &errorMessage); + +}; + +#endif // VIDEOWRITER_H