diff --git a/res/icon.png b/res/icon.png new file mode 100644 index 0000000..feae36f Binary files /dev/null and b/res/icon.png differ diff --git a/res/resources.qrc b/res/resources.qrc index 5739fb3..2f22372 100644 --- a/res/resources.qrc +++ b/res/resources.qrc @@ -2,5 +2,6 @@ noimage.png splash.png + icon.png diff --git a/src/camera.cpp b/src/camera.cpp index 3640513..6e67e7d 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -6,7 +6,7 @@ Camera::Camera(cam::Camera::Description desc) { - cameraId_ = desc.getHash(); + cameraId_ = desc.getId(); std::function cb = [this](cv::Mat image){newImage(Image(image, cameraId_));}; camera_ = new cam::Camera(cb); camera_->openCamera(desc); diff --git a/src/cameras.cpp b/src/cameras.cpp index 1351ad3..74deaa9 100644 --- a/src/cameras.cpp +++ b/src/cameras.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include Cameras::Cameras(uvosled* led): led_(led) { @@ -46,7 +48,7 @@ std::shared_ptr Cameras::getCamera(size_t id) std::vector desc = getCameras(); for(size_t i = 0; i < desc.size(); ++i) { - if(desc[i].getHash() == id) + if(desc[i].getId() == id) return cameras_[i]; } return std::shared_ptr(nullptr); @@ -62,14 +64,35 @@ bool Cameras::addCamera(const cam::Camera::Description& desc) return false; } - cameras_.back()->cam()->setTriggerMode(cam::Camera::TRIGGER_SOFTWARE); cameras_.back()->cam()->setExposureTime(exposrueTime_*1000000); - setFree(false); - cameraAdded(cameras_.back()); - qDebug()<<"Using camera"<id(); + + if(desc.getVendor().find("Photonfocus") != std::string::npos) + { + qDebug()<<"Mitiagting broken PhotonFocus single shot mode"; + std::shared_ptr camera = cameras_.back(); + camera->cam()->setTriggerMode(cam::Camera::TRIGGER_FREE); + camera->cam()->setAcquisitionMode(cam::Camera::MODE_FREE); + camera->cam()->setFrameRate(10); + camera->cam()->startAcquisition(); + QTimer::singleShot(2000, [camera, this](){finishAddCamera(camera);}); + } + else + { + finishAddCamera(cameras_.back()); + } + return true; } +void Cameras::finishAddCamera(std::shared_ptr camera) +{ + camera->cam()->setTriggerMode(cam::Camera::TRIGGER_SOFTWARE); + setFree(free_); + connect(camera.get(), &Camera::newImage, this, &Cameras::imageRecived); + qDebug()<<"Using camera"<id(); + cameraAdded(camera); +} + void Cameras::trigger() { for(auto& camera : cameras_) @@ -108,6 +131,11 @@ bool Cameras::stop() return ret; } +void Cameras::disable(bool disable) +{ + disable_ = disable; +} + bool Cameras::setFree(bool free) { stop(); @@ -117,7 +145,10 @@ bool Cameras::setFree(bool free) for(auto& camera : cameras_) { if(!camera->cam()->setAcquisitionMode(free ? cam::Camera::MODE_FREE : cam::Camera::MODE_SINGLE)) + { + qDebug()<<"failed to set single on camera"<id(); ret = false; + } } return ret; } @@ -130,34 +161,40 @@ bool Cameras::setExposureTime(double exposureTime) for(auto& camera : cameras_) { if(!camera->cam()->setExposureTime(exposrueTime_*1000000)) + { + qDebug()<<"failed to set exposure on camera"<id(); ret = false; + } } return ret; } void Cameras::imageRecived(Camera::Image img) { - bool allreadyUpdated = false; - for(auto& camera : cameras_) + if(!disable_) { + bool allreadyUpdated = false; for(auto& image : images_) { - if(image.cameraId == camera->id()) + if(image.cameraId == img.cameraId) { allreadyUpdated = true; - goto FOUND; + break;; } } + + if(!allreadyUpdated) + images_.push_back(img); + + qDebug()<<"Recived"<> cameras_; @@ -30,11 +31,12 @@ private: private slots: void imageRecived(Camera::Image img); + void finishAddCamera(std::shared_ptr camera); signals: void cameraRemoved(std::shared_ptr camera); void cameraAdded(std::shared_ptr camera); - void newImages(std::vector images_); + void newImages(std::vector images); public slots: @@ -55,6 +57,7 @@ public: Cameras(uvosled* led = nullptr); void load(QSettings& settings); void store(QSettings& settings); + void disable(bool disable); }; #endif // CAMERAS_H diff --git a/src/imagepipeline.cpp b/src/imagepipeline.cpp index 469aca7..964aed8 100644 --- a/src/imagepipeline.cpp +++ b/src/imagepipeline.cpp @@ -1,37 +1,96 @@ #include "imagepipeline.h" #include +#include +#include #include #include +#include ImagePipeline::ImagePipeline(Cameras* cameras, QObject *parent): QObject(parent), cameras_(cameras) { + connect(cameras_, &Cameras::newImages, this, &ImagePipeline::apply); } cv::Mat ImagePipeline::process(const Profile profile, std::vector images) { + qDebug()<<__FUNCTION__<<"got"< remapedImages; remapedImages.reserve(images.size()); - for(Camera::Image& image : images) + try { - for(auto& camera : profile.cameras) + if(profile.nodistort && images.size() > 0) { - if(camera.id == image.cameraId) + for(auto& image : images) { - if(camera.darkmap.data) - image.mat = image.mat - camera.darkmap; - remapedImages.push_back(applyRemap(image.mat, camera.remapMap)); - break; + if(profile.cameras[0].id == image.cameraId) + { + RemapedImage img; + img.origin.x = 0; + img.origin.y = 0; + image.mat.copyTo(img.image); + if(profile.cameras[0].darkmap.data) + img.image = img.image - profile.cameras[0].darkmap; + remapedImages.push_back(img); + break; + } + } + } + else + { + for(Camera::Image& image : images) + { + qDebug()<<__FUNCTION__<<"image cam id"< 0) + { + 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; + if(profile.lightmap.data) + normalize(output, profile.lightmap); + + if(profile.calcurve.data) + applyCurve(output, profile.calcurve); + return output; + } + else + { + qDebug()<<"Image pipe failure insufficant matched images"; + return cv::Mat(); + } } void ImagePipeline::apply(std::vector images) @@ -41,6 +100,7 @@ void ImagePipeline::apply(std::vector images) futureImageWatchers_.push_back(new QFutureWatcher()); connect(futureImageWatchers_.back(), &QFutureWatcher::finished, this, &ImagePipeline::imageFinished); + statusMsg("Processing"); QFuture futureImage = QtConcurrent::run(&ImagePipeline::process, profile_, images); futureImageWatchers_.back()->setFuture(futureImage); } @@ -51,11 +111,20 @@ void ImagePipeline::setProfile(const Profile& profile) profile_ = profile; cameras_->setExposureTime(profile_.exposureTime); cameras_->setLighting(profile_.lighting); + qDebug()<<"setting profile "<getCameras())) { invalid_ = true; sigInvalidProfile("A camera required for this profile is not available"); } + statusMsg("set profile " + profile_.getName()); } void ImagePipeline::imageFinished() @@ -65,11 +134,18 @@ void ImagePipeline::imageFinished() if(futureImageWatchers_[i]->isFinished()) { cv::Mat result = futureImageWatchers_[i]->result(); - sigResult(Camera::Image(result, 0)); - delete futureImageWatchers_[i]; - futureImageWatchers_.erase(futureImageWatchers_.begin()+i); - i--; + if(result.data) + { + sigResult(Camera::Image(result, 0)); + delete futureImageWatchers_[i]; + futureImageWatchers_.erase(futureImageWatchers_.begin()+i); + i--; + statusMsg("Finished"); + } + else + { + sigInvalidProfile("Image pipe failure"); + } } } } - diff --git a/src/imagepipeline.h b/src/imagepipeline.h index 5ca8d86..09c09d2 100644 --- a/src/imagepipeline.h +++ b/src/imagepipeline.h @@ -30,6 +30,7 @@ private slots: signals: void sigInvalidProfile(QString message); void sigResult(Camera::Image image); + void statusMsg(QString msg); public slots: void setProfile(const Profile& profile); diff --git a/src/main.cpp b/src/main.cpp index 4bdf7ad..9bac951 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "cameras.h" #include "./ui/cameradialog.h" @@ -17,6 +18,7 @@ #include "./ui/profiledialog.h" #include "imagepipeline.h" + const char* organziation = "UVOS"; const char* application = "UVOS"; const char* version = "UVOS"; @@ -44,13 +46,18 @@ void showProfileDialog(Cameras* cameras) { qDebug()<<__FUNCTION__; cameras->stop(); + cameras->disable(true); + std::vector descs = cameras->getCameras(); ProfileDialog diag(cameras); diag.show(); diag.exec(); + cameras->disable(false); } int main(int argc, char *argv[]) { + Log::level = Log::WARN; + QApplication a(argc, argv); QCoreApplication::setOrganizationName("UVOS"); QCoreApplication::setOrganizationDomain("uvos.xyz"); @@ -61,11 +68,12 @@ int main(int argc, char *argv[]) splash.show(); QDir().mkpath(Profile::profileLocation()); - QDir().mkpath(CameraSetup::camerasLocation()); qRegisterMetaType("cv::Mat"); qRegisterMetaType("size_t"); + qRegisterMetaType("Camera::Image"); qRegisterMetaType("Image"); + qRegisterMetaType>("std::vector"); QSettings settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName()); @@ -100,11 +108,16 @@ int main(int argc, char *argv[]) QObject::connect(&w, &MainWindow::sigEditProfiles, [&cameras, &w](){showProfileDialog(&cameras); w.refreshProfiles();}); QObject::connect(&pipe, &ImagePipeline::sigResult, w.mainImageViewer(), &CvImageViewer::setImage, Qt::QueuedConnection); + 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"< #include -void CameraSetup::store() const +void CameraSetup::store(const QString &filename) const { - if(darkmap.data) - cv::imwrite(darkmapLocation(id).toStdString(), darkmap); + cv::FileStorage matf(filename.toStdString(), cv::FileStorage::APPEND); if(remapMap.xMat.data) - saveRemapMap(remapMap, remapMapLocation(id).toStdString()); + { + matf<<("_"+QString::number(id)+"_xmat").toStdString()<>bgmask; matf.release(); } -void CameraSetup::loadRemapMaps(const QString &filename) -{ - remapMap = loadRemapMap(filename.toStdString()); -} - -void CameraSetup::load(size_t cameraId) +void CameraSetup::load(const QString &filename, size_t cameraId) { id = cameraId; - loadDarkMap(darkmapLocation(id)); - loadRemapMaps(remapMapLocation(id)); - loadBgMask(bgmaskLocation(id)); -} - -QString CameraSetup::camerasLocation() -{ - return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/cameras/"; -} - -QString CameraSetup::darkmapLocation(size_t cameraId) -{ - return camerasLocation() + QString::number(cameraId) + ".darkmap.png"; -} - -QString CameraSetup::bgmaskLocation(size_t cameraId) -{ - return camerasLocation() + QString::number(cameraId) + "bgmask.mat"; -} - -QString CameraSetup::remapMapLocation(size_t cameraId) -{ - return camerasLocation() + QString::number(cameraId) + "remap.mat"; + cv::FileStorage matf(filename.toStdString(), cv::FileStorage::READ); + if (matf.isOpened()) + { + matf[("_"+QString::number(id)+"_darkmap").toStdString()]>>darkmap; + matf[("_"+QString::number(id)+"_bgmask").toStdString()]>>bgmask; + matf[("_"+QString::number(id)+"_xmat").toStdString()]>>remapMap.xMat; + matf[("_"+QString::number(id)+"_ymat").toStdString()]>>remapMap.yMat; + matf[("_"+QString::number(id)+"_origin").toStdString()]>>remapMap.topLeftCoordinate; + } + else + { + qDebug()<<"could not open file"<(id)); settings.setValue(GROUP + QString("/exposureTime"), exposureTime); settings.setValue(GROUP + QString("/name"), name_); + settings.setValue(GROUP + QString("/nodistort"), nodistort); if(lightmap.data) cv::imwrite((profileLocation() + QString::number(id) + ".lightmap.png").toStdString(), lightmap); @@ -93,10 +72,18 @@ void Profile::store(QSettings& settings) const { const CameraSetup& camera = cameras[i]; settings.setArrayIndex(i); - camera.store(); + camera.store(profileLocation() + name_ + ".profile.mat"); settings.setValue("id", static_cast(camera.id)); } settings.endArray(); + + cv::FileStorage matf((profileLocation() + name_ + ".calcurve.mat").toStdString(), cv::FileStorage::WRITE); + matf<<"cal"<>calcurve; + matf.release(); + + if(calcurve.data && (calcurve.type() != CV_32FC1 || calcurve.rows != 2)) + calcurve.release(); + + cv::FileStorage matfl((profileLocation() + name_ + ".lightmap.mat").toStdString(), cv::FileStorage::READ); + matfl["cal"]>>lightmap; + matfl.release(); } void Profile::load(const QString& name) @@ -164,15 +163,43 @@ QList Profile::avaiableProfiles() return ret; } -void Profile::setCamerasSetupsFromDescription(const std::vector& desc) +void Profile::setCamerasSetupsFromDescription(const std::vector& descs) { - cameras.clear(); - cameras.reserve(desc.size()); - for(size_t i = 0; i < desc.size(); ++i) + for(size_t i = 0; i < cameras.size(); ++i) { - CameraSetup tmp; - tmp.load(desc[i].getHash()); - cameras.push_back(tmp); + bool found = false; + for(auto& cameraDesc : descs) + { + if(cameras[i].id == cameraDesc.getId()) + { + found = true; + break; + } + } + if(!found) + { + cameras.erase(cameras.begin()+i); + --i; + } + } + + for(size_t i = 0; i < descs.size(); ++i) + { + bool found = false; + for(auto& camera : cameras) + { + if(camera.id == descs[i].getId()) + { + found = true; + break; + } + } + if(!found) + { + CameraSetup tmp; + tmp.load(profileLocation() + name_ + ".profile.mat", descs[i].getId()); + cameras.push_back(tmp); + } } } @@ -184,7 +211,7 @@ bool Profile::camerasSufficant(const std::vector& desc bool found = false; for(auto& camera : desc) { - if(camera.getHash() == cameraProfile.id) + if(camera.getId() == cameraProfile.id) { found = true; break; diff --git a/src/profile.h b/src/profile.h index 561787d..3eeae19 100644 --- a/src/profile.h +++ b/src/profile.h @@ -16,15 +16,8 @@ public: RemapMap remapMap; cv::Mat darkmap; cv::Mat bgmask; - void store() const; - void load(size_t cameraId); - void loadBgMask(const QString& filename); - void loadDarkMap(const QString& filename); - void loadRemapMaps(const QString& filename); - static QString camerasLocation(); - static QString remapMapLocation(size_t cameraId); - static QString bgmaskLocation(size_t cameraId); - static QString darkmapLocation(size_t cameraId); + void store(const QString& filename) const; + void load(const QString& name, size_t cameraId); }; class LightingSetup @@ -50,7 +43,9 @@ public: LightingSetup lighting; double exposureTime = 1.0/60.0; cv::Mat lightmap; + cv::Mat calcurve; std::vector cameras; + bool nodistort = false; Profile(const QString& name = "Unamed"); void store(QSettings& settings) const; diff --git a/src/ui/cameradialog.ui b/src/ui/cameradialog.ui index b01d46c..8c8e927 100644 --- a/src/ui/cameradialog.ui +++ b/src/ui/cameradialog.ui @@ -16,6 +16,10 @@ Select Cameras + + + :/images/icon.png:/images/icon.png + @@ -46,7 +50,9 @@
./src/ui/cameralistwidget.h
- + + + buttonBox diff --git a/src/ui/cameralistwidget.cpp b/src/ui/cameralistwidget.cpp index d7e1dc8..879cfd1 100644 --- a/src/ui/cameralistwidget.cpp +++ b/src/ui/cameralistwidget.cpp @@ -20,7 +20,7 @@ void CameraListWidget::setConfigured(std::vector configured) setHorizontalHeaderItem(1, new QTableWidgetItem("Configured")); for(size_t i = 0; i < desc_.size() && i < configured.size(); ++i) { - setItem(static_cast(i), 1, new QTableWidgetItem("No")); + setItem(static_cast(i), 1, new QTableWidgetItem(configured[i] ? "Yes" : "No")); qDebug()<<"Set item "<& d setRowCount(static_cast(desc_.size())); for(size_t i = 0; i < desc_.size(); ++i) { - setItem(static_cast(i), 0, new QTableWidgetItem((desc_[i].vendor + " " + desc_[i].model).c_str())); + setItem(static_cast(i), 0, new QTableWidgetItem((desc_[i].getVendor() + " " + desc_[i].getModel()).c_str())); } } diff --git a/src/ui/configurecameradialog.cpp b/src/ui/configurecameradialog.cpp index b7622c0..b311528 100644 --- a/src/ui/configurecameradialog.cpp +++ b/src/ui/configurecameradialog.cpp @@ -7,20 +7,26 @@ #include #include #include +#include ConfigureCameraDialog::ConfigureCameraDialog(const CameraSetup& setup, std::shared_ptr camera, double exposureTime, QWidget *parent): QDialog(parent), setup_(setup), camera_(camera), + profileExposure_(exposureTime), ui(new Ui::ConfigureCameraDialog) { ui->setupUi(this); + qDebug()<<"profileExposure_"<doubleSpinBox->setValue(profileExposure_); + setExposure(profileExposure_); - ui->doubleSpinBox->setValue(exposureTime); + uint64_t min, max; + camera_->cam()->getExposureTimeLimits(min, max); + ui->doubleSpinBox->setMaximum(max/1000000.0); + ui->doubleSpinBox->setMinimum(min/1000000.0); - connect(ui->pushButtonBgLoad, &QPushButton::clicked, this, &ConfigureCameraDialog::loadBg); - connect(ui->pushButtonRemapLoad, &QPushButton::clicked, this, &ConfigureCameraDialog::loadRemap); - connect(ui->pushButtonDarkImageLoad, &QPushButton::clicked, this, &ConfigureCameraDialog::loadDark); + connect(ui->doubleSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), this, &ConfigureCameraDialog::setExposure); connect(ui->pushButtonBgClear, &QPushButton::clicked, [this](){setup_.bgmask.release(); checkConfig();}); connect(ui->pushButtonRemapClear, &QPushButton::clicked, [this](){setup_.remapMap = RemapMap(); checkConfig();}); connect(ui->pushButtonDarkImageClear, &QPushButton::clicked, [this](){setup_.darkmap.release(); checkConfig();}); @@ -38,45 +44,12 @@ ConfigureCameraDialog::~ConfigureCameraDialog() delete ui; } - - -void ConfigureCameraDialog::loadBg() +void ConfigureCameraDialog::setExposure(double value) { - QString filename = QFileDialog::getOpenFileName(this, tr("Open Background Mask"), CameraSetup::camerasLocation(), "OpenCV Mat (*.mat)"); - if(!filename.isEmpty()) - { - setup_.loadBgMask(filename); - if(!setup_.bgmask.data) - QMessageBox::warning(this, "Warning", "Could not load " + filename); - checkConfig(); - } -} - -void ConfigureCameraDialog::loadRemap() -{ - QString filename = QFileDialog::getOpenFileName(this, tr("Open Background Mask"), CameraSetup::camerasLocation(), "OpenCV Mat (*.mat)"); - if(!filename.isEmpty()) - { - setup_.loadRemapMaps(filename); - if(!setup_.remapMap.xMat.data || !setup_.remapMap.yMat.data) - { - QMessageBox::warning(this, "Warning", "Could not load " + filename); - setup_.remapMap = RemapMap(); - } - checkConfig(); - } -} - -void ConfigureCameraDialog::loadDark() -{ - QString filename = QFileDialog::getOpenFileName(this, tr("Open Background Mask"), CameraSetup::camerasLocation(), "Image (*.png)"); - if(!filename.isEmpty()) - { - setup_.loadDarkMap(filename); - if(!setup_.darkmap.data) - QMessageBox::warning(this, "Warning", "Could not load " + filename); - checkConfig(); - } + if(!camera_->cam()->setExposureTime(value*1000000.0)) + QMessageBox::warning(this, "Warning", "Failed to set exposure"); + else + qDebug()<<"set exposure to "< points = detectCharucoPoints(img.mat, false); if(points.size() < 8) { @@ -117,13 +95,13 @@ void ConfigureCameraDialog::gotImage(Camera::Image img) break; } RemapMap map; - if(createRemapMap(img.mat, map, points)) + if(createRemapMap(masked, map, points)) setup_.remapMap = map; else QMessageBox::warning(this, "Failed", "Error creating map"); for(size_t i = 0; i < points.size(); ++i) - cv::circle(img.mat, points[i].point, 5, cv::Scalar(0,255,0), 1); - ui->widget_4->setImage(Camera::Image(setup_.bgmask, camera_->id())); + cv::circle(img.mat, points[i].point, img.mat.cols/50, cv::Scalar(255,255,255), img.mat.cols/200); + ui->widget_4->setImage(Camera::Image(img.mat, camera_->id())); mode_ = MODE_IDLE; break; } @@ -157,6 +135,8 @@ void ConfigureCameraDialog::captureDark() { QMessageBox::information(this, "Cover lense", "Please cover the lense of the camera."); mode_ = MODE_DARK_GET; + ui->doubleSpinBox->setValue(profileExposure_); + setExposure(profileExposure_); takeImage(); } @@ -165,7 +145,7 @@ void ConfigureCameraDialog::accept() if(checkConfig()) QDialog::accept(); else - QMessageBox::warning(this, "Unfinished", "Can not accept unfinished camera setup"); + QMessageBox::information(this, "Unfinished", "Can not accept unfinished camera setup"); } bool ConfigureCameraDialog::checkConfig() @@ -182,5 +162,5 @@ bool ConfigureCameraDialog::checkConfig() ui->ledDark->setLit(darkMapOK); ui->ledRemap->setLit(remapMapOk); - return bgOk && remapMapOk && darkMapOK; + return remapMapOk; } diff --git a/src/ui/configurecameradialog.h b/src/ui/configurecameradialog.h index ec5d60f..1566b7d 100644 --- a/src/ui/configurecameradialog.h +++ b/src/ui/configurecameradialog.h @@ -22,25 +22,27 @@ class ConfigureCameraDialog : public QDialog std::shared_ptr camera_; int mode_ = MODE_IDLE; cv::Mat fgImage; + double profileExposure_; private: bool checkConfig(); void gotImage(Camera::Image img); private slots: - void loadBg(); - void loadRemap(); - void loadDark(); void captureBg(); void captureRemap(); void captureDark(); void takeImage(); + void setExposure(double value); + +public slots: + void accept() override; public: explicit ConfigureCameraDialog(const CameraSetup& setup, const std::shared_ptr camera, double exposureTime = 1.0/60, QWidget *parent = nullptr); ~ConfigureCameraDialog(); CameraSetup getCameraSetup(){return setup_;} - void accept() override; + private: Ui::ConfigureCameraDialog *ui; diff --git a/src/ui/configurecameradialog.ui b/src/ui/configurecameradialog.ui index 4bf1a50..94fd5f5 100644 --- a/src/ui/configurecameradialog.ui +++ b/src/ui/configurecameradialog.ui @@ -6,8 +6,8 @@ 0 0 - 466 - 438 + 545 + 614 @@ -31,6 +31,29 @@ 6 + + + + + 0 + 0 + + + + + 40 + 40 + + + + + + + + Create + + + @@ -48,13 +71,6 @@ - - - - Background image - - - @@ -62,32 +78,6 @@ - - - - false - - - Clear - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - @@ -98,57 +88,40 @@ - - + + - Create + Background image - - - - - + + - Remap Map + Show - - - - Load - - - - - - - Load - - - - - + + - + 0 0 - 0 - 0 + 40 + 40 - - + + - Load + Show @@ -159,10 +132,36 @@
- - + + + + + 0 + 0 + + + + + 40 + 40 + + + + + + - + Remap Map (required) + + + + + + + false + + + Clear @@ -182,11 +181,14 @@ + + 5 + 1.000000000000000 - 0.100000000000000 + 0.001000000000000 @@ -219,18 +221,18 @@
- - Led - QWidget -
./src/ui/led.h
- 1 -
CvImageViewer QWidget
./src/ui/cvimageviewer.h
1
+ + Led + QWidget +
./src/ui/led.h
+ 1 +
diff --git a/src/ui/cvimageviewer.cpp b/src/ui/cvimageviewer.cpp index 8d380c7..3b864df 100644 --- a/src/ui/cvimageviewer.cpp +++ b/src/ui/cvimageviewer.cpp @@ -1,21 +1,60 @@ #include "cvimageviewer.h" #include #include +#include +#include +#include CvImageViewer::CvImageViewer(QWidget *parent, size_t lastId) : QWidget(parent), - lastId_(lastId) + lastId_(lastId), + saveAction_("Save Image", nullptr) { + connect(&saveAction_, &QAction::triggered, this, &CvImageViewer::saveImage); qimage_.load(":/images/noimage.png"); + + imageContextMenu_.addAction(&saveAction_); } 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" ); + } + if(!fileName.isEmpty()) + { + QStringList tokens = fileName.split('.'); + if(tokens.back() != "mat" && tokens.back() != "png") + 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"<button() == Qt::RightButton) + { + saveAction_.setEnabled(origImage_.data); + imageContextMenu_.popup(event->globalPos()); + } + else if(origImage_.data && event->x() > imgrect_.x() && event->y() > imgrect_.y() && event->x() < imgrect_.x()+imgrect_.width() && event->y() < imgrect_.y()+imgrect_.height()) + { + int x = (event->x()-imgrect_.x())/static_cast(imgrect_.width())*origImage_.cols; + int y = (event->y()-imgrect_.y())/static_cast(imgrect_.height())*origImage_.rows; + qDebug()<= 0 && y >= 0 && x <= origImage_.cols && y < origImage_.rows) + sigValue(x, y, origImage_.at(y,x)); + } + else + { + + sigValue(x, y, 0); + } + } + QWidget::mousePressEvent(event); +} + void CvImageViewer::paintEvent(QPaintEvent* event) { Q_UNUSED(event) QPainter painter(this); - if(!fixedOnWidth_) - { - double ratio = qimage_.size().width() / qimage_.size().height(); - painter.drawImage(QRect((rect().width()-rect().height())/2, rect().y(), rect().height()*ratio, rect().height()), qimage_); - } + double ratio = qimage_.size().height() / (double)qimage_.size().width(); + if(rect().width()*ratio <= rect().height()) + imgrect_.setRect(0, (rect().height()-rect().width()*ratio)/2, rect().width(), rect().width()*ratio); else - { - double ratio = qimage_.size().height() / qimage_.size().width(); - painter.drawImage(QRect(rect().x(), (rect().height()-rect().width())/2, rect().width(), rect().width()*ratio), qimage_); - } + imgrect_.setRect((rect().width()-rect().height()/ratio)/2, 0, rect().height()/ratio, rect().height()); + painter.drawImage(imgrect_, qimage_); } diff --git a/src/ui/cvimageviewer.h b/src/ui/cvimageviewer.h index 58b0f77..f932a99 100644 --- a/src/ui/cvimageviewer.h +++ b/src/ui/cvimageviewer.h @@ -3,19 +3,32 @@ #include #include +#include #include "../cameras.h" class CvImageViewer : public QWidget { Q_OBJECT +private: + cv::Mat origImage_; cv::Mat image_; QImage qimage_; bool fixedOnWidth_ = false; size_t lastId_; + QMenu imageContextMenu_; + QAction saveAction_; + QRect imgrect_; + +private slots: + void saveImage(); protected: virtual void paintEvent(QPaintEvent* event) override; + virtual void mousePressEvent(QMouseEvent *event) override; + +signals: + void sigValue(size_t x, size_t y, double value); public slots: void setImage(Camera::Image img); @@ -23,6 +36,8 @@ public slots: public: explicit CvImageViewer(QWidget *parent = nullptr, size_t lastId = 0); void setFixedOnWidth(bool in){fixedOnWidth_ = in;} + cv::Mat getImage(){return origImage_;} + size_t lastId(){return lastId_;} ~CvImageViewer(); }; diff --git a/src/ui/editprofiledialog.cpp b/src/ui/editprofiledialog.cpp index 0bdaf99..9b54db9 100644 --- a/src/ui/editprofiledialog.cpp +++ b/src/ui/editprofiledialog.cpp @@ -2,6 +2,8 @@ #include "ui_editprofiledialog.h" #include #include +#include +#include #include "configurecameradialog.h" @@ -24,26 +26,91 @@ EditProfileDialog::EditProfileDialog(Cameras* cameras, const Profile profile, QW ui->checkBoxCh3->setChecked(profile_.lighting.mask & CHANNEL_C); ui->checkBoxCh4->setChecked(profile_.lighting.mask & CHANNEL_D); - if(profile_.cameras.size() == 0) - profile_.setCamerasSetupsFromDescription(cameras_->getCameras()); + ui->checkBoxNodistort->setChecked(profile_.nodistort); + + std::vector descs = cameras_->getCameras(); + profile_.setCamerasSetupsFromDescription(descs); + + if(profile_.cameras.size() > 0) + { + uint64_t min, max; + std::shared_ptr cam = cameras_->getCamera(profile_.cameras[0].id); + if(cam) + { + cam->cam()->getExposureTimeLimits(min, max); + ui->doubleSpinBoxExposure->setMaximum(max/1000000.0); + ui->doubleSpinBoxExposure->setMinimum(min/1000000.0); + } + } + + ui->calLed->setLit(profile_.calcurve.data); connect(ui->doubleSpinBoxBrightness, QOverload::of(&QDoubleSpinBox::valueChanged), [this](double in){profile_.lighting.brightness = in/100.0;}); - connect(ui->doubleSpinBoxExposure, QOverload::of(&QDoubleSpinBox::valueChanged), [this](double in){profile_.exposureTime = in;}); + connect(ui->doubleSpinBoxExposure, QOverload::of(&QDoubleSpinBox::valueChanged), [this](double in){profile_.exposureTime = in; invalidateCameras();}); 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); connect(ui->checkBoxCh3, &QCheckBox::clicked, this, &EditProfileDialog::setMask); connect(ui->checkBoxCh4, &QCheckBox::clicked, this, &EditProfileDialog::setMask); connect(ui->pushButton, &QPushButton::clicked, this, &EditProfileDialog::configureCamera); + connect(ui->checkBoxNodistort, &QCheckBox::stateChanged, [this](int state){profile_.nodistort = state == Qt::Checked ?: false; setConfigured();}); + connect(ui->pushButtonCalLoad, &QPushButton::clicked, this, &EditProfileDialog::loadCalcurve); + connect(ui->pushButtonLightmapLoad, &QPushButton::clicked, this, &EditProfileDialog::loadCalcurve); ui->listView->setCameras(cameras_->getCameras()); ui->listView->setSelectionMode(QAbstractItemView::SingleSelection); setConfigured(); } -void EditProfileDialog::setConfigured() +void EditProfileDialog::loadLightmap() +{ + QString fileName = QFileDialog::getOpenFileName(this, "Open Lightmap", "./", "*.mat"); + if(!fileName.isEmpty()) + { + profile_.calcurve.release(); + cv::FileStorage matf(fileName.toStdString(), cv::FileStorage::READ); + matf["image"]>>profile_.lightmap; + + if(matf.isOpened() && (!profile_.calcurve.data || profile_.calcurve.type() != CV_32FC1)) + { + profile_.lightmap.release(); + QMessageBox::warning(this, "Invalid file", "File selected dose not contain a valid lightmap"); + } + else if(!profile_.calcurve.data) + { + QMessageBox::warning(this, "Can no open", "Can not open file selected"); + } + matf.release(); + ui->ledLightmap->setLit(profile_.lightmap.data); + } +} + +void EditProfileDialog::loadCalcurve() +{ + QString fileName = QFileDialog::getOpenFileName(this, "Open Cal Curve", "./", "*.mat"); + if(!fileName.isEmpty()) + { + profile_.calcurve.release(); + cv::FileStorage matf(fileName.toStdString(), cv::FileStorage::READ); + matf["cal"]>>profile_.calcurve; + + if(matf.isOpened() && (!profile_.calcurve.data || profile_.calcurve.type() != CV_32FC1 || profile_.calcurve.rows != 2)) + { + profile_.calcurve.release(); + QMessageBox::warning(this, "Invalid file", "File selected dose not contain a valid cal curve"); + } + else if(!profile_.calcurve.data) + { + QMessageBox::warning(this, "Can no open", "Can not open file selected"); + } + matf.release(); + ui->calLed->setLit(profile_.calcurve.data); + } +} + +bool EditProfileDialog::setConfigured() { std::vector descs = cameras_->getCameras(); - std::vector configured(descs.size(), false); + std::vector configured(descs.size(), profile_.nodistort); for(size_t i = 0; i< profile_.cameras.size(); ++i) { @@ -52,12 +119,19 @@ void EditProfileDialog::setConfigured() { for(auto& camera : descs) { - if(camera.getHash() == profileCamera.id) + if(camera.getId() == profileCamera.id) configured[i] = true; } } } ui->listView->setConfigured(configured); + bool fullyConfigured = true; + for(bool config : configured) + { + if(!config) + fullyConfigured = false; + } + return fullyConfigured; } void EditProfileDialog::invalidateCameras() @@ -78,10 +152,12 @@ void EditProfileDialog::configureCamera() qDebug()<<"descs"< camera = cameras_->getCamera(profile_.cameras[i].id); if(camera) @@ -94,9 +170,18 @@ void EditProfileDialog::configureCamera() } } } + setConfigured(); } } +void EditProfileDialog::accept() +{ + if(!setConfigured()) + QMessageBox::information(this, "Unfinished", "Can not accept with unconfigured cameras"); + else + QDialog::accept(); +} + void EditProfileDialog::setMask() { uint8_t mask = (ui->checkBoxCh1->isChecked() ? CHANNEL_A : 0) | diff --git a/src/ui/editprofiledialog.h b/src/ui/editprofiledialog.h index 5bfc50c..6a899c8 100644 --- a/src/ui/editprofiledialog.h +++ b/src/ui/editprofiledialog.h @@ -15,13 +15,17 @@ class EditProfileDialog : public QDialog Profile profile_; Cameras* cameras_; - void setConfigured(); + bool setConfigured(); void invalidateCameras(); private slots: - void setMask(); void configureCamera(); + void loadCalcurve(); + void loadLightmap(); + +public slots: + virtual void accept() override; public: explicit EditProfileDialog(Cameras* cameras, const Profile profile = Profile(), QWidget *parent = nullptr); diff --git a/src/ui/editprofiledialog.ui b/src/ui/editprofiledialog.ui index 7e9783b..25d8a49 100644 --- a/src/ui/editprofiledialog.ui +++ b/src/ui/editprofiledialog.ui @@ -7,11 +7,11 @@ 0 0 539 - 485 + 652 - Profile + Edit Profile @@ -153,6 +153,9 @@ + + 5 + 1.000000000000000 @@ -176,9 +179,89 @@ + + + + Don't undisort camera image + + + + + + + 10 + + + + + Calibration curve: + + + + + + + + 0 + 0 + + + + + 40 + 40 + + + + + + + + + 0 + 0 + + + + Load + + + + + + + Lightmap: + + + + + + + + 0 + 0 + + + + + 40 + 40 + + + + + + + + Load + + + + + @@ -192,6 +275,12 @@ + + Led + QWidget +
./src/ui/led.h
+ 1 +
CameraListWidget QListView diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 7782173..2cf7348 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../profile.h" @@ -17,9 +18,62 @@ MainWindow::MainWindow(QWidget *parent) connect(ui->actionProfile, &QAction::triggered, [this](bool checked){(void)checked; sigEditProfiles();}); connect(ui->comboBox, &QComboBox::currentTextChanged, this, &MainWindow::sigProfile); connect(ui->pushButtonCapture, &QPushButton::clicked, this, &MainWindow::sigCapture); + connect(ui->mainViewer, &CvImageViewer::sigValue, this, &MainWindow::setImageValue); + connect(ui->actionOpen, &QAction::triggered, [this](bool checked){(void)checked; openImage();}); + connect(ui->actionSave_2, &QAction::triggered, [this](bool checked){(void)checked; saveImage();}); refreshProfiles(); } +void MainWindow::setImageValue(size_t x, size_t y, double value) +{ + ui->lcdNumber_3->display((double)x); + ui->lcdNumber_2->display((double)y); + ui->lcdNumber->display(value); +} + +void MainWindow::saveImage() +{ + if(!ui->mainViewer->getImage().data) + { + QMessageBox::warning(this, "No image", "There is no image to save"); + return; + } + + QString fileName = QFileDialog::getSaveFileName(this, "Save Image", "./", "*.mat"); + if(!fileName.isEmpty()) + { + QStringList tokens = fileName.split('.'); + if(tokens.back() != "mat") + fileName.append(".mat"); + cv::FileStorage matf(fileName.toStdString(), cv::FileStorage::WRITE); + matf<<"image"<mainViewer->getImage(); + matf.release(); + } +} + +void MainWindow::openImage() +{ + QString fileName = QFileDialog::getOpenFileName(this, "Open Image", "./", "*.mat"); + if(!fileName.isEmpty()) + { + cv::Mat image; + cv::FileStorage matf(fileName.toStdString(), cv::FileStorage::READ); + matf["image"]>>image; + + if(matf.isOpened() && (!image.data || image.type() != CV_32FC1)) + { + image.release(); + QMessageBox::warning(this, "Invalid file", "File selected dose not contain a valid lightmap"); + } + else if(!image.data) + { + QMessageBox::warning(this, "Can no open", "Can not open file selected"); + } + matf.release(); + ui->mainViewer->setImage(Camera::Image(image, 0)); + } +} + void MainWindow::addCamera(std::shared_ptr camera) { viewers_.push_back(new CvImageViewer(this, camera->id())); @@ -28,6 +82,11 @@ void MainWindow::addCamera(std::shared_ptr camera) ui->viewerLayout->addWidget(viewers_.back()); } +void MainWindow::statusMsg(QString msg) +{ + ui->statusbar->showMessage(msg); +} + void MainWindow::removeCamera(std::shared_ptr camera) { for(size_t i = 0; i < viewers_.size(); ++i) @@ -93,4 +152,3 @@ MainWindow::~MainWindow() delete viewer; delete ui; } - diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 5fd0f33..0f33bd9 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -16,6 +16,11 @@ class MainWindow : public QMainWindow private: std::vector viewers_; +private slots: + void setImageValue(size_t x, size_t y, double value); + void saveImage(); + void openImage(); + signals: void sigCapture(); void sigProfile(QString profileName); @@ -30,6 +35,7 @@ public slots: void removeCamera(std::shared_ptr camera); bool setProfile(const QString& profileName); QString getProfileName(); + void statusMsg(QString msg); public: MainWindow(QWidget *parent = nullptr); diff --git a/src/ui/mainwindow.ui b/src/ui/mainwindow.ui index 3ae254c..784b7f2 100644 --- a/src/ui/mainwindow.ui +++ b/src/ui/mainwindow.ui @@ -11,7 +11,11 @@ - MainWindow + Lubricant Detector + + + + :/images/icon.png:/images/icon.png @@ -27,6 +31,9 @@ + + Qt::ScrollBarAsNeeded + true @@ -68,7 +75,7 @@ 0 0 467 - 353 + 313 @@ -79,6 +86,55 @@
+ + + + 10 + + + + + Qt::LeftToRight + + + X + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Y + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Value + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + @@ -146,7 +202,8 @@ File - + + @@ -164,6 +221,9 @@ Quit + + Ctrl+Q + @@ -180,6 +240,22 @@ Save + + + Save + + + Ctrl+S + + + + + Open + + + Ctrl+O + + @@ -189,6 +265,8 @@ 1 - + + + diff --git a/src/ui/profiledialog.cpp b/src/ui/profiledialog.cpp index c6fdaec..a6f04ff 100644 --- a/src/ui/profiledialog.cpp +++ b/src/ui/profiledialog.cpp @@ -34,7 +34,7 @@ void ProfileDialog::editProfile() QMessageBox::critical(this, "Profile Incompatible", "Not all cameras need for this profile are available"); return; } - EditProfileDialog dialog(cameras_, profile); + EditProfileDialog dialog(cameras_, profile, this); dialog.show(); int ret = dialog.exec(); if(ret == QDialog::Accepted) diff --git a/src/ui/profiledialog.ui b/src/ui/profiledialog.ui index c2b3e9c..9c07933 100644 --- a/src/ui/profiledialog.ui +++ b/src/ui/profiledialog.ui @@ -13,6 +13,10 @@ Profiles + + + :/images/icon.png:/images/icon.png + @@ -61,7 +65,9 @@ - + + + buttonBox