Initial commit

This commit is contained in:
2021-06-10 12:09:44 +02:00
commit 5efbdcbd6a
32 changed files with 1914 additions and 0 deletions

54
CMakeLists.txt Normal file
View File

@ -0,0 +1,54 @@
cmake_minimum_required(VERSION 3.5)
project(MAClient LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
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(OpenCV REQUIRED)
set(PROJECT_SOURCES
res/resources.qrc
src/main.cpp
src/cameras.cpp
src/cameras.h
src/camera.cpp
src/camera.h
src/profile.cpp
src/profile.h
src/imagepipeline.cpp
src/imagepipeline.h
src/ui/cameradialog.cpp
src/ui/cameradialog.h
src/ui/cameradialog.ui
src/ui/profiledialog.cpp
src/ui/profiledialog.h
src/ui/profiledialog.ui
src/ui/editprofiledialog.h
src/ui/editprofiledialog.cpp
src/ui/editprofiledialog.ui
src/ui/mainwindow.cpp
src/ui/mainwindow.h
src/ui/mainwindow.ui
src/ui/cvimageviewer.cpp
src/ui/cvimageviewer.h
src/ui/cvimageviewer.ui
src/ui/led.cpp
src/ui/led.h
src/ui/cameralistwidget.h
src/ui/cameralistwidget.cpp
)
add_executable(MAClient ${PROJECT_SOURCES})
target_link_libraries(MAClient PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Concurrent ${OpenCV_LIBS} -luvoscam -luvosled -luvosunwrap)
target_include_directories(${PROJECT_NAME} PRIVATE ${OpenCV_INCLUDE_DIRS} src src/ui)

BIN
res/noimage.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 KiB

6
res/resources.qrc Normal file
View File

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/images">
<file>noimage.png</file>
<file>splash.png</file>
</qresource>
</RCC>

BIN
res/splash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

18
src/camera.cpp Normal file
View File

@ -0,0 +1,18 @@
#include "camera.h"
#include <QRandomGenerator>
#include <string>
#include <functional>
#include <QDebug>
Camera::Camera(cam::Camera::Description desc)
{
cameraId_ = desc.getHash();
std::function<void(cv::Mat)> cb = [this](cv::Mat image){newImage(Image(image, cameraId_));};
camera_ = new cam::Camera(cb);
camera_->openCamera(desc);
}
Camera::~Camera()
{
delete camera_;
}

46
src/camera.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef CAMERA_H
#define CAMERA_H
#include <QObject>
#include <vector>
#include <uvoscam.h>
#include <uvosled.h>
#include <memory.h>
#include <stdint.h>
#include <QSettings>
#include <opencv2/core/mat.hpp>
#include "profile.h"
class Camera : public QObject
{
Q_OBJECT
public:
class Image
{
public:
cv::Mat mat;
size_t cameraId;
Image(cv::Mat mati, size_t cameraIdi): mat(mati), cameraId(cameraIdi){}
Image() = default;
Image(const Image& img) = default;
};
private:
cam::Camera* camera_ = nullptr;
void callback(cv::Mat);
size_t cameraId_;
signals:
void newImage(Image);
public:
Camera(cam::Camera::Description);
~Camera();
cam::Camera* cam(){return camera_;}
size_t id() const {return cameraId_;}
bool operator==(const Camera& cam){return cam.id() == id();}
bool operator!=(const Camera& cam){return !operator==(cam);}
};
#endif // CAMERA_H

181
src/cameras.cpp Normal file
View File

@ -0,0 +1,181 @@
#include "cameras.h"
#include <QRandomGenerator>
#include <string>
#include <functional>
#include <QDebug>
Cameras::Cameras(uvosled* led): led_(led)
{
}
bool Cameras::setCameras(const std::vector<cam::Camera::Description>& descriptions)
{
clear();
bool ret = true;
for(auto& camera : descriptions)
{
if(!addCamera(camera))
ret = false;
}
return ret;
}
void Cameras::clear()
{
free_ = false;
for(auto& camera : cameras_)
cameraRemoved(camera);
cameras_.clear();
if(led_)
uvosled_set_current(led_, 0xFF, 0);
}
std::vector<cam::Camera::Description> Cameras::getCameras()
{
std::vector<cam::Camera::Description> desc;
desc.reserve(cameras_.size());
for(std::shared_ptr<Camera> camera : cameras_)
desc.push_back(camera->cam()->getDescription());
return desc;
}
bool Cameras::addCamera(const cam::Camera::Description& desc)
{
cameras_.push_back(std::shared_ptr<Camera>(new Camera(desc)));
if(!cameras_.back()->cam()->isOpen())
{
cameras_.pop_back();
return false;
}
cameras_.back()->cam()->setTriggerMode(cam::Camera::TRIGGER_SOFTWARE);
cameras_.back()->cam()->setExposureTime(exposrueTime_*1000000);
setFree(false);
cameraAdded(cameras_.back());
qDebug()<<"Using camera"<<cameras_.back()->id();
return true;
}
void Cameras::trigger()
{
for(auto& camera : cameras_)
camera->cam()->trigger();
if(led_ && !free_)
uvosled_capture(led_, lighting_.mask, lighting_.brightness, exposrueTime_*1.5, exposrueTime_*0.25);
}
bool Cameras::start()
{
bool ret = true;
for(auto& camera : cameras_)
{
if(!camera->cam()->startAcquisition())
ret = false;
}
if(free_)
uvosled_set_current(led_, lighting_.mask, lighting_.brightness);
return ret;
}
bool Cameras::stop()
{
bool ret = true;
for(auto& camera : cameras_)
{
if(!camera->cam()->stopAcquisition())
ret = false;
}
if(led_)
uvosled_set_current(led_, 0xFF, 0);
return ret;
}
bool Cameras::setFree(bool free)
{
stop();
free_ = free;
bool ret = true;
for(auto& camera : cameras_)
{
if(!camera->cam()->setAcquisitionMode(free ? cam::Camera::MODE_FREE : cam::Camera::MODE_SINGLE))
ret = false;
}
return ret;
}
bool Cameras::setExposureTime(double exposureTime)
{
stop();
exposrueTime_ = exposureTime;
bool ret = true;
for(auto& camera : cameras_)
{
if(!camera->cam()->setExposureTime(exposrueTime_*1000000))
ret = false;
}
return ret;
}
void Cameras::imageRecived(Camera::Image img)
{
bool allreadyUpdated = false;
for(auto& camera : cameras_)
{
for(auto& image : images_)
{
if(image.cameraId == camera->id())
{
allreadyUpdated = true;
goto FOUND;
}
}
}
FOUND:
if(!allreadyUpdated)
images_.push_back(img);
if(images_.size() == cameras_.size())
newImages(images_);
images_.clear();
}
void Cameras::store(QSettings &settings)
{
std::vector<cam::Camera::Description> available = cam::Camera::getAvailableCameras();
settings.beginWriteArray(GROUP, cameras_.size());
for(size_t i = 0; i < cameras_.size(); ++i)
{
settings.setArrayIndex(i);
settings.setValue("id", static_cast<unsigned long long>(cameras_[i]->id()));
}
settings.endArray();
}
void Cameras::load(QSettings &settings)
{
std::vector<cam::Camera::Description> available = cam::Camera::getAvailableCameras();
int size = settings.beginReadArray(GROUP);
for(int i = 0; i < size; ++i)
{
settings.setArrayIndex(i);
size_t hash = settings.value("id", 0).toULongLong();
for(auto& camera : available)
{
if(camera.getHash() == hash)
addCamera(camera);
}
}
settings.endArray();
}

59
src/cameras.h Normal file
View File

@ -0,0 +1,59 @@
#ifndef CAMERAS_H
#define CAMERAS_H
#include <QObject>
#include <vector>
#include <uvoscam.h>
#include <uvosled.h>
#include <memory.h>
#include <stdint.h>
#include <QSettings>
#include <opencv2/core/mat.hpp>
#include "profile.h"
#include "camera.h"
class Cameras : public QObject
{
Q_OBJECT
static constexpr const char* GROUP = "Cameras";
private:
uvosled* led_;
bool free_ = false;
double exposrueTime_ = 1.0/60.0;
LightingSetup lighting_;
std::vector<std::shared_ptr<Camera>> cameras_;
std::vector<Camera::Image> images_;
private slots:
void imageRecived(Camera::Image img);
signals:
void cameraRemoved(std::shared_ptr<Camera> camera);
void cameraAdded(std::shared_ptr<Camera> camera);
void newImages(std::vector<Camera::Image> images_);
public slots:
bool setExposureTime(double exposureTime);
void trigger();
bool start();
bool stop();
bool setFree(bool free);
void setLighting(const LightingSetup& lighting) {lighting_ = lighting;}
public:
bool setCameras(const std::vector<cam::Camera::Description>& descriptions);
bool addCamera(const cam::Camera::Description& desc);
std::vector<cam::Camera::Description> getCameras();
size_t numCameras(){return cameras_.size();}
void clear();
Cameras(uvosled* led = nullptr);
void load(QSettings& settings);
void store(QSettings& settings);
};
#endif // CAMERAS_H

74
src/imagepipeline.cpp Normal file
View File

@ -0,0 +1,74 @@
#include "imagepipeline.h"
#include <uvosunwrap/unwrap.h>
#include <QtConcurrent/QtConcurrentRun>
#include <QFuture>
ImagePipeline::ImagePipeline(Cameras* cameras, QObject *parent): QObject(parent), cameras_(cameras)
{
}
cv::Mat ImagePipeline::process(const Profile profile, std::vector<Camera::Image> images)
{
std::vector<RemapedImage> remapedImages;
remapedImages.reserve(images.size());
for(Camera::Image& image : images)
{
for(auto& camera : profile.cameras)
{
if(camera.id == image.cameraId)
{
if(camera.darkmap.data)
image.mat = image.mat - camera.darkmap;
remapedImages.push_back(applyRemap(image.mat, camera.remapMap));
break;
}
}
}
cv::Mat output = simpleStich(remapedImages);
output.convertTo(output, CV_32FC1, 1.0/255.0, 0);
if(profile.lightmap.data)
normalize(output, profile.lightmap);
return output;
}
void ImagePipeline::apply(std::vector<Camera::Image> images)
{
if(!invalid_)
{
futureImageWatchers_.push_back(new QFutureWatcher<cv::Mat>());
connect(futureImageWatchers_.back(), &QFutureWatcher<cv::Mat>::finished, this, &ImagePipeline::imageFinished);
QFuture<cv::Mat> futureImage = QtConcurrent::run(&ImagePipeline::process, profile_, images);
futureImageWatchers_.back()->setFuture(futureImage);
}
}
void ImagePipeline::setProfile(const Profile& profile)
{
profile_ = profile;
cameras_->setExposureTime(profile_.exposureTime);
cameras_->setLighting(profile_.lighting);
if(!profile_.camerasSufficant(cameras_->getCameras()))
{
invalid_ = true;
sigInvalidProfile("A camera required for this profile is not available");
}
}
void ImagePipeline::imageFinished()
{
for(size_t i = 0; i < futureImageWatchers_.size(); ++i)
{
if(futureImageWatchers_[i]->isFinished())
{
cv::Mat result = futureImageWatchers_[i]->result();
sigResult(Camera::Image(result, 0));
delete futureImageWatchers_[i];
futureImageWatchers_.erase(futureImageWatchers_.begin()+i);
i--;
}
}
}

41
src/imagepipeline.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef IMAGEPIPELINE_H
#define IMAGEPIPELINE_H
#include <QObject>
#include <vector>
#include <QFutureWatcher>
#include "profile.h"
#include "cameras.h"
class ImagePipeline: public QObject
{
Q_OBJECT
private:
Cameras* cameras_;
Profile profile_;
bool invalid_ = true;
std::vector<QFutureWatcher<cv::Mat>*> futureImageWatchers_;
static cv::Mat process(const Profile profile, std::vector<Camera::Image> images);
private slots:
void apply(std::vector<Camera::Image> images);
void imageFinished();
signals:
void sigInvalidProfile(QString message);
void sigResult(Camera::Image image);
public slots:
void setProfile(const Profile& profile);
public:
ImagePipeline(Cameras* cameras, QObject* parent = nullptr);
};
#endif // IMAGEPIPELINE_H

93
src/main.cpp Normal file
View File

@ -0,0 +1,93 @@
#include <QApplication>
#include <uvoscam.h>
#include <QSettings>
#include <QString>
#include <QDebug>
#include <QMessageBox>
#include <QSplashScreen>
#include <QDir>
#include <QThread>
#include <opencv2/core/mat.hpp>
#include "cameras.h"
#include "./ui/cameradialog.h"
#include "profile.h"
#include "./ui/mainwindow.h"
#include "imagepipeline.h"
const char* organziation = "UVOS";
const char* application = "UVOS";
const char* version = "UVOS";
std::vector<cam::Camera::Description> showCameraSelectionDialog()
{
std::vector<cam::Camera::Description> ret;
CameraDialog diag(cam::Camera::getAvailableCameras());
diag.show();
if(diag.exec() == QDialog::Accepted)
ret = diag.getDescriptions();
return ret;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QCoreApplication::setOrganizationName("UVOS");
QCoreApplication::setOrganizationDomain("uvos.xyz");
QCoreApplication::setApplicationName("LubircantThiknessMapperUi");
QCoreApplication::setApplicationVersion("0.1");
QSplashScreen splash(QPixmap(":/images/splash.png"));
splash.show();
QDir().mkpath(Profile::profileLocation());
QDir().mkpath(CameraSetup::camerasLocation());
qRegisterMetaType<cv::Mat>("cv::Mat");
qRegisterMetaType<size_t>("size_t");
qRegisterMetaType<Camera::Image>("Image");
QSettings settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
uvosled led;
int uvosledRet = uvosled_connect(&led);
Cameras cameras(uvosledRet < 0 ? nullptr : &led);
ImagePipeline pipe(&cameras);
MainWindow w;
QObject::connect(&cameras, &Cameras::cameraAdded, &w, &MainWindow::addCamera);
QObject::connect(&cameras, &Cameras::cameraRemoved, &w, &MainWindow::removeCamera);
QObject::connect(&w, &MainWindow::sigCapture, [&cameras](){cameras.start(); cameras.trigger();});
QObject::connect(&w, &MainWindow::sigChooseCameras, [&cameras](){cameras.setCameras(showCameraSelectionDialog());});
QObject::connect(&pipe, &ImagePipeline::sigResult, w.mainImageViewer(), &CvImageViewer::setImage, Qt::QueuedConnection);
QObject::connect(&w, &MainWindow::sigProfile, [&pipe](QString name)
{
Profile profile;
profile.load(name);
pipe.setProfile(profile);
});
cameras.load(settings);
splash.hide();
w.show();
if(uvosledRet < 0)
QMessageBox::warning(&w, "UVOS LED", "Can not connect to the UVOS LED device");
if(cameras.getCameras().empty())
{
QMessageBox::information(&w, "Cameras", "No cameras configured, please choose at least one camera.");
cameras.setCameras(showCameraSelectionDialog());
}
int ret = a.exec();
cameras.store(settings);
return ret;
}

151
src/profile.cpp Normal file
View File

@ -0,0 +1,151 @@
#include "profile.h"
#include <opencv2/imgcodecs.hpp>
#include <QStandardPaths>
#include <QFile>
#include <QDir>
void CameraSetup::store() const
{
cv::imwrite((camerasLocation() + QString::number(id) + ".darkmap.png").toStdString(), darkmap);
}
void CameraSetup::load(size_t cameraId)
{
id = cameraId;
darkmap = cv::imread((camerasLocation() + QString::number(id) + ".darkmap.png").toStdString());
}
QString CameraSetup::camerasLocation()
{
return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/cameras/";
}
void LightingSetup::store(QSettings& settings) const
{
settings.setValue(GROUP + QString("/brightness"), brightness);
settings.setValue(GROUP + QString("/mask"), mask);
}
void LightingSetup::load(const QSettings& settings)
{
brightness = settings.value(GROUP + QString("/brightness"), 0.25).toDouble();
mask = settings.value(GROUP + QString("/maks"), 0).toUInt();
}
void Profile::store(QSettings& settings) const
{
lighting.store(settings);
settings.setValue(GROUP + QString("/id"), static_cast<unsigned long long>(id));
settings.setValue(GROUP + QString("/exposureTime"), exposureTime);
settings.setValue(GROUP + QString("/name"), name_);
cv::imwrite((profileLocation() + QString::number(id) + ".lightmap.png").toStdString(), lightmap);
settings.beginWriteArray(GROUP + QString("/cameras"), cameras.size());
for(size_t i = 0; i < cameras.size(); ++i)
{
const CameraSetup& camera = cameras[i];
settings.setArrayIndex(i);
camera.store();
settings.setValue("id", static_cast<unsigned long long>(camera.id));
}
settings.endArray();
}
void Profile::load(QSettings &settings)
{
lighting.load(settings);
id = settings.value(GROUP + QString("/id")).toULongLong();
exposureTime = settings.value(GROUP + QString("/exposureTime"), 1.0/60.0).toDouble();
name_ = settings.value(GROUP + QString("/name"), "NULL").toString();
lightmap = cv::imread((profileLocation() + QString::number(id) + ".lightmap.png").toStdString());
int size = settings.beginReadArray(GROUP + QString("/cameras"));
for(int i = 0; i < size; ++i)
{
settings.setArrayIndex(i);
cameras.push_back(CameraSetup());
cameras.back().load(settings.value("id", 0).toULongLong());
}
settings.endArray();
}
void Profile::load(const QString& name)
{
QSettings settings(profileLocation() + name + ".profile.ini");
name_=name;
load(settings);
}
void Profile::store(const QString& name)
{
QSettings settings(profileLocation() + name + ".profile.ini");
name_=name;
store(settings);
}
void Profile::load()
{
load(name_);
}
void Profile::store()
{
store(name_);
}
void Profile::deleteProfile()
{
QFile::remove(profileLocation() + name_ + ".profile.ini");
}
QList<QString> Profile::avaiableProfiles()
{
QDir dir(profileLocation());
dir.setFilter(QDir::Files);
QStringList filters;
filters<<"*.ini";
dir.setNameFilters(filters);
QList<QString> ret;
QStringList list = dir.entryList();
for(QString string : list)
ret.push_back(string.split(".")[0]);
return ret;
}
bool Profile::camerasSufficant(const std::vector<cam::Camera::Description>& desc) const
{
bool invalid = false;
for(auto& cameraProfile : cameras)
{
bool found = false;
for(auto& camera : desc)
{
if(camera.getHash() == cameraProfile.id)
{
found = true;
break;
}
}
if(!found)
{
invalid = true;
break;
}
}
return !invalid;
}
QString Profile::profileLocation()
{
return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/profiles/";
}
Profile::Profile(const QString& name): name_(name)
{
id = QRandomGenerator::system()->generate64();
}

67
src/profile.h Normal file
View File

@ -0,0 +1,67 @@
#ifndef PROFILE_H
#define PROFILE_H
#include <QSettings>
#include <stdint.h>
#include <vector>
#include <QRandomGenerator>
#include <opencv2/core/mat.hpp>
#include <uvosunwrap/unwrap.h>
#include "camera.h"
class CameraSetup
{
public:
size_t id;
RemapMap remapMap;
cv::Mat darkmap;
cv::Mat bgmask;
void store() const;
void load(size_t cameraId);
static QString camerasLocation();
static QString remapMapLocation(size_t cameraId);
static QString bgmaskLocation(size_t cameraId);
static QString darkmapLocation(size_t cameraId);
};
class LightingSetup
{
static constexpr const char* GROUP = "Lighting";
public:
double brightness = 0.25;
uint8_t mask = 0;
void store(QSettings& settings) const;
void load(const QSettings& settings);
};
class Profile
{
static constexpr const char* GROUP = "Profile";
QString name_ = "NULL";
public:
uint64_t id;
LightingSetup lighting;
double exposureTime = 1.0/60.0;
cv::Mat lightmap;
std::vector<CameraSetup> cameras;
Profile(const QString& name = "NULL");
void store(QSettings& settings) const;
void store(const QString& name);
void store();
void load(QSettings& settings);
void load(const QString& name);
void load();
void deleteProfile();
void setName(const QString name){name_=name;}
QString getName() const {return name_;}
bool camerasSufficant(const std::vector<cam::Camera::Description>& desc) const;
static QList<QString> avaiableProfiles();
static QString profileLocation();
};
#endif // PROFILE_H

21
src/ui/cameradialog.cpp Normal file
View File

@ -0,0 +1,21 @@
#include "cameradialog.h"
#include "ui_cameradialog.h"
#include "../cameras.h"
CameraDialog::CameraDialog(const std::vector<cam::Camera::Description>& desc, QWidget *parent) :
QDialog(parent),
ui(new Ui::CameraDialog)
{
ui->setupUi(this);
ui->listView->setCameras(desc);
}
CameraDialog::~CameraDialog()
{
delete ui;
}
std::vector<cam::Camera::Description> CameraDialog::getDescriptions()
{
return ui->listView->getSelectedDescriptions();
}

26
src/ui/cameradialog.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef CAMERADIALOG_H
#define CAMERADIALOG_H
#include <QDialog>
#include <vector>
#include <uvoscam.h>
#include <QSettings>
namespace Ui {
class CameraDialog;
}
class CameraDialog : public QDialog
{
Q_OBJECT
public:
explicit CameraDialog(const std::vector<cam::Camera::Description>& desc, QWidget *parent = nullptr);
~CameraDialog();
std::vector<cam::Camera::Description> getDescriptions();
private:
Ui::CameraDialog *ui;
};
#endif // CAMERADIALOG_H

91
src/ui/cameradialog.ui Normal file
View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CameraDialog</class>
<widget class="QDialog" name="CameraDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="windowTitle">
<string>Select Cameras</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Select Cameras:</string>
</property>
</widget>
</item>
<item>
<widget class="CameraListWidget" name="listView"/>
</item>
<item>
<widget class="QPushButton" name="pushButtonConfigure">
<property name="text">
<string>Configure Cameras</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>CameraListWidget</class>
<extends>QListView</extends>
<header location="global">cameralistwidget.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>CameraDialog</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>CameraDialog</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,45 @@
#include "cameralistwidget.h"
#include <QDebug>
#include <QHeaderView>
#include "../cameras.h"
CameraListWidget::CameraListWidget(QWidget* parent): QTableWidget(parent)
{
setColumnCount(1);
setSelectionBehavior(QAbstractItemView::SelectRows);
setSelectionMode(QAbstractItemView::MultiSelection);
setHorizontalHeaderItem(0, new QTableWidgetItem("Camera"));
setRowCount(desc_.size());
horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
}
void CameraListWidget::setConfigured(std::vector<bool> configured)
{
setColumnCount(2);
setHorizontalHeaderItem(1, new QTableWidgetItem("Configured"));
for(size_t i = 0; i < desc_.size() && i < configured.size(); ++i)
setItem(static_cast<int>(i), 0, new QTableWidgetItem("No"));
}
void CameraListWidget::setCameras(const std::vector<cam::Camera::Description>& desc)
{
desc_ = desc;
qDebug()<<"cameras: "<<desc_.size();
setRowCount(static_cast<int>(desc_.size()));
for(size_t i = 0; i < desc_.size(); ++i)
{
setItem(static_cast<int>(i), 0, new QTableWidgetItem((desc_[i].vendor + " " + desc_[i].model).c_str()));
}
}
std::vector<cam::Camera::Description> CameraListWidget::getSelectedDescriptions()
{
QList<QModelIndex> selected = selectedIndexes();
std::vector<cam::Camera::Description> cameras;
for(auto& selection : selected)
{
if(selection.column() == 0)
cameras.push_back(desc_[selection.row()]);
}
return cameras;
}

19
src/ui/cameralistwidget.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef CAMERALISTWIDGET_H
#define CAMERALISTWIDGET_H
#include <vector>
#include <uvoscam.h>
#include <QTableWidget>
class CameraListWidget : public QTableWidget
{
private:
std::vector<cam::Camera::Description> desc_;
public:
CameraListWidget(QWidget* parent);
void setCameras(const std::vector<cam::Camera::Description>& desc);
void setConfigured(std::vector<bool> configured);
std::vector<cam::Camera::Description> getSelectedDescriptions();
};
#endif // CAMERALISTWIDGET_H

36
src/ui/cvimageviewer.cpp Normal file
View File

@ -0,0 +1,36 @@
#include "cvimageviewer.h"
#include <QPicture>
#include <QDebug>
CvImageViewer::CvImageViewer(QWidget *parent, size_t lastId) :
QWidget(parent),
lastId_(lastId)
{
qimage_.load(":/images/noimage.png");
}
CvImageViewer::~CvImageViewer()
{
}
void CvImageViewer::setImage(Camera::Image img)
{
image_ = img.mat;
if(image_.type() == CV_8UC3 || image_.type() == CV_8SC3)
qimage_ = QImage(image_.data, image_.cols, image_.rows, image_.step, QImage::Format_RGB888);
else if(image_.type() == CV_8UC1 || image_.type() == CV_8SC1)
qimage_ = QImage(image_.data, image_.cols, image_.rows, image_.step, QImage::Format_Grayscale8);
else if(image_.type() == CV_32FC1 || image_.type() == CV_64FC1)
img.mat.convertTo(image_, CV_8UC1, 255, 0);
update();
}
void CvImageViewer::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event)
QPainter painter(this);
if(!fixedOnWidth_)
painter.drawImage(QRect((rect().width()-rect().height())/2, rect().y(), rect().height(), rect().height()), qimage_);
else
painter.drawImage(QRect(rect().x(), (rect().height()-rect().width())/2, rect().width(), rect().width()), qimage_);
}

30
src/ui/cvimageviewer.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef CVIMAGEVIEWER_H
#define CVIMAGEVIEWER_H
#include <QWidget>
#include <QPainter>
#include "../cameras.h"
class CvImageViewer : public QWidget
{
Q_OBJECT
cv::Mat image_;
QImage qimage_;
bool fixedOnWidth_ = false;
size_t lastId_;
protected:
virtual void paintEvent(QPaintEvent* event) override;
public slots:
void setImage(Camera::Image img);
public:
explicit CvImageViewer(QWidget *parent = nullptr, size_t lastId = 0);
void setFixedOnWidth(bool in){fixedOnWidth_ = in;}
size_t lastId(){return lastId_;}
~CvImageViewer();
};
#endif // CVIMAGEVIEWER_H

28
src/ui/cvimageviewer.ui Normal file
View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CvImageViewer</class>
<widget class="QWidget" name="CvImageViewer">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,16 @@
#include "editprofiledialog.h"
#include "ui_editprofiledialog.h"
EditProfileDialog::EditProfileDialog(Cameras* cameras, Profile* profile, QWidget *parent) :
QDialog(parent),
profile_(profile),
cameras_(cameras),
ui(new Ui::EditProfileDialog)
{
ui->setupUi(this);
}
EditProfileDialog::~EditProfileDialog()
{
delete ui;
}

View File

@ -0,0 +1,28 @@
#ifndef EDDITPROFILEDIALOG_H
#define EDDITPROFILEDIALOG_H
#include <QDialog>
#include <profile.h>
#include "../cameras.h"
namespace Ui {
class EditProfileDialog;
}
class EditProfileDialog : public QDialog
{
Q_OBJECT
Profile* profile_;
Cameras* cameras_;
public:
explicit EditProfileDialog(Cameras* cameras, Profile* profile, QWidget *parent = nullptr);
Profile* getProfile(){return profile_;}
~EditProfileDialog();
private:
Ui::EditProfileDialog *ui;
};
#endif // EDDITPROFILEDIALOG_H

228
src/ui/editprofiledialog.ui Normal file
View File

@ -0,0 +1,228 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EditProfileDialog</class>
<widget class="QDialog" name="EditProfileDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>539</width>
<height>485</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Profile Name</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditName"/>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Cameras</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="CameraListWidget" name="listView"/>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Exposure Time</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBoxExposure">
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>s</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Lights</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Brightness</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBoxBrightness"/>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>%</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Channels:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QCheckBox" name="checkBoxCh1">
<property name="text">
<string>CH1</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxCh2">
<property name="text">
<string>CH2</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxCh3">
<property name="text">
<string>CH3</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxCh4">
<property name="text">
<string>CH4</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>CameraListWidget</class>
<extends>QListView</extends>
<header location="global">./src/ui/cameralistwidget.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>EditProfileDialog</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>EditProfileDialog</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>

31
src/ui/led.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "led.h"
#include <QPainter>
Led::Led(QWidget* parent): QWidget(parent)
{
}
bool Led::lit() const
{
return lit_;
}
void Led::setLit(bool lit)
{
if(lit != lit_)
{
lit_ = lit;
stateChanged(lit_);
update();
}
}
void Led::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event)
QPainter ledPainter(this);
ledPainter.setPen(Qt::black);
if(lit_) ledPainter.setBrush(Qt::red);
else ledPainter.setBrush(Qt::NoBrush);
ledPainter.drawEllipse(rect().adjusted(0, 0, -1, -1));
}

29
src/ui/led.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef LED_H
#define LED_H
#include <QWidget>
class Led : public QWidget
{
Q_OBJECT
bool lit_ = false;
public:
Led(QWidget* parent = nullptr);
bool lit() const;
public slots:
void setLit(bool lit);
signals:
void stateChanged(bool lit);
protected:
virtual void paintEvent(QPaintEvent* event) override;
};
#endif // LED_H

69
src/ui/mainwindow.cpp Normal file
View File

@ -0,0 +1,69 @@
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QDebug>
#include <QMessageBox>
#include <uvosled.h>
#include "../profile.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->statusbar->showMessage("idle");
connect(ui->actionQuit, &QAction::triggered, [this](bool checked){(void)checked; close();});
connect(ui->actionCameras, &QAction::triggered, [this](bool checked){(void)checked; sigChooseCameras();});
connect(ui->comboBox, &QComboBox::currentTextChanged, this, &MainWindow::sigProfile);
connect(ui->pushButtonCapture, &QPushButton::clicked, this, &MainWindow::sigCapture);
ui->widget->setLit(true);
refreshProfiles();
}
void MainWindow::addCamera(std::shared_ptr<Camera> camera)
{
viewers_.push_back(new CvImageViewer(this, camera->id()));
viewers_.back()->setFixedOnWidth(true);
connect(camera.get(), &Camera::newImage, viewers_.back(), &CvImageViewer::setImage, Qt::QueuedConnection);
ui->viewerLayout->addWidget(viewers_.back());
}
void MainWindow::removeCamera(std::shared_ptr<Camera> camera)
{
for(size_t i = 0; i < viewers_.size(); ++i)
{
if(viewers_[i]->lastId() == camera->id())
{
ui->viewerLayout->removeWidget(viewers_[i]);
delete viewers_[i];
viewers_.erase(viewers_.begin()+i);
--i;
}
}
}
void MainWindow::refreshProfiles()
{
ui->comboBox->clear();
QList<QString> profiles = Profile::avaiableProfiles();
for(const QString& string : profiles)
ui->comboBox->addItem(string);
}
void MainWindow::profileInconpatible(QString message)
{
QMessageBox::warning(this, "Profile Incompatible", message);
}
CvImageViewer* MainWindow::mainImageViewer()
{
return ui->mainViewer;
}
MainWindow::~MainWindow()
{
for(CvImageViewer* viewer : viewers_)
delete viewer;
delete ui;
}

39
src/ui/mainwindow.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <stdint.h>
#include "../cameras.h"
#include "cvimageviewer.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
std::vector<CvImageViewer*> viewers_;
signals:
void sigCapture();
void sigProfile(QString profileName);
void sigChooseCameras();
public slots:
void addCamera(std::shared_ptr<Camera> camera);
void refreshProfiles();
void profileInconpatible(QString message);
void removeCamera(std::shared_ptr<Camera> camera);
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
CvImageViewer* mainImageViewer();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

230
src/ui/mainwindow.ui Normal file
View File

@ -0,0 +1,230 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QGroupBox" name="groupBoxCameras">
<property name="title">
<string>Cameras</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>278</width>
<height>483</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<layout class="QVBoxLayout" name="viewerLayout"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="verticalLayoutWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBoxResult">
<property name="title">
<string>Result</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QScrollArea" name="scrollArea_2">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents_2">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>467</width>
<height>315</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="CvImageViewer" name="mainViewer" native="true"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Controles</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPushButton" name="pushButtonCapture">
<property name="text">
<string>Capture</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Profile:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="Led" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Uncal</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>32</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionSave"/>
<addaction name="actionQuit"/>
</widget>
<widget class="QMenu" name="menuSetup">
<property name="title">
<string>Settings</string>
</property>
<addaction name="actionCameras"/>
<addaction name="actionCallibration"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuSetup"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionQuit">
<property name="text">
<string>Quit</string>
</property>
</action>
<action name="actionCameras">
<property name="text">
<string>Cameras</string>
</property>
</action>
<action name="actionCallibration">
<property name="text">
<string>Profile</string>
</property>
</action>
<action name="actionSave">
<property name="text">
<string>Save</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>Led</class>
<extends>QWidget</extends>
<header location="global">./src/ui/led.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>CvImageViewer</class>
<extends>QWidget</extends>
<header location="global">./src/ui/cvimageviewer.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

37
src/ui/profiledialog.cpp Normal file
View File

@ -0,0 +1,37 @@
#include "profiledialog.h"
#include "ui_profiledialog.h"
#include "editprofiledialog.h"
ProfileDialog::ProfileDialog(Cameras* cameras, QWidget *parent) :
QDialog(parent),
cameras_(cameras),
ui(new Ui::ProfileDialog)
{
ui->setupUi(this);
ui->listWidget->addItems(Profile::avaiableProfiles());
}
ProfileDialog::~ProfileDialog()
{
delete ui;
}
void ProfileDialog::editProfile()
{
}
void ProfileDialog::addProfile()
{
Profile newProfile;
EditProfileDialog dialog(cameras_, &newProfile);
dialog.show();
int ret = dialog.exec();
if(ret == QDialog::Accepted)
{
}
}

29
src/ui/profiledialog.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef PROFILEDIALOG_H
#define PROFILEDIALOG_H
#include <QDialog>
#include "../cameras.h"
namespace Ui {
class ProfileDialog;
}
class ProfileDialog : public QDialog
{
Q_OBJECT
Cameras* cameras_;
private slots:
void addProfile();
void editProfile();
public:
explicit ProfileDialog(Cameras* cameras, QWidget *parent = nullptr);
~ProfileDialog();
private:
Ui::ProfileDialog *ui;
};
#endif // PROFILEDIALOG_H

92
src/ui/profiledialog.ui Normal file
View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ProfileDialog</class>
<widget class="QDialog" name="ProfileDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Profiles</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Profiles:</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listWidget"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pushButtonEdit">
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonAdd">
<property name="text">
<string>Add</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>ProfileDialog</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>ProfileDialog</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>