New Status screen added, result processing pipeline started
This commit is contained in:
parent
7d15290a58
commit
f7ba865d6e
12 changed files with 326 additions and 21 deletions
13
femtoCAM.pro
13
femtoCAM.pro
|
|
@ -1,8 +1,8 @@
|
|||
QT += core gui
|
||||
QT += core gui charts
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
CONFIG += c++17
|
||||
CONFIG += c++25
|
||||
|
||||
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
|
||||
CONFIG += link_pkgconfig
|
||||
|
|
@ -16,16 +16,19 @@ SOURCES += \
|
|||
idscam.cpp \
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
processing.cpp
|
||||
processing.cpp \
|
||||
statsview.cpp
|
||||
|
||||
HEADERS += \
|
||||
framebatch.h \
|
||||
idscam.h \
|
||||
mainwindow.h \
|
||||
processing.h
|
||||
processing.h \
|
||||
statsview.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui
|
||||
mainwindow.ui \
|
||||
statsview.ui
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
|
|
|
|||
12
framebatch.h
12
framebatch.h
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <opencv4/opencv2/opencv.hpp>
|
||||
#include <QList>
|
||||
#include <QMutex>
|
||||
#include "arv.h"
|
||||
|
||||
struct Hit {
|
||||
|
|
@ -39,4 +40,15 @@ struct alignas(64) FrameBatch {
|
|||
int count = 0;
|
||||
};
|
||||
|
||||
struct BatchResult {
|
||||
ProcessingResult result[BATCHSIZE];
|
||||
quint64 frame_no[BATCHSIZE];
|
||||
quint64 hit_hist[10] = {};
|
||||
};
|
||||
|
||||
struct ResList {
|
||||
QList<BatchResult*> results;
|
||||
QMutex *resultMutex = new QMutex();
|
||||
};
|
||||
|
||||
#endif // FRAMEBATCH_H
|
||||
|
|
|
|||
14
idscam.cpp
14
idscam.cpp
|
|
@ -175,6 +175,18 @@ void IdsCam::buffer_polling()
|
|||
pending_n = callback_data.pendingData->length();
|
||||
}
|
||||
|
||||
quint64 batch_results_n;
|
||||
{
|
||||
QMutexLocker locker(results.resultMutex);
|
||||
batch_results_n = results.results.length();
|
||||
for(int i = 0; i < batch_results_n; i++)
|
||||
{
|
||||
BatchResult* cur = results.results.at(i);
|
||||
emit new_hist_av(cur->hit_hist);
|
||||
delete cur;
|
||||
}
|
||||
results.results.clear();
|
||||
}
|
||||
|
||||
if(fps_timer.elapsed() > 3000)
|
||||
{
|
||||
|
|
@ -212,7 +224,7 @@ void IdsCam::buffer_polling()
|
|||
QMutexLocker locker(callback_data.pendingMutex);
|
||||
batch_ptr = callback_data.pendingData->takeFirst();
|
||||
}
|
||||
Worker *w = new Worker(batch_ptr, callback_data.stream);
|
||||
Worker *w = new Worker(batch_ptr, callback_data.stream, &results);
|
||||
workers.start(w);
|
||||
}
|
||||
|
||||
|
|
|
|||
3
idscam.h
3
idscam.h
|
|
@ -67,9 +67,12 @@ private:
|
|||
|
||||
QThreadPool workers{};
|
||||
ProcessingConfig pro_cfg{};
|
||||
|
||||
ResList results{};
|
||||
signals:
|
||||
void new_status_text(QString text);
|
||||
void vis_new_frame(QImage img);
|
||||
void new_hist_av(quint64 hit_hist[10]);
|
||||
};
|
||||
|
||||
#endif // IDSCAM_H
|
||||
|
|
|
|||
|
|
@ -23,8 +23,11 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
|
||||
connect(ui->startButton, &QPushButton::clicked, this, &MainWindow::handle_start_button);
|
||||
|
||||
connect(ui->statsButton, &QPushButton::clicked, &stats, &StatsView::show);
|
||||
|
||||
connect(&cam, &IdsCam::new_status_text, ui->infotext, &QLabel::setText);
|
||||
connect(&cam, &IdsCam::vis_new_frame, this, &MainWindow::visualize_new_frame);
|
||||
connect(&cam, &IdsCam::new_hist_av, stats.histogramm, &BarChart::new_batch_data);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <QMainWindow>
|
||||
#include <QPixmap>
|
||||
#include "idscam.h"
|
||||
#include "statsview.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
|
|
@ -21,6 +22,8 @@ public:
|
|||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
StatsView stats;
|
||||
|
||||
IdsCam cam{};
|
||||
void handle_cam_selector(int i);
|
||||
void handle_pixel_format_selector(int i);
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@
|
|||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -48,10 +48,10 @@
|
|||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
|
|
@ -68,14 +68,14 @@
|
|||
<string>Camera Settings</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -85,7 +85,7 @@
|
|||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -161,7 +161,7 @@
|
|||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -177,16 +177,23 @@
|
|||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QPushButton" name="statsButton">
|
||||
<property name="text">
|
||||
<string>Stats</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
|
|||
|
|
@ -2,16 +2,27 @@
|
|||
|
||||
|
||||
|
||||
Worker::Worker(FrameBatch *batch, ArvStream *stream)
|
||||
:batch(batch), stream(stream)
|
||||
Worker::Worker(FrameBatch *batch, ArvStream *stream, ResList *result)
|
||||
:batch(batch), stream(stream), result(result)
|
||||
{
|
||||
}
|
||||
|
||||
void Worker::run()
|
||||
{
|
||||
batch_result = new BatchResult(); // Constructed as a pointer! Will need cleanup when done!
|
||||
for(int i=0; i<BATCHSIZE; i++)
|
||||
{
|
||||
ProcessingResult res = processArvBuffer(batch->frames[i], cfg);
|
||||
batch_result->result[i] = processArvBuffer(batch->frames[i], cfg);
|
||||
batch_result->frame_no[i] = batch->frame_no[i]; // TODO: a lot of optimisation could be done!
|
||||
|
||||
quint8 hits = std::min(batch_result->result[i].extended_data.length(), 10); // Max 10 hits in histogramm
|
||||
batch_result->hit_hist[hits]++;
|
||||
}
|
||||
|
||||
// Append Batch Result to Output Data - with mutex!
|
||||
{
|
||||
QMutexLocker locker(result->resultMutex);
|
||||
result->results.append(batch_result);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
|
|
|
|||
|
|
@ -26,12 +26,15 @@ QImage drawHitsOnGrayImage(const QImage& grayImage, const ProcessingResult& resu
|
|||
class Worker : public QRunnable
|
||||
{
|
||||
public:
|
||||
Worker(FrameBatch* batch, ArvStream *stream);
|
||||
Worker(FrameBatch* batch, ArvStream *stream, ResList *result);
|
||||
void run() override;
|
||||
private:
|
||||
FrameBatch* batch;
|
||||
ArvStream *stream;
|
||||
ProcessingConfig cfg{};
|
||||
ResList *result;
|
||||
BatchResult *batch_result = nullptr;
|
||||
|
||||
};
|
||||
|
||||
#endif // PROCESSING_H
|
||||
|
|
|
|||
97
statsview.cpp
Normal file
97
statsview.cpp
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
#include "statsview.h"
|
||||
#include "ui_statsview.h"
|
||||
|
||||
StatsView::StatsView(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::StatsView)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
connect(ui->closeButton, &QPushButton::clicked, this, &QDialog::close);
|
||||
|
||||
counts = new CountChart(ui->counts);
|
||||
histogramm = new BarChart(ui->histogramm);
|
||||
}
|
||||
|
||||
StatsView::~StatsView()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
CountChart::CountChart(QChartView *view)
|
||||
:chartView(view)
|
||||
{
|
||||
//series.append(0,6);
|
||||
//series.append(2,4);
|
||||
|
||||
chartView->chart()->addSeries(&series);
|
||||
axisX.setRange(0,10);
|
||||
axisY.setRange(0,10);
|
||||
axisX.setTitleText("Frame");
|
||||
axisY.setTitleText("Counts");
|
||||
|
||||
chartView->chart()->addAxis(&axisY, Qt::AlignLeft);
|
||||
chartView->chart()->addAxis(&axisX, Qt::AlignBottom);
|
||||
series.attachAxis(&axisX);
|
||||
series.attachAxis(&axisY);
|
||||
|
||||
chartView->chart()->legend()->hide();
|
||||
chartView->chart()->setTitle("Counts per Frame");
|
||||
}
|
||||
|
||||
BarChart::BarChart(QChartView *view)
|
||||
:chartView(view)
|
||||
{
|
||||
sets.append(new QBarSet{"Last batch"});
|
||||
sets.append(new QBarSet{"Avg. over batches"});
|
||||
|
||||
|
||||
QStringList categories;
|
||||
for(int i = 0; i<10; i++)
|
||||
{
|
||||
categories << QString("%1").arg(i);
|
||||
sets.barSets().at(0)->append(0);
|
||||
sets.barSets().at(1)->append(0);
|
||||
}
|
||||
categories.last() = "9+";
|
||||
|
||||
chartView->chart()->addSeries(&sets);
|
||||
chartView->chart()->setTitle("Distribution of Counts per frame");
|
||||
//chartView->chart()->setAnimationOptions(QChart::SeriesAnimations);
|
||||
|
||||
// Axis
|
||||
axisX.append(categories);
|
||||
chartView->chart()->addAxis(&axisX, Qt::AlignBottom);
|
||||
sets.attachAxis(&axisX);
|
||||
|
||||
axisY.setRange(0,100);
|
||||
chartView->chart()->addAxis(&axisY, Qt::AlignLeft);
|
||||
sets.attachAxis(&axisY);
|
||||
|
||||
chartView->chart()->legend()->setVisible(1);
|
||||
chartView->chart()->legend()->setAlignment(Qt::AlignBottom);
|
||||
}
|
||||
|
||||
void BarChart::new_batch_data(quint64 distr[10])
|
||||
{
|
||||
for(int i = 0; i<10; i++)
|
||||
{
|
||||
// New set
|
||||
sets.barSets().at(0)->remove(i);
|
||||
sets.barSets().at(0)->insert(i, distr[i]);
|
||||
|
||||
// Avg
|
||||
if(n_since_res == 0)
|
||||
{
|
||||
sets.barSets().at(1)->remove(i);
|
||||
sets.barSets().at(1)->insert(i, distr[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
float val = sets.barSets().at(1)->at(i);
|
||||
sets.barSets().at(1)->remove(i);
|
||||
sets.barSets().at(1)->insert(i, (val * n_since_res + (float)distr[i]) / (float)(n_since_res + 1) );
|
||||
}
|
||||
}
|
||||
n_since_res++;
|
||||
}
|
||||
60
statsview.h
Normal file
60
statsview.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#ifndef STATSVIEW_H
|
||||
#define STATSVIEW_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QChart>
|
||||
#include <QChartView>
|
||||
#include <QLineSeries>
|
||||
#include <QValueAxis>
|
||||
#include <QBarSeries>
|
||||
#include <QBarSet>
|
||||
#include <QBarCategoryAxis>
|
||||
|
||||
using namespace QtCharts;
|
||||
|
||||
namespace Ui {
|
||||
class StatsView;
|
||||
}
|
||||
|
||||
class CountChart : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CountChart(QChartView* view);
|
||||
private:
|
||||
QChartView* chartView = nullptr;
|
||||
QValueAxis axisX{};
|
||||
QValueAxis axisY{};
|
||||
QLineSeries series{};
|
||||
};
|
||||
|
||||
class BarChart : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
BarChart(QChartView* view);
|
||||
private:
|
||||
QChartView* chartView = nullptr;
|
||||
QBarCategoryAxis axisX{};
|
||||
QValueAxis axisY{};
|
||||
QBarSeries sets{};
|
||||
quint64 n_since_res = 0;
|
||||
public slots:
|
||||
void new_batch_data(quint64 distr[10]);
|
||||
};
|
||||
|
||||
class StatsView : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit StatsView(QWidget *parent = nullptr);
|
||||
~StatsView();
|
||||
CountChart *counts;
|
||||
BarChart *histogramm;
|
||||
|
||||
private:
|
||||
Ui::StatsView *ui;
|
||||
};
|
||||
|
||||
#endif // STATSVIEW_H
|
||||
91
statsview.ui
Normal file
91
statsview.ui
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>StatsView</class>
|
||||
<widget class="QDialog" name="StatsView">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>800</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QChartView" name="counts" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QChartView" name="histogramm" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonSettings">
|
||||
<property name="text">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonReset">
|
||||
<property name="text">
|
||||
<string>Reset Stats</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="closeButton">
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QChartView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>QtCharts</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Loading…
Add table
Add a link
Reference in a new issue