Compare commits

...

10 commits

Author SHA1 Message Date
uvos 0ddaa0bacd Make it more obvious when a image can be exported as a png and when not 2021-08-23 19:16:32 +02:00
uvos 5b07c96ce7 allow saveing main viewer image as png 2021-07-26 10:29:13 +02:00
uvos 6354b0379d add legeleese 2021-07-22 12:56:40 +02:00
uvos 24646e82ed improve kfactor support
add per camera gain
add the ability to save plot to vector pdf
add the ability to plot uint8_t mat types
2021-07-20 23:17:31 +02:00
uvos 1b6c3672b6 add kfactor support 2021-07-20 15:31:23 +02:00
uvos 7350c6ce96 Fix mistakes in cvimageviewer ploting and selection 2021-07-19 23:04:57 +02:00
uvos a9f263b22d Change lighting length to be based on when cameras report finished
Fix viewer handling when cammeras are available
2021-07-19 11:12:23 +02:00
uvos 65cdc7b78f Try not to change the current profile on profiles reload 2021-07-17 22:42:06 +02:00
uvos 3c788f57c2 Version Bump
Remember Save paths
add missing files
2021-07-17 22:24:44 +02:00
uvos 42da1746b5 Add 2d ploting for axis lines 2021-07-17 21:48:54 +02:00
46 changed files with 45478 additions and 196 deletions

View file

@ -11,8 +11,8 @@ set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets Concurrent REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Concurrent REQUIRED)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets Concurrent PrintSupport REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Concurrent PrintSupport REQUIRED)
find_package(OpenCV REQUIRED)
set(PROJECT_SOURCES
@ -53,12 +53,23 @@ set(PROJECT_SOURCES
src/ui/statisticsdialog.h
src/ui/statisticsdialog.cpp
src/ui/statisticsdialog.ui
src/ui/plot.cpp
src/ui/plot.h
src/qcustomplot/qcustomplot.h
src/qcustomplot/qcustomplot.cpp
src/regessioncalculator.h
src/regessioncalculator.cpp
src/ui/regressiondiag.h
src/ui/regressiondiag.cpp
src/ui/regressiondiag.ui
src/utilites.h
src/utilites.cpp
)
add_executable(MAClient ${PROJECT_SOURCES})
target_compile_options(MAClient PRIVATE "-std=gnu++17" "-Wall" "-O2" "-fno-strict-aliasing")
target_link_libraries(MAClient PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Concurrent ${OpenCV_LIBS} -luvoscam -luvosled -luvosunwrap)
target_link_libraries(MAClient PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Concurrent Qt${QT_VERSION_MAJOR}::PrintSupport ${OpenCV_LIBS} -luvoscam -luvosled -luvosunwrap)
target_include_directories(${PROJECT_NAME} PRIVATE ${OpenCV_INCLUDE_DIRS} src src/ui)
set(CMAKE_INSTALL_PREFIX "/usr")

View file

@ -6,9 +6,9 @@ Version=1.0
# The name of the application
Name=Lubricant Thickness Detector
# A comment which can/will be used as a tooltip
Comment=MAClient -sd 0 -t 30
Comment=MAClient
# The executable of the application, possibly with arguments.
Exec=MAClient
Exec=MAClient -sd 0 -t 30
# The name of the icon that will be used to display this entry
Icon=MAClient
# Describes whether this application needs to be run in a terminal or not

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "camera.h"
#include <QRandomGenerator>
#include <string>

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CAMERA_H
#define CAMERA_H

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "cameras.h"
#include <QRandomGenerator>
#include <string>
@ -157,13 +173,20 @@ void Cameras::trigger()
if(serial_)
{
if(captureingCamera == 0)
lightFor(lighting_, exposrueTime_*1.5*cameras_.size());
{
lightFor(lighting_, 10000);
qDebug()<<__func__<<"started";
std::this_thread::sleep_for(std::chrono::microseconds(static_cast<long>(exposrueTime_)));
}
cameras_[captureingCamera]->cam()->trigger();
++captureingCamera;
if(captureingCamera < cameras_.size())
QTimer::singleShot(exposrueTime_*1000, this, &Cameras::trigger);
else
{
captureingCamera = 0;
qDebug()<<__func__<<"finished";
}
}
else
{
@ -271,6 +294,7 @@ void Cameras::imageRecived(Camera::Image img)
if(images_.size() == cameras_.size())
{
lightOff();
cameraFailureTimer.stop();
newImages(images_);
images_.clear();
@ -300,9 +324,16 @@ double Cameras::getMeanTemp()
void Cameras::setSetup(const std::vector<CameraSetup>& setups)
{
for(auto& camera : cameras_)
{
for(auto& setup : setups)
{
if(camera->id() == setup.id)
{
camera->cam()->setBayerMode(setup.bayerMode);
camera->cam()->setGain(setup.gain);
}
}
}
}
void Cameras::store(QSettings &settings)

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CAMERAS_H
#define CAMERAS_H

View file

@ -1,4 +1,20 @@
#include "imagepipeline.h"
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "imagepipeline.h"
#include <uvosunwrap/unwrap.h>
#include <uvosunwrap/normalize.h>
#include <uvosunwrap/curve.h>
@ -7,6 +23,7 @@
#include <QDebug>
#include <algorithm>
#include <opencv2/highgui.hpp>
#include <math.h>
ImagePipeline::ImagePipeline(Cameras* cameras, bool simpleStichingAlg, QObject *parent):
QObject(parent), cameras_(cameras), simpleStichingAlg_(simpleStichingAlg)
@ -43,6 +60,19 @@ void ImagePipeline::applyDarkMap(cv::Mat& image, const cv::Mat& darkmap)
image = subtracted;
}
void ImagePipeline::sanityCheckMap(cv::Mat& mat)
{
for(int y = 0; y < mat.rows; y++)
{
float* col = mat.ptr<float>(y);
for(int x = 0; x < mat.cols; ++x)
{
if(isnan(col[x]) || isinf(col[x]))
col[x] = 0.5;
}
}
}
cv::Mat ImagePipeline::process(const Profile profile, std::vector<Camera::Image> images, bool simpleStichingAlg)
{
qDebug()<<__func__<<"got"<<images.size()<<"images";
@ -85,7 +115,12 @@ cv::Mat ImagePipeline::process(const Profile profile, std::vector<Camera::Image>
RemapedImage remaped = applyRemap(image.mat, camera.remapMap);
qDebug()<<"Camera"<<camera.id<<"image remaped to"<<remaped.image.data<<remaped.image.rows<<remaped.image.cols
<<"at"<<remaped.origin.x<<'x'<<remaped.origin.y;
remapedImages.push_back(applyRemap(image.mat, camera.remapMap));
RemapedImage remapedImage = applyRemap(image.mat, camera.remapMap);
if(profile.kFactor != 0 && remapedImage.image.type() == CV_8UC1)
applyKfactor(remapedImage.image, remapedImage.angle, profile.kFactor);
else if(profile.kFactor != 0)
qWarning()<<"Can not apply k factor due to image format";
remapedImages.push_back(remapedImage);
matched = true;
break;
}
@ -104,7 +139,8 @@ cv::Mat ImagePipeline::process(const Profile profile, std::vector<Camera::Image>
if(remapedImages.size() > 0)
{
std::sort(remapedImages.begin(), remapedImages.end(), [](const RemapedImage& imgA, const RemapedImage& imgB) -> bool {return imgA.origin.x < imgB.origin.x;});
std::sort(remapedImages.begin(), remapedImages.end(),
[](const RemapedImage& imgA, const RemapedImage& imgB) -> bool {return imgA.origin.x < imgB.origin.x;});
cv::Mat output;
if(simpleStichingAlg)
output = simpleStich(remapedImages);
@ -136,6 +172,9 @@ cv::Mat ImagePipeline::process(const Profile profile, std::vector<Camera::Image>
if(profile.calcurve.data)
applyCurve(output, profile.calcurve);
sanityCheckMap(output);
return output;
}
else

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef IMAGEPIPELINE_H
#define IMAGEPIPELINE_H
@ -23,6 +39,7 @@ private:
static cv::Mat process(const Profile profile, std::vector<Camera::Image> images, bool simpleStich);
static void applyDarkMap(cv::Mat& image, const cv::Mat &darkmap);
static void sanityCheckMap(cv::Mat& mat);
private slots:

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QApplication>
#include <uvoscam.h>
#include <QSettings>
@ -68,7 +84,7 @@ int main(int argc, char *argv[])
QCoreApplication::setOrganizationName("UVOS");
QCoreApplication::setOrganizationDomain("uvos.xyz");
QCoreApplication::setApplicationName("MAClient");
QCoreApplication::setApplicationVersion("0.1");
QCoreApplication::setApplicationVersion("0.5");
//parse comand line
QCommandLineParser parser;
@ -122,41 +138,44 @@ int main(int argc, char *argv[])
MainWindow w(parser.isSet(viewerOption));
QObject::connect(&cameras, &Cameras::cameraAdded, &w, &MainWindow::addCamera);
QObject::connect(&cameras, &Cameras::cameraRemoved, &w, &MainWindow::removeCamera);
QObject::connect(&cameras, &Cameras::enableCapture, &w, &MainWindow::enableCapture);
QObject::connect(&w, &MainWindow::sigCapture, [&cameras](){cameras.start(); cameras.trigger();});
QTimer temperatureTimer;
temperatureTimer.setSingleShot(false);
QObject::connect(&temperatureTimer, &QTimer::timeout, [&cameras, &w](){w.setTemperature(cameras.getMeanTemp());});
temperatureTimer.start(1000);
QObject::connect(&w, &MainWindow::sigChooseCameras, [&cameras, &w]()
if(!parser.isSet(viewerOption))
{
bool accepted;
std::vector<cam::Camera::Description> descs = showCameraSelectionDialog(&accepted, &w);
if(accepted)
cameras.setCameras(descs);
});
QObject::connect(&cameras, &Cameras::cameraAdded, &w, &MainWindow::addCamera);
QObject::connect(&cameras, &Cameras::cameraRemoved, &w, &MainWindow::removeCamera);
QObject::connect(&cameras, &Cameras::enableCapture, &w, &MainWindow::enableCapture);
QObject::connect(&w, &MainWindow::sigCapture, [&cameras](){cameras.start(); cameras.trigger();});
QObject::connect(&w, &MainWindow::sigEditProfiles, [&cameras, &w](){showProfileDialog(&cameras, &w); w.refreshProfiles();});
QObject::connect(&pipe, &ImagePipeline::sigResult, w.mainImageViewer(), &CvImageViewer::setImage, Qt::QueuedConnection);
QObject::connect(&pipe, &ImagePipeline::sigResult, [&w](){w.statusMsg("idle");});
QObject::connect(&pipe, &ImagePipeline::sigInvalidProfile, &w, &MainWindow::profileInconpatible);
QTimer temperatureTimer;
temperatureTimer.setSingleShot(false);
QObject::connect(&temperatureTimer, &QTimer::timeout, [&cameras, &w](){w.setTemperature(cameras.getMeanTemp());});
temperatureTimer.start(1000);
QObject::connect(&w, &MainWindow::sigProfile, [&pipe](QString name)
{
Profile profile;
profile.load(name);
if(profile.cameras.size() != 0)
qDebug()<<"loading profile"<<name<<"with"<<profile.cameras.size()<<"cameras and first camera"<<profile.cameras.at(0).id;
else
qDebug()<<"empty profile!!";
pipe.setProfile(profile);
});
QObject::connect(&w, &MainWindow::sigChooseCameras, [&cameras, &w]()
{
bool accepted;
std::vector<cam::Camera::Description> descs = showCameraSelectionDialog(&accepted, &w);
if(accepted)
cameras.setCameras(descs);
});
cameras.load(settings);
QObject::connect(&w, &MainWindow::sigEditProfiles, [&cameras, &w](){showProfileDialog(&cameras, &w); w.refreshProfiles();});
QObject::connect(&pipe, &ImagePipeline::sigResult, w.mainImageViewer(), &CvImageViewer::setImage, Qt::QueuedConnection);
QObject::connect(&pipe, &ImagePipeline::sigResult, [&w](){w.statusMsg("idle");});
QObject::connect(&pipe, &ImagePipeline::sigInvalidProfile, &w, &MainWindow::profileInconpatible);
QObject::connect(&w, &MainWindow::sigProfile, [&pipe](QString name)
{
Profile profile;
profile.load(name);
if(profile.cameras.size() != 0)
qDebug()<<"loading profile"<<name<<"with"<<profile.cameras.size()<<"cameras and first camera"<<profile.cameras.at(0).id;
else
qDebug()<<"empty profile!!";
pipe.setProfile(profile);
});
cameras.load(settings);
}
splash.hide();
w.show();
@ -183,8 +202,9 @@ int main(int argc, char *argv[])
}
ret = a.exec();
cameras.store(settings);
if(!parser.isSet(viewerOption))
cameras.store(settings);
}
if(uvosledRet >= 0)

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "profile.h"
#include <opencv2/imgcodecs.hpp>
#include <QStandardPaths>
@ -23,6 +39,7 @@ void CameraSetup::store(const QString &filename) const
matf<<("_"+QString::number(id)+"_bgmask").toStdString()<<bgmask;
}
matf<<("_"+QString::number(id)+"_bayermode").toStdString()<<bayerMode;
matf<<("_"+QString::number(id)+"_gain").toStdString()<<gain;
matf.release();
}
@ -38,6 +55,15 @@ void CameraSetup::load(const QString &filename, size_t cameraId)
matf[("_"+QString::number(id)+"_ymat").toStdString()]>>remapMap.yMat;
matf[("_"+QString::number(id)+"_origin").toStdString()]>>remapMap.topLeftCoordinate;
matf[("_"+QString::number(id)+"_bayermode").toStdString()]>>bayerMode;
try
{
matf[("_"+QString::number(id)+"_gain").toStdString()]>>gain;
}
catch(cv::Exception& e)
{
qWarning()<<"Profile dose not have gain";
gain = 1.0;
}
}
else
{
@ -66,6 +92,7 @@ void Profile::store(QSettings& settings) const
settings.setValue(GROUP + QString("/exposureTime"), exposureTime);
settings.setValue(GROUP + QString("/name"), name_);
settings.setValue(GROUP + QString("/nodistort"), nodistort);
settings.setValue(GROUP + QString("/kfact"), kFactor);
if(lightmap.data)
cv::imwrite((profileLocation() + QString::number(id) + ".lightmap.png").toStdString(), lightmap);
@ -97,6 +124,8 @@ void Profile::load(QSettings &settings)
name_ = settings.value(GROUP + QString("/name"), "NULL").toString();
nodistort = settings.value(GROUP + QString("/nodistort"), "NULL").toBool();
kFactor = settings.value(GROUP + QString("/kfact"), 0).toDouble();
lightmap = cv::imread((profileLocation() + QString::number(id) + ".lightmap.png").toStdString());
int size = settings.beginReadArray(GROUP + QString("/cameras"));

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PROFILE_H
#define PROFILE_H
#include <QSettings>
@ -18,6 +34,7 @@ public:
cv::Mat darkmap;
cv::Mat bgmask;
cam::Camera::BayerMode bayerMode = cam::Camera::BAYER_BLUE;
double gain = 1.0;
void store(const QString& filename) const;
void load(const QString& name, size_t cameraId);
};
@ -48,6 +65,7 @@ public:
cv::Mat calcurve;
std::vector<CameraSetup> cameras;
bool nodistort = false;
float kFactor = 0;
Profile(const QString& name = "");
void store(QSettings& settings) const;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,50 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "regessioncalculator.h"
#include <stdexcept>
#include <math.h>
#include <QDebug>
RegessionCalculator::RegessionCalculator(const std::vector<double>& xValues, const std::vector<double>& yValues)
{
if(xValues.size() == yValues.size())
{
this->xValues = xValues;
this->yValues = yValues;
double sumY = 0;
double sumX = 0;
double sumXTimesY = 0;
double sumSquaredX = 0;
double sumSquaredY = 0;
for (unsigned i = 0; i < xValues.size(); i++)
{
sumY += yValues[i];
sumX += xValues[i];
sumSquaredX += xValues[i]*xValues[i];
sumSquaredY += yValues[i]*yValues[i];
sumXTimesY += xValues[i]*yValues[i];
}
slope = (sumXTimesY - (sumX*sumY)/xValues.size()) / (sumSquaredX - (sumX*sumX)/xValues.size());
offset = sumY/xValues.size() - slope*(sumX/xValues.size());
double error = (xValues.size()*sumSquaredY-sumY*sumY-slope*slope*(xValues.size()*sumSquaredX-sumX*sumX)) / (xValues.size()*(xValues.size()-2));
stdError = sqrt( (error*error*xValues.size() ) / ( xValues.size()*sumSquaredX-sumX*sumX));
}
else throw std::invalid_argument("xValues and yValues need to be the same size");
}

35
src/regessioncalculator.h Normal file
View file

@ -0,0 +1,35 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version 3 as published by
* the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REGESSIONCALCULATOR_H
#define REGESSIONCALCULATOR_H
#include <vector>
class RegessionCalculator
{
public:
std::vector<double> xValues;
std::vector<double> yValues;
double slope;
double offset;
double stdError;
RegessionCalculator(const std::vector<double>& xValues, const std::vector<double>& yValues);
};
#endif // REGESSIONCALCULATOR_H

39
src/ui/aboutdiag.cpp Normal file
View file

@ -0,0 +1,39 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "aboutdiag.h"
#include "ui_aboutdiag.h"
#include <QPalette>
AboutDiag::AboutDiag(QWidget *parent) :
QDialog(parent),
ui(new Ui::AboutDiag)
{
ui->setupUi(this);
setFixedSize(size());
QPalette pal = palette();
pal.setColor(QPalette::Window, QColor(52,52,60));
pal.setColor(QPalette::WindowText, QColor(255,255,255));
pal.setColor(QPalette::Text, QColor(255,255,255));
setAutoFillBackground(true);
setPalette(pal);
}
AboutDiag::~AboutDiag()
{
delete ui;
}

38
src/ui/aboutdiag.h Normal file
View file

@ -0,0 +1,38 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ABOUTTELSYS_H
#define ABOUTTELSYS_H
#include <QDialog>
namespace Ui {
class AboutDiag;
}
class AboutDiag : public QDialog
{
Q_OBJECT
public:
explicit AboutDiag(QWidget *parent = 0);
~AboutDiag();
private:
Ui::AboutDiag *ui;
};
#endif // ABOUTTELSYS_H

85
src/ui/aboutdiag.ui Normal file
View file

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AboutDiag</class>
<widget class="QDialog" name="AboutDiag">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>812</width>
<height>315</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>80000</width>
<height>15200</height>
</size>
</property>
<property name="windowTitle">
<string>About</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>30</horstretch>
<verstretch>50</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>800</width>
<height>200</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../../res/resources.qrc">:/images/splash.png</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;UVOS MAClient Version: 0.5&lt;/span&gt;&lt;/p&gt;&lt;p&gt;© 2021 Carl Philipp Klemm&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="openExternalLinks">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../res/resources.qrc"/>
</resources>
<connections/>
</ui>

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "cameradialog.h"
#include "ui_cameradialog.h"
#include "../cameras.h"

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CAMERADIALOG_H
#define CAMERADIALOG_H

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "cameralistwidget.h"
#include <QDebug>
#include <QHeaderView>

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CAMERALISTWIDGET_H
#define CAMERALISTWIDGET_H

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "configurecameradialog.h"
#include "ui_configurecameradialog.h"
@ -51,6 +67,9 @@ ConfigureCameraDialog::ConfigureCameraDialog(const CameraSetup& setup, std::shar
break;
}
ui->doubleSpinBoxGain->setValue(setup_.gain);
camera_->cam()->setGain(setup_.gain);
camera_->cam()->setBayerMode(setup_.bayerMode);
uint64_t min, max;
@ -70,6 +89,7 @@ ConfigureCameraDialog::ConfigureCameraDialog(const CameraSetup& setup, std::shar
connect(ui->pushButtonBgShow, &QPushButton::clicked, [this](){if(setup_.bgmask.data) ui->widget_4->setImage(Camera::Image(setup_.bgmask, 0));});
connect(ui->pushButtonDarkImageShow, &QPushButton::clicked, [this](){if(setup_.darkmap.data) ui->widget_4->setImage(Camera::Image(setup_.darkmap, 0));});
connect(ui->comboBox_bayer, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ConfigureCameraDialog::bayerIndexChanged);
connect(ui->doubleSpinBoxGain, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &ConfigureCameraDialog::setExposure);
checkConfig();
}
@ -87,6 +107,15 @@ void ConfigureCameraDialog::setExposure(double value)
qDebug()<<"set exposure to "<<value*1000000.0;
}
void ConfigureCameraDialog::setGain(double value)
{
if(!camera_->cam()->setGain(value))
QMessageBox::warning(this, "Warning", "Failed to set exposure");
else
qDebug()<<"set gain to "<<value;
setup_.gain = value;
}
void ConfigureCameraDialog::bayerIndexChanged(int index)
{
switch(index)

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CONFIGURECAMERADIALOG_H
#define CONFIGURECAMERADIALOG_H
@ -36,6 +52,7 @@ private slots:
void takeImage();
void setExposure(double value);
void bayerIndexChanged(int index);
void setGain(double value);
public slots:
void accept() override;

View file

@ -31,13 +31,10 @@
<property name="horizontalSpacing">
<number>6</number>
</property>
<item row="1" column="4">
<widget class="QPushButton" name="pushButtonRemapClear">
<property name="enabled">
<bool>false</bool>
</property>
<item row="3" column="3">
<widget class="QPushButton" name="pushButtonBgCreate">
<property name="text">
<string>Clear</string>
<string>Create</string>
</property>
</widget>
</item>
@ -57,6 +54,33 @@
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QPushButton" name="pushButtonDarkImageCreate">
<property name="text">
<string>Create</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="pushButtonRemapClear">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="pushButtonDarkImageShow">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Show</string>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QPushButton" name="pushButtonDarkImageClear">
<property name="enabled">
@ -67,6 +91,27 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Dark image</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Remap Map (required)</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="pushButtonRemapCreate">
<property name="text">
<string>Create</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Led" name="ledDark" native="true">
<property name="sizePolicy">
@ -83,58 +128,6 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Background image</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="pushButtonBgCreate">
<property name="text">
<string>Create</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="pushButtonRemapCreate">
<property name="text">
<string>Create</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Dark image</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="pushButtonBgShow">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Show</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Remap Map (required)</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QPushButton" name="pushButtonDarkImageCreate">
<property name="text">
<string>Create</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Led" name="ledRemap" native="true">
<property name="sizePolicy">
@ -151,16 +144,6 @@
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="pushButtonDarkImageShow">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Show</string>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QPushButton" name="pushButtonBgClear">
<property name="enabled">
@ -171,6 +154,33 @@
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="pushButtonBgShow">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Show</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Background image</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Gain</string>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QDoubleSpinBox" name="doubleSpinBoxGain"/>
</item>
</layout>
</item>
<item>

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "cvimageviewer.h"
#include <QPicture>
#include <QDebug>
@ -10,22 +26,38 @@ CvImageViewer::CvImageViewer(QWidget *parent, size_t lastId) :
QWidget(parent),
lastId_(lastId),
saveAction_("Save Image", nullptr),
exportAction_("Export Image as PNG", nullptr),
zoomAction_("Zoom to selection", nullptr),
resetAction_("Reset Zoom", nullptr),
statisticsAction_("Get selection properties", nullptr),
xPlotAction_("Plot x axis", nullptr),
yPlotAction_("Plot y axis", nullptr),
roi_(0,0,0,0)
{
qimage_.load(":/images/noimage.png");
connect(&saveAction_, &QAction::triggered, this, &CvImageViewer::saveImage);
connect(&exportAction_, &QAction::triggered, this, &CvImageViewer::exportImage);
connect(&zoomAction_, &QAction::triggered, this, &CvImageViewer::zoomToSelection);
connect(&resetAction_, &QAction::triggered, this, &CvImageViewer::resetZoom);
connect(&statisticsAction_, &QAction::triggered, this, &CvImageViewer::showSatDiag);
connect(&xPlotAction_, &QAction::triggered, this, &CvImageViewer::plotOnX);
connect(&yPlotAction_, &QAction::triggered, this, &CvImageViewer::plotOnY);
imageContextMenu_.addAction(&saveAction_);
imageContextMenu_.addAction(&exportAction_);
imageContextMenu_.addAction(&zoomAction_);
imageContextMenu_.addAction(&resetAction_);
imageContextMenu_.addAction(&statisticsAction_);
imageContextMenu_.addAction(&xPlotAction_);
imageContextMenu_.addAction(&yPlotAction_);
plot.setMinimumWidth(800);
plot.setMinimumHeight(600);
plot.setWindowIcon(windowIcon());
plot.setWindowTitle(windowTitle());
setMouseTracking(true);
}
CvImageViewer::~CvImageViewer()
@ -34,39 +66,36 @@ CvImageViewer::~CvImageViewer()
void CvImageViewer::saveImage()
{
QString fileName;
if(origImage_.type() == CV_8UC3 || origImage_.type() == CV_8SC3 || origImage_.type() == CV_8UC1 || origImage_.type() == CV_8SC1)
{
fileName = QFileDialog::getSaveFileName(this, "Save Image", "./", "*.mat *.png" );
}
else
{
fileName = QFileDialog::getSaveFileName(this, "Save Image", "./", "*.mat" );
}
QString fileName = QFileDialog::getSaveFileName(this, "Save Image", lastSavePath_, "*.mat" );
if(!fileName.isEmpty())
{
lastSavePath_= fileName.mid(0, fileName.lastIndexOf('/'));
QStringList tokens = fileName.split('.');
if(tokens.back() != "mat" && tokens.back() != "png")
if(tokens.back() != "mat")
fileName.append(".mat");
tokens = fileName.split('.');
if(tokens.back() == "png")
{
imwrite(fileName.toStdString(), origImage_);
}
else
{
cv::FileStorage matf(fileName.toStdString(), cv::FileStorage::WRITE);
matf<<"image"<<origImage_;
matf.release();
}
cv::FileStorage matf(fileName.toStdString(), cv::FileStorage::WRITE);
matf<<"image"<<origImage_;
matf.release();
}
}
void CvImageViewer::showSatDiag()
void CvImageViewer::exportImage()
{
if(origImage_.channels() > 1 || selectionRect_.width() < 2 || selectionRect_.height() < 2)
if(!(origImage_.type() == CV_8UC3 || origImage_.type() == CV_8SC3 || origImage_.type() == CV_8UC1 || origImage_.type() == CV_8SC1))
return;
QString fileName = QFileDialog::getSaveFileName(this, "Save Image", lastSavePath_, "*.png" );
if(!fileName.isEmpty())
{
lastSavePath_= fileName.mid(0, fileName.lastIndexOf('/'));
QStringList tokens = fileName.split('.');
if(tokens.back() != "png")
fileName.append(".png");
imwrite(fileName.toStdString(), origImage_);
}
}
cv::Rect CvImageViewer::roiFromSelection()
{
int xA;
int yA;
int xB;
@ -74,9 +103,18 @@ void CvImageViewer::showSatDiag()
transfromToSourceCoordinates(selectionRect_.x(), selectionRect_.y(), xA, yA);
transfromToSourceCoordinates(selectionRect_.x()+selectionRect_.width(), selectionRect_.y()+selectionRect_.height(), xB, yB);
selectionRect_ = QRect(0, 0, 0, 0);
cv::Rect roi(xA, yA, xB-xA, yB-yA);
cv::Rect roi;
roi = cv::Rect(std::min(xA, xB), std::min(yA, yB), std::abs(xA-xB), std::abs(yA-yB));
return roi;
}
cv::Mat roiImage = origImage_(roi);
void CvImageViewer::showSatDiag()
{
qDebug()<<selectionRect_.width()<<selectionRect_.height();
if(!origImage_.data || origImage_.channels() > 1 || abs(selectionRect_.width()) < 2 || abs(selectionRect_.height()) < 2)
return;
cv::Mat roiImage = origImage_(roiFromSelection());
if(roiImage.type() != CV_64FC1)
roiImage.convertTo(roiImage, CV_64FC1);
@ -92,10 +130,13 @@ void CvImageViewer::showSatDiag()
void CvImageViewer::setClamp(double max)
{
clamp_ = max;
convertImage(origImage_);
update();
roi_ = cv::Rect(0, 0, image_.size().width, image_.size().height);
if(origImage_.data)
{
clamp_ = max;
convertImage(origImage_);
update();
roi_ = cv::Rect(0, 0, image_.size().width, image_.size().height);
}
}
void CvImageViewer::convertImage(cv::Mat image)
@ -105,11 +146,17 @@ void CvImageViewer::convertImage(cv::Mat image)
{
qimage_ = QImage(image_.data, image_.cols, image_.rows, image_.step, QImage::Format_RGB888);
statisticsAction_.setDisabled(true);
xPlotAction_.setDisabled(true);
yPlotAction_.setDisabled(true);
exportAction_.setDisabled(false);
}
else if(image_.type() == CV_8UC1 || image_.type() == CV_8SC1)
{
qimage_ = QImage(image_.data, image_.cols, image_.rows, image_.step, QImage::Format_Grayscale8);
statisticsAction_.setDisabled(false);
xPlotAction_.setDisabled(false);
yPlotAction_.setDisabled(false);
exportAction_.setDisabled(false);
}
else if(image_.type() == CV_32FC1 || image_.type() == CV_64FC1)
{
@ -128,6 +175,9 @@ void CvImageViewer::convertImage(cv::Mat image)
image_.convertTo(image_, CV_8UC1, a, b);
qimage_ = QImage(image_.data, image_.cols, image_.rows, image_.step, QImage::Format_Grayscale8);
statisticsAction_.setDisabled(false);
xPlotAction_.setDisabled(false);
yPlotAction_.setDisabled(false);
exportAction_.setDisabled(true);
}
else if(image_.type() == CV_32FC3 || image_.type() == CV_64FC3)
{
@ -142,18 +192,25 @@ void CvImageViewer::convertImage(cv::Mat image)
image_.convertTo(image_, CV_8UC3, a, b);
qimage_ = QImage(image_.data, image_.cols, image_.rows, image_.step, QImage::Format_Grayscale8);
statisticsAction_.setDisabled(true);
xPlotAction_.setDisabled(true);
yPlotAction_.setDisabled(true);
exportAction_.setDisabled(true);
}
else
{
image_.convertTo(image_, CV_8UC1, 255, 0);
qimage_ = QImage(image_.data, image_.cols, image_.rows, image_.step, QImage::Format_Grayscale8);
statisticsAction_.setDisabled(true);
statisticsAction_.setDisabled(false);
xPlotAction_.setDisabled(false);
yPlotAction_.setDisabled(false);
exportAction_.setDisabled(false);
}
}
void CvImageViewer::setImage(Camera::Image img)
{
origImage_=img.mat;
clamp_ = std::numeric_limits<double>::max();
qDebug()<<"viwer got"<<image_.rows<<'x'<<image_.cols<<" type "<<image_.type()<<"image from camera"<<img.cameraId;
convertImage(img.mat);
update();
@ -178,17 +235,10 @@ void CvImageViewer::resetZoom()
void CvImageViewer::zoomToSelection()
{
if(selectionRect_.width() > 2 && selectionRect_.height() > 2)
if(abs(selectionRect_.width()) > 2 && abs(selectionRect_.height()) > 2)
{
convertImage(origImage_);
int xA;
int yA;
int xB;
int yB;
transfromToSourceCoordinates(selectionRect_.x(), selectionRect_.y(), xA, yA);
transfromToSourceCoordinates(selectionRect_.x()+selectionRect_.width(), selectionRect_.y()+selectionRect_.height(), xB, yB);
selectionRect_ = QRect(0, 0, 0, 0);
roi_ = cv::Rect(xA, yA, xB-xA, yB-yA);
roi_ = roiFromSelection();
cv::Mat cropped;
cropped = image_(roi_);
convertImage(cropped);
@ -196,6 +246,78 @@ void CvImageViewer::zoomToSelection()
}
}
void CvImageViewer::plotOnX()
{
if(!xLine_.isNull() && origImage_.data && (origImage_.type() == CV_32FC1 || origImage_.type() == CV_64FC1 || origImage_.type() == CV_8UC1))
{
cv::Mat plotImage;
if(origImage_.type() == CV_8UC1)
origImage_.convertTo(plotImage, CV_32FC1);
else
plotImage = origImage_;
plot.clear();
QVector<double> keys;
QVector<double> values;
int x, y;
transfromToSourceCoordinates(xLine_.p1().x(), xLine_.p1().y(), x, y);
double max = 0;
for(int i = 0; i < plotImage.cols; ++i)
{
keys.push_back(i);
double value;
if(plotImage.type() == CV_32FC1)
value = plotImage.at<float>(y, i);
else
value = plotImage.at<double>(y, i);
if(max < value)
max = value;
values.push_back(value);
}
plot.setMaxValue(max);
plot.addData(keys, values, true);
plot.show();
plot.repaint();
}
}
void CvImageViewer::plotOnY()
{
if(!xLine_.isNull() && origImage_.data && (origImage_.type() == CV_32FC1 || origImage_.type() == CV_64FC1 || origImage_.type() == CV_8UC1))
{
cv::Mat plotImage;
if(origImage_.type() == CV_8UC1)
origImage_.convertTo(plotImage, CV_32FC1);
else
plotImage = origImage_;
plot.clear();
QVector<double> keys;
QVector<double> values;
int x, y;
transfromToSourceCoordinates(yLine_.p1().x(), yLine_.p1().y(), x, y);
double max = 0;
for(int i = 0; i < plotImage.rows; ++i)
{
keys.push_back(i);
double value;
if(plotImage.type() == CV_32FC1)
value = plotImage.at<float>(i, x);
else
value = plotImage.at<double>(i, x);
if(max < value)
max = value;
values.push_back(value);
}
plot.setMaxValue(max);
plot.addData(keys, values, true);
plot.show();
plot.repaint();
}
}
void CvImageViewer::mousePressEvent(QMouseEvent *event)
{
if(origImage_.data)
@ -229,14 +351,35 @@ void CvImageViewer::mousePressEvent(QMouseEvent *event)
void CvImageViewer::mouseMoveEvent(QMouseEvent *event)
{
if(selectionStarted_)
if(origImage_.data && event->x() > imgrect_.x() && event->y() > imgrect_.y() && event->x() < imgrect_.x()+imgrect_.width() && event->y() < imgrect_.y()+imgrect_.height())
{
if(event->x() > imgrect_.x() && event->y() > imgrect_.y() && event->x() < imgrect_.x()+imgrect_.width() && event->y() < imgrect_.y()+imgrect_.height())
if(selectionStarted_)
{
selectionRect_.setBottomRight(event->pos());
repaint();
}
xLine_ = QLine(imgrect_.x(), event->y(), imgrect_.x()+imgrect_.width(), event->y());
yLine_ = QLine(event->x(), imgrect_.y(), event->x(), imgrect_.y()+imgrect_.height());
repaint();
}
else if(!xLine_.isNull() || !selectionRect_.isNull())
{
xLine_ = QLine();
yLine_ = QLine();
selectionRect_ = QRect();
repaint();
}
}
void CvImageViewer::leaveEvent(QEvent *event)
{
if((!xLine_.isNull() || !selectionRect_.isNull()) && !imageContextMenu_.isActiveWindow() )
{
xLine_ = QLine();
yLine_ = QLine();
selectionRect_ = QRect();
repaint();
}
QWidget::leaveEvent(event);
}
void CvImageViewer::mouseReleaseEvent(QMouseEvent *event)
@ -263,7 +406,10 @@ void CvImageViewer::paintEvent(QPaintEvent* event)
imgrect_.setRect((rect().width()-rect().height()/ratio)/2, 0, rect().height()/ratio, rect().height());
painter.drawImage(imgrect_, qimage_);
painter.setPen(QPen(QBrush(QColor(0,0,0,180)),1,Qt::DashLine));
painter.setPen(QPen(QBrush(QColor(200,200,255,255)),1,Qt::DashLine));
painter.drawLine(xLine_);
painter.drawLine(yLine_);
painter.setPen(Qt::NoPen);
painter.setBrush(QBrush(QColor(255,255,255,120)));
painter.drawRect(selectionRect_);
}

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CVIMAGEVIEWER_H
#define CVIMAGEVIEWER_H
@ -7,6 +23,7 @@
#include <QSlider>
#include <limits>
#include "../cameras.h"
#include "plot.h"
class CvImageViewer : public QWidget
{
@ -19,24 +36,35 @@ private:
bool fixedOnWidth_ = false;
size_t lastId_;
QMenu imageContextMenu_;
Plot plot;
QAction saveAction_;
QAction exportAction_;
QAction zoomAction_;
QAction resetAction_;
QAction statisticsAction_;
QAction xPlotAction_;
QAction yPlotAction_;
QRect imgrect_;
cv::Rect roi_;
QRect selectionRect_;
QLine xLine_;
QLine yLine_;
bool selectionStarted_ = false;
double clamp_ = std::numeric_limits<double>::max();
inline static QString lastSavePath_ = "./";
void transfromToSourceCoordinates(int inX, int inY, int& outX, int& outY);
void convertImage(cv::Mat image);
cv::Rect roiFromSelection();
private slots:
void saveImage();
void exportImage();
void zoomToSelection();
void resetZoom();
void showSatDiag();
void plotOnX();
void plotOnY();
protected:
virtual void paintEvent(QPaintEvent* event) override;
@ -44,6 +72,7 @@ protected:
virtual void mouseMoveEvent(QMouseEvent *event) override;
virtual void mouseReleaseEvent(QMouseEvent *event) override;
virtual void resizeEvent(QResizeEvent *event) override;
virtual void leaveEvent(QEvent *event) override;
signals:
void sigValue(size_t x, size_t y, double value);
@ -63,3 +92,4 @@ public:
};
#endif // CVIMAGEVIEWER_H

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "editprofiledialog.h"
#include "ui_editprofiledialog.h"
#include <uvosled.h>
@ -20,6 +36,7 @@ EditProfileDialog::EditProfileDialog(Cameras* cameras, const Profile profile, QW
ui->lineEditName->setText(name);
ui->doubleSpinBoxBrightness->setValue(profile_.lighting.brightness*100.0);
ui->doubleSpinBoxExposure->setValue(profile_.exposureTime);
ui->doubleSpinBox_kFactor->setValue(profile_.kFactor);
qDebug()<<"Mask: "<<profile_.lighting.mask<<" & "<<(profile_.lighting.mask & CHANNEL_A);
@ -50,6 +67,7 @@ EditProfileDialog::EditProfileDialog(Cameras* cameras, const Profile profile, QW
connect(ui->doubleSpinBoxBrightness, QOverload<double>::of(&QDoubleSpinBox::valueChanged), [this](double in){profile_.lighting.brightness = in/100.0;});
connect(ui->doubleSpinBoxExposure, QOverload<double>::of(&QDoubleSpinBox::valueChanged), [this](double in){profile_.exposureTime = in;});
connect(ui->doubleSpinBox_kFactor, QOverload<double>::of(&QDoubleSpinBox::valueChanged), [this](double in){profile_.kFactor = in;});
connect(ui->lineEditName, &QLineEdit::textChanged, [this](QString in){profile_.setName(in);});
connect(ui->checkBoxCh1, &QCheckBox::clicked, this, &EditProfileDialog::setMask);
connect(ui->checkBoxCh2, &QCheckBox::clicked, this, &EditProfileDialog::setMask);

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EDDITPROFILEDIALOG_H
#define EDDITPROFILEDIALOG_H

View file

@ -192,25 +192,35 @@
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<property name="topMargin">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>k factor:</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBox_kFactor">
<property name="minimum">
<double>-100.000000000000000</double>
</property>
<property name="maximum">
<double>100.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<property name="topMargin">
<number>10</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Calibration curve:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Lightmap:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Led" name="calLed" native="true">
<property name="sizePolicy">
@ -227,6 +237,20 @@
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="pushButtonLightmapLoad">
<property name="text">
<string>Load</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Lightmap:</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="pushButtonCalLoad">
<property name="sizePolicy">
@ -240,10 +264,17 @@
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="pushButtonLightmapLoad">
<item row="0" column="3">
<widget class="QPushButton" name="pushButtonCalClear">
<property name="text">
<string>Load</string>
<string>Clear</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Calibration curve:</string>
</property>
</widget>
</item>
@ -263,13 +294,6 @@
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="pushButtonCalClear">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="pushButtonLightmapClear">
<property name="text">

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "led.h"
#include <QPainter>

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LED_H
#define LED_H

View file

@ -1,9 +1,27 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QDebug>
#include <QMessageBox>
#include <uvosled.h>
#include <QFileDialog>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include "../profile.h"
@ -55,9 +73,10 @@ void MainWindow::saveImage()
return;
}
QString fileName = QFileDialog::getSaveFileName(this, "Save Image", "./", "*.mat");
QString fileName = QFileDialog::getSaveFileName(this, "Save Image", lastSavedPath_, "*.mat");
if(!fileName.isEmpty())
{
lastSavedPath_= fileName.mid(0, fileName.lastIndexOf('/'));
QStringList tokens = fileName.split('.');
if(tokens.back() != "mat")
fileName.append(".mat");
@ -69,33 +88,47 @@ void MainWindow::saveImage()
void MainWindow::openImage()
{
QString fileName = QFileDialog::getOpenFileName(this, "Open Image", "./", "*.mat");
QString fileName = QFileDialog::getOpenFileName(this, "Open Image", lastSavedPath_, "*.mat *.png");
if(!fileName.isEmpty())
{
cv::Mat image;
cv::FileStorage matf(fileName.toStdString(), cv::FileStorage::READ);
try
QStringList tokens = fileName.split('.');
if(tokens.back() == "png")
{
matf["image"]>>image;
image = cv::imread(fileName.toStdString());
if(image.data && image.channels() == 3)
cv::cvtColor(image, image, cv::COLOR_BGR2GRAY);
image.convertTo(image, CV_32FC1, 1.0/255.0, 0);
}
catch(const cv::Exception& ex)
else
{
qDebug()<<ex.what();
QMessageBox::warning(this, "Invalid file", "File selected dose not contain a valid image");
return;
}
cv::FileStorage matf(fileName.toStdString(), cv::FileStorage::READ);
try
{
matf["image"]>>image;
}
catch(const cv::Exception& ex)
{
qDebug()<<ex.what();
QMessageBox::warning(this, "Invalid file", "File selected dose not contain a valid image");
return;
}
if(matf.isOpened() && (!image.data || image.type() != CV_32FC1))
{
image.release();
QMessageBox::warning(this, "Invalid file", "File selected dose not contain a valid image");
if(matf.isOpened() && !image.data)
{
image.release();
QMessageBox::warning(this, "Invalid file", "File selected dose not contain a valid image");
}
matf.release();
}
else if(!image.data)
if(!image.data)
{
QMessageBox::warning(this, "Can no open", "Can not open file selected");
}
matf.release();
ui->mainViewer->setImage(Camera::Image(image, 0));
else
{
ui->mainViewer->setImage(Camera::Image(image, 0));
}
}
}
@ -166,6 +199,7 @@ void MainWindow::refreshProfiles()
QList<QString> profiles = Profile::avaiableProfiles();
for(const QString& string : profiles)
ui->comboBox->addItem(string);
setProfile(tmp);
}
void MainWindow::profileInconpatible(QString message)

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
@ -16,7 +32,8 @@ class MainWindow : public QMainWindow
Q_OBJECT
private:
std::vector<CvImageViewer*> viewers_;
AboutDiag about_;
AboutDiag about_;
inline static QString lastSavedPath_ = "./";
private slots:
void setImageValue(size_t x, size_t y, double value);

308
src/ui/plot.cpp Normal file
View file

@ -0,0 +1,308 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "plot.h"
#include <QKeySequence>
#include <QFont>
#include "statisticsdialog.h"
#include "regressiondiag.h"
Plot::Plot(QWidget* parent):
QCustomPlot(parent),
actionStatistics("Show statistics", nullptr),
actionAdd_Regression("Add regression", nullptr),
actionDelete_Regression("Delete regression", nullptr),
actionExport_Selection("Export selection", nullptr),
actionSetValueString("Set Y Axis Label", nullptr),
savePdfAction("Save to pdf", nullptr)
{
xAxis->setLabel("Coordinate");
yAxis->setLabel("Counts");
xAxis->setRange(0, 10);
yAxis->setRange(0, 65535);
addMainGraph();
setInteraction(QCP::iSelectPlottables, true);
setInteraction(QCP::iRangeDrag, true);
setInteraction(QCP::iRangeZoom);
axisRect()->setRangeDrag(Qt::Horizontal);
axisRect()->setRangeZoom(Qt::Horizontal);
setSelectionRectMode(QCP::srmNone);
//setup actions
actionStatistics.setShortcut(Qt::Key_S);
actionStatistics.setShortcutVisibleInContextMenu(true);
addAction(&actionStatistics);
actionAdd_Regression.setShortcut(Qt::Key_R);
actionAdd_Regression.setShortcutVisibleInContextMenu(true);
addAction(&actionAdd_Regression);
actionDelete_Regression.setShortcut(Qt::Key_Delete);
actionDelete_Regression.setShortcutVisibleInContextMenu(true);
addAction(&actionDelete_Regression);
actionExport_Selection.setShortcut(Qt::CTRL + Qt::Key_E);
actionExport_Selection.setShortcutVisibleInContextMenu(true);
addAction(&actionExport_Selection);
//graph context menu
connect(&actionStatistics, &QAction::triggered, this, &Plot::showStatistics);
connect(&actionAdd_Regression, &QAction::triggered, this, &Plot::addRegression);
connect(&actionDelete_Regression, &QAction::triggered, this, &Plot::deleteRegression);
connect(&actionExport_Selection, &QAction::triggered, this, &Plot::saveCsvDiag);
connect(&actionSetValueString, &QAction::triggered, this, &Plot::askForValueString);
connect(&savePdfAction, &QAction::triggered, this, &Plot::savePdf);
graphContextMenu.addAction(&actionStatistics);
graphContextMenu.addAction(&actionAdd_Regression);
graphContextMenu.addAction(&actionDelete_Regression);
graphContextMenu.addAction(&actionExport_Selection);
graphContextMenu.addAction(&actionSetValueString);
graphContextMenu.addAction(&savePdfAction);
}
Plot::~Plot()
{
}
void Plot::savePdf()
{
QString fileName = QFileDialog::getSaveFileName(this, "Save graph as PDF", "./", "*.pdf" );
if(!fileName.isEmpty())
QCustomPlot::savePdf(fileName);
}
bool Plot::event(QEvent *event)
{
if(event->type()==QEvent::Gesture) graphContextMenu.show();
return QCustomPlot::event(event);
}
void Plot::setLabel(QString label)
{
yAxis->setLabel(label);
}
void Plot::addMainGraph()
{
addGraph();
graph(graphCount()-1)->setSelectable(QCP::stDataRange);
graph(graphCount()-1)->setPen(QPen(QBrush(QColor(0,0,255,255)),2,Qt::SolidLine));
QPen selectionPen = graph(graphCount()-1)->pen();
selectionPen.setColor(QColor(255,0,0));
graph(graphCount()-1)->selectionDecorator()->setPen(selectionPen);
}
void Plot::clear()
{
clearGraphs();
addMainGraph();
xAxis->setRange(0, 10);
replot();
}
void Plot::askForValueString()
{
bool ok = false;
QString label = QInputDialog::getText(this, "Y Axis Label", "New Label:", QLineEdit::Normal, yAxis->label(), &ok);
if(ok)
{
setLabel(label);
replot();
}
}
void Plot::setMaxValue(double maxVal)
{
yAxis->setRange(0, maxVal);
}
void Plot::saveCsvDiag()
{
if(graphCount() > 0 && !graph(0)->selection().dataRanges().at(0).isEmpty())
{
QString fileName = QFileDialog::getSaveFileName(this, "Save selection as CSV", "./", "*.csv" );
saveCsv(fileName);
}
else QMessageBox::warning(this, "Warning", "No selection has been made", QMessageBox::Ok);
}
void Plot::saveCsv(QString fileName)
{
if(!fileName.isEmpty())
{
QCPDataRange range = graph(0)->selection().dataRanges().at(0);
QCPGraphDataContainer::const_iterator begin = graph(0)->data()->at(range.begin());
QCPGraphDataContainer::const_iterator end = graph(0)->data()->at(range.end());
std::vector<double> keys;
keys.resize(end-begin);
std::vector<double> values;
values.resize(end-begin);
for (QCPGraphDataContainer::const_iterator item=begin; item != end; ++item)
{
keys[item-begin]=item->key;
values[item-begin]=item->value;
}
saveToCsv(fileName, keys, values, xAxis->label(), yAxis->label());
}
}
void Plot::addRegression()
{
if(graphCount() > 0 && !graph(0)->selection().dataRanges().at(0).isEmpty())
{
QCPDataRange range = graph(0)->selection().dataRanges().at(0);
QCPGraphDataContainer::const_iterator begin = graph(0)->data()->at(range.begin());
QCPGraphDataContainer::const_iterator end = graph(0)->data()->at(range.end());
std::vector<double> values;
std::vector<double> keys;
values.resize(end-begin);
keys.resize(end-begin);
for (QCPGraphDataContainer::const_iterator item=begin; item != end; ++item)
{
values[item-begin] = item->value;
keys[item-begin] = item->key;
}
regressions.push_back(RegessionCalculator(keys, values));
QPen regressionPen =graph(0)->pen();
regressionPen.setColor(QColor(0,255,0));
QPen selectionPen = graph(0)->pen();
selectionPen.setColor(QColor(255,0,0));
QCPGraphDataContainer::const_iterator center = begin + (end - begin)/2;
addGraph();
graph(graphCount()-1)->setPen(regressionPen);
graph(graphCount()-1)->addData(100+center->key, regressions.back().slope*(100+center->key) + regressions.back().offset);
graph(graphCount()-1)->addData(-100+center->key, regressions.back().slope*(-100+center->key) + regressions.back().offset);
graph(graphCount()-1)->selectionDecorator()->setPen(selectionPen);
replot();
}
else QMessageBox::warning(this, "Warning", "No selection has been made", QMessageBox::Ok);
}
void Plot::deleteRegression()
{
if(graphCount() > 0 && selectedGraphs().size() > 1 && selectedGraphs().at(1) != graph(0))
{
int i = 0;
while(selectedGraphs().at(1) != graph(i) ) i++;
regressions.erase(regressions.begin()+i-1);
removeGraph(selectedGraphs().at(1));
replot();
}
}
void Plot::showStatistics()
{
if(graphCount() > 0 && !graph(0)->selection().dataRanges().isEmpty() && !graph(0)->selection().dataRanges().at(0).isEmpty())
{
QCPDataRange dataRange = graph(0)->selection().dataRanges().at(0);
QCPGraphDataContainer::const_iterator begin = graph(0)->data()->at(dataRange.begin());
QCPGraphDataContainer::const_iterator end = graph(0)->data()->at(dataRange.end());
std::vector<double> dataVct;
dataVct.reserve(dataRange.size());
for (QCPGraphDataContainer::const_iterator item = begin; item != end; item++)
dataVct.push_back(item->value);
StatisticsDialog statDiag(dataVct, this);
statDiag.show();
statDiag.exec();
}
else if(graphCount() > 0 && selectedGraphs().size() > 0 && selectedGraphs().at(0) != graph(0))
{
unsigned i = 0;
while(selectedGraphs().at(0) != graph(i)) i++;
RegressionDiag regDiag(regressions.at(i-1), this);
regDiag.show();
regDiag.exec();
}
else QMessageBox::warning(this, "Warning", "No selection has been made", QMessageBox::Ok);
}
void Plot::addData(QVector<double> keys, QVector<double> values, bool inOrder, bool ignoreLimit)
{
if(graphCount() > 0)
{
graph(0)->addData(keys, values, inOrder);
if(!ignoreLimit)while(graph(0)->data()->size() > graphPointLimit) graph(0)->data()->remove(graph(0)->data()->begin()->key);
xAxis->setRange( graph(0)->data()->begin()->key, keys.back() );
replot();
}
}
void Plot::addData(double key, double value, bool ignoreLimit)
{
if(graphCount() > 0)
{
graph(0)->addData(key, value);
if(!ignoreLimit)while(graph(0)->data()->size() > graphPointLimit) graph(0)->data()->remove(graph(0)->data()->begin()->key);
xAxis->setRange( graph(0)->data()->begin()->key, key );
}
}
void Plot::setLimit(int graphPointLimit)
{
this->graphPointLimit = graphPointLimit;
if(graphCount() > 0) while(graph(0)->data()->size() > graphPointLimit) graph(0)->data()->remove(graph(0)->data()->begin()->key);
}
int Plot::getLimit()
{
return graphPointLimit;
}
void Plot::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::MiddleButton || (event->button() == Qt::LeftButton && event->modifiers() == Qt::Modifier::SHIFT) )
{
setCursor(Qt::ClosedHandCursor);
setSelectionRectMode(QCP::srmNone);
}
else if(event->button() == Qt::LeftButton)
{
setSelectionRectMode(QCP::srmSelect);
}
else if(event->button() == Qt::RightButton)
{
graphContextMenu.popup(event->globalPos());
setSelectionRectMode(QCP::srmNone);
}
QCustomPlot::mousePressEvent(event);
}
void Plot::mouseReleaseEvent(QMouseEvent *event)
{
setCursor(Qt::ArrowCursor);
QCustomPlot::mouseReleaseEvent(event);
}

84
src/ui/plot.h Normal file
View file

@ -0,0 +1,84 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PLOT_H
#define PLOT_H
#include<QVector>
#include<QAction>
#include<QWidget>
#include "qcustomplot/qcustomplot.h"
#include "regessioncalculator.h"
#include "statisticsdialog.h"
#include "utilites.h"
class Plot : public QCustomPlot
{
private:
std::vector<RegessionCalculator> regressions;
QMenu graphContextMenu;
int graphPointLimit = 10000;
QAction actionStatistics;
QAction actionAdd_Regression;
QAction actionDelete_Regression;
QAction actionExport_Selection;
QAction actionSetValueString;
QAction savePdfAction;
private slots:
void savePdf();
public:
Plot(QWidget* parent = nullptr);
~Plot();
void setLabel(QString label);
void clear();
void setLimit(int graphPointLimit);
int getLimit();
void setMaxValue(double maxVal);
signals:
void sigSaveCsv();
public slots:
void addPoints(QVector<double> keys, QVector<double> values);
void saveCsv(QString fileName);
void saveCsvDiag();
void showStatistics();
void deleteRegression();
void addRegression();
void askForValueString();
void addData(QVector<double> keys, QVector<double> values, bool inOrder = false, bool ignoreLimit = false);
void addData(double key, double value, bool ignoreLimit = false);
protected:
virtual void mousePressEvent(QMouseEvent *event);
virtual void mouseReleaseEvent(QMouseEvent *event);
virtual bool event(QEvent *event);
private:
void addMainGraph();
};
#endif // PLOT_H

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "profiledialog.h"
#include "ui_profiledialog.h"
#include "editprofiledialog.h"

View file

@ -1,3 +1,19 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PROFILEDIALOG_H
#define PROFILEDIALOG_H

40
src/ui/regressiondiag.cpp Normal file
View file

@ -0,0 +1,40 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "regressiondiag.h"
#include "ui_regressiondiag.h"
RegressionDiag::RegressionDiag(const RegessionCalculator& reg, QWidget *parent) :
QDialog(parent),
ui(new Ui::RegressionDiag)
{
ui->setupUi(this);
ui->lcdNumber_slope->display(reg.slope);
ui->lcdNumber_offset->display(reg.offset);
ui->lcdNumber_StdError->display(reg.stdError);
ui->lcdNumbe_count->display((int)reg.xValues.size());
#ifdef Q_OS_ANDROID
setWindowState(Qt::WindowMaximized);
#endif
}
RegressionDiag::~RegressionDiag()
{
delete ui;
}

40
src/ui/regressiondiag.h Normal file
View file

@ -0,0 +1,40 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REGRESSIONDIAG_H
#define REGRESSIONDIAG_H
#include <QDialog>
#include "regessioncalculator.h"
namespace Ui {
class RegressionDiag;
}
class RegressionDiag : public QDialog
{
Q_OBJECT
public:
explicit RegressionDiag(const RegessionCalculator& reg, QWidget *parent = 0);
~RegressionDiag();
private:
Ui::RegressionDiag *ui;
};
#endif // REGRESSIONDIAG_H

160
src/ui/regressiondiag.ui Normal file
View file

@ -0,0 +1,160 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RegressionDiag</class>
<widget class="QDialog" name="RegressionDiag">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>377</width>
<height>208</height>
</rect>
</property>
<property name="windowTitle">
<string>Regression</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Slope:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLCDNumber" name="lcdNumber_slope">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="digitCount">
<number>8</number>
</property>
<property name="value" stdset="0">
<double>99999999.000000000000000</double>
</property>
<property name="intValue" stdset="0">
<number>99999999</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLCDNumber" name="lcdNumber_offset">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="digitCount">
<number>8</number>
</property>
<property name="value" stdset="0">
<double>99999999.000000000000000</double>
</property>
<property name="intValue" stdset="0">
<number>99999999</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Slope standard error:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLCDNumber" name="lcdNumber_StdError">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="smallDecimalPoint">
<bool>false</bool>
</property>
<property name="digitCount">
<number>8</number>
</property>
<property name="value" stdset="0">
<double>99999999.000000000000000</double>
</property>
<property name="intValue" stdset="0">
<number>99999999</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Offset:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Count:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLCDNumber" name="lcdNumbe_count">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="digitCount">
<number>8</number>
</property>
<property name="intValue" stdset="0">
<number>99999999</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>RegressionDiag</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>RegressionDiag</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -0,0 +1,98 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "statisticsdialog.h"
#include "ui_statisticsdialog.h"
#include <QClipboard>
#include <limits>
#include <cmath>
StatisticsDialog::StatisticsDialog(const std::vector<double>& data, QWidget *parent):
QDialog(parent),
ui(new Ui::StatisticsDialog)
{
ui->setupUi(this);
connect(ui->pushButton_1, &QPushButton::clicked, this, &StatisticsDialog::copyCount);
connect(ui->pushButton_4, &QPushButton::clicked, this, &StatisticsDialog::copyMean);
connect(ui->pushButton_5, &QPushButton::clicked, this, &StatisticsDialog::copyMinMax);
connect(ui->pushButton_Sd, &QPushButton::clicked, this, &StatisticsDialog::copySd);
ui->lcdNumber_Count->display(static_cast<double>(data.size()));
double mean = 0;
double max = std::numeric_limits<double>::min();
double min = std::numeric_limits<double>::max();
for(double point : data)
{
mean += point;
if(point < min)
min = point;
if(point > max)
max = point;
}
mean = mean / data.size();
ui->lcdNumber_Mean->display(mean);
double sd = 0;
for(double point : data)
{
sd += (point - mean)*(point - mean);
}
sd /= data.size();
sd = sqrt(sd);
ui->lcdNumber_Sd->display(sd);
ui->lcdNumber_Max->display(max);
ui->lcdNumber_Min->display(min);
}
void StatisticsDialog::copyCount()
{
QString buffer(QString::number(ui->lcdNumber_Count->value(), 'g', 10));
QGuiApplication::clipboard()->setText(buffer, QClipboard::Clipboard);
QGuiApplication::clipboard()->setText(buffer, QClipboard::Selection);
}
void StatisticsDialog::copyMean()
{
QString buffer(QString::number(ui->lcdNumber_Mean->value(), 'g', 10));
QGuiApplication::clipboard()->setText(buffer, QClipboard::Clipboard);
QGuiApplication::clipboard()->setText(buffer, QClipboard::Selection);
}
void StatisticsDialog::copyMinMax()
{
QString buffer(QString::number(ui->lcdNumber_Min->value(), 'g', 10));
buffer.append(",");
buffer.append(QString::number(ui->lcdNumber_Max->value(), 'g', 10));
QGuiApplication::clipboard()->setText(buffer, QClipboard::Clipboard);
QGuiApplication::clipboard()->setText(buffer, QClipboard::Selection);
}
void StatisticsDialog::copySd()
{
QString buffer(QString::number(ui->lcdNumber_Sd->value(), 'g', 10));
QGuiApplication::clipboard()->setText(buffer, QClipboard::Clipboard);
QGuiApplication::clipboard()->setText(buffer, QClipboard::Selection);
}
StatisticsDialog::~StatisticsDialog()
{
delete ui;
}

45
src/ui/statisticsdialog.h Normal file
View file

@ -0,0 +1,45 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef STATISTICSDIALOG_H
#define STATISTICSDIALOG_H
#include <QDialog>
#include <vector>
namespace Ui {
class StatisticsDialog;
}
class StatisticsDialog : public QDialog
{
Q_OBJECT
public:
explicit StatisticsDialog(const std::vector<double>& data, QWidget *parent = 0);
~StatisticsDialog();
private slots:
void copyCount();
void copyMean();
void copyMinMax();
void copySd();
private:
Ui::StatisticsDialog *ui;
};
#endif // STATISTICSDIALOG_H

269
src/ui/statisticsdialog.ui Normal file
View file

@ -0,0 +1,269 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>StatisticsDialog</class>
<widget class="QDialog" name="StatisticsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>491</width>
<height>201</height>
</rect>
</property>
<property name="windowTitle">
<string>Statistics</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Count:</string>
</property>
</widget>
</item>
<item>
<widget class="QLCDNumber" name="lcdNumber_Count">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="digitCount">
<number>10</number>
</property>
<property name="segmentStyle">
<enum>QLCDNumber::Flat</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_1">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Copy</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Geometric mean:</string>
</property>
</widget>
</item>
<item>
<widget class="QLCDNumber" name="lcdNumber_Mean">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="digitCount">
<number>10</number>
</property>
<property name="segmentStyle">
<enum>QLCDNumber::Flat</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Copy</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Standard deviation:</string>
</property>
</widget>
</item>
<item>
<widget class="QLCDNumber" name="lcdNumber_Sd">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="digitCount">
<number>10</number>
</property>
<property name="segmentStyle">
<enum>QLCDNumber::Flat</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_Sd">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Copy</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Maximum:</string>
</property>
</widget>
</item>
<item>
<widget class="QLCDNumber" name="lcdNumber_Max">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="digitCount">
<number>10</number>
</property>
<property name="segmentStyle">
<enum>QLCDNumber::Flat</enum>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Minimum:</string>
</property>
</widget>
</item>
<item>
<widget class="QLCDNumber" name="lcdNumber_Min">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="digitCount">
<number>10</number>
</property>
<property name="segmentStyle">
<enum>QLCDNumber::Flat</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_5">
<property name="text">
<string>Copy</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>StatisticsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>StatisticsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

49
src/utilites.cpp Normal file
View file

@ -0,0 +1,49 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "utilites.h"
#include <vector>
#include <QTextStream>
#include <QFile>
#include <QDebug>
#include <QStringList>
#include <QMessageBox>
#include <thread>
#include <stdexcept>
bool saveToCsv(const QString& filename, const std::vector<double> &keys, const std::vector<double> &values, const QString& keyLable, const QString& valueLable )
{
if(keys.size() != values.size())
{
throw std::invalid_argument("keys and values need to be the same size");
return false;
}
QFile file(filename);
if(file.open(QIODevice::WriteOnly | QIODevice::Text))
{
QTextStream fileStream(&file);
fileStream<<"id"<<','<<keyLable<<','<<valueLable<<'\n';
for(size_t i = 0; i < keys.size(); i++)
{
fileStream<<i<<','<<(int64_t)keys[i]<<','<<values[i]<<'\n';
}
fileStream.flush();
file.close();
return true;
}
return false;
}

27
src/utilites.h Normal file
View file

@ -0,0 +1,27 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UTILITYS_H
#define UTILITYS_H
#include <QString>
#include <stdint.h>
#include <array>
bool saveToCsv(const QString& filename, const std::vector<double> &keys, const std::vector<double> &values, const QString& keyLable, const QString& valueLable);
#endif // UTILITYS_H