commit 19c47100c24c7c9a5a449fc9e708ed5673c62f7c Author: Filip Orsag Date: Mon Mar 14 12:14:39 2016 +0100 Initial commit. diff --git a/customgraphicsview.cpp b/customgraphicsview.cpp new file mode 100644 index 0000000..db2b31a --- /dev/null +++ b/customgraphicsview.cpp @@ -0,0 +1,13 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file customgraphicsview.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include "customgraphicsview.h" + +void CustomGraphicsView::mousePressEvent(QMouseEvent *event) { + emit colorPickerPosition(event->x(), event->y()); + } diff --git a/customgraphicsview.h b/customgraphicsview.h new file mode 100644 index 0000000..947157a --- /dev/null +++ b/customgraphicsview.h @@ -0,0 +1,28 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file customgraphicsview.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef CUSTOMGRAPHICSVIEW_H +#define CUSTOMGRAPHICSVIEW_H + +#include +#include + +class CustomGraphicsView : public QGraphicsView +{ + Q_OBJECT +public: + void mousePressEvent(QMouseEvent *event); + +signals: + void colorPickerPosition(int, int); + +public slots: + +}; + +#endif // CUSTOMGRAPHICSVIEW_H diff --git a/images/application.ico b/images/application.ico new file mode 100644 index 0000000..6b87afc Binary files /dev/null and b/images/application.ico differ diff --git a/images/icons/analyzeEdges.png b/images/icons/analyzeEdges.png new file mode 100644 index 0000000..bd88930 Binary files /dev/null and b/images/icons/analyzeEdges.png differ diff --git a/images/icons/btn_addLayers.png b/images/icons/btn_addLayers.png new file mode 100644 index 0000000..070e4aa Binary files /dev/null and b/images/icons/btn_addLayers.png differ diff --git a/images/icons/btn_analyzeLayers.png b/images/icons/btn_analyzeLayers.png new file mode 100644 index 0000000..fa242c1 Binary files /dev/null and b/images/icons/btn_analyzeLayers.png differ diff --git a/images/icons/close.png b/images/icons/close.png new file mode 100644 index 0000000..2b31702 Binary files /dev/null and b/images/icons/close.png differ diff --git a/images/icons/delete.png b/images/icons/delete.png new file mode 100644 index 0000000..ce4eb18 Binary files /dev/null and b/images/icons/delete.png differ diff --git a/images/icons/exit.png b/images/icons/exit.png new file mode 100644 index 0000000..fddbc2b Binary files /dev/null and b/images/icons/exit.png differ diff --git a/images/icons/help.png b/images/icons/help.png new file mode 100644 index 0000000..d60425f Binary files /dev/null and b/images/icons/help.png differ diff --git a/images/icons/newProject.png b/images/icons/newProject.png new file mode 100644 index 0000000..e091702 Binary files /dev/null and b/images/icons/newProject.png differ diff --git a/images/icons/openImage.png b/images/icons/openImage.png new file mode 100644 index 0000000..6f118cd Binary files /dev/null and b/images/icons/openImage.png differ diff --git a/images/icons/openProject.png b/images/icons/openProject.png new file mode 100644 index 0000000..f35f258 Binary files /dev/null and b/images/icons/openProject.png differ diff --git a/images/icons/save-as.png b/images/icons/save-as.png new file mode 100644 index 0000000..0a213db Binary files /dev/null and b/images/icons/save-as.png differ diff --git a/images/icons/save.png b/images/icons/save.png new file mode 100644 index 0000000..1732110 Binary files /dev/null and b/images/icons/save.png differ diff --git a/images/icons/settings.png b/images/icons/settings.png new file mode 100644 index 0000000..6e52db7 Binary files /dev/null and b/images/icons/settings.png differ diff --git a/images/icons/zoom-fit.png b/images/icons/zoom-fit.png new file mode 100644 index 0000000..586a252 Binary files /dev/null and b/images/icons/zoom-fit.png differ diff --git a/images/icons/zoom-in.png b/images/icons/zoom-in.png new file mode 100644 index 0000000..0ab0f8a Binary files /dev/null and b/images/icons/zoom-in.png differ diff --git a/images/icons/zoom-orig.png b/images/icons/zoom-orig.png new file mode 100644 index 0000000..3f5d89d Binary files /dev/null and b/images/icons/zoom-orig.png differ diff --git a/images/icons/zoom-out.png b/images/icons/zoom-out.png new file mode 100644 index 0000000..6e4848e Binary files /dev/null and b/images/icons/zoom-out.png differ diff --git a/images/wizard/wmark.png b/images/wizard/wmark.png new file mode 100644 index 0000000..79c1ba2 Binary files /dev/null and b/images/wizard/wmark.png differ diff --git a/layercomposer.cpp b/layercomposer.cpp new file mode 100644 index 0000000..835ccd5 --- /dev/null +++ b/layercomposer.cpp @@ -0,0 +1,87 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file layercomposer.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include "layercomposer.h" +#include + +LayerComposer::LayerComposer(QWidget *parent) : QMainWindow(parent) { +} + +QImage LayerComposer::composeLayers (std::vector importedLayers, + std::vector analysingLayers, + std::vector importedIndexes, + std::vector analysingIndexes, + QString &bgRootDir, + QString &overLayRootDir) { + + + QString bgImgFileName; + for (unsigned int i = 0; i < importedIndexes.size(); i++) { + bgImgFileName = importedLayers[importedIndexes[i]]; + } + bgImgFileName = bgRootDir + bgImgFileName; + + // final image + // size is taken from the background bitmap + QImage bgImage(bgImgFileName); + QImage resultImage = QImage(bgImage.width(), bgImage.height(), QImage::Format_ARGB32_Premultiplied); + QPainter painter(&resultImage); + + // draw background + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(resultImage.rect(), Qt::transparent); + + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + painter.drawImage(0, 0, bgImage); + // ---------------------- + + QString overlayFileName; + QString srcAddr = overLayRootDir; + for (unsigned int i = 0; i < analysingIndexes.size(); i++) { + overlayFileName = srcAddr + analysingLayers[analysingIndexes[i]]; + + // mask black colour + QPixmap mypixmap(overlayFileName); + mypixmap.setMask(mypixmap.createMaskFromColor(Qt::black)); + + // draw given image + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + painter.drawPixmap(0, 0, mypixmap); + } + + painter.end(); + return resultImage; + } + + +QImage LayerComposer::maskSelectedLayer(QString &bgImageFileName, QString &bgRootDir, QRgb maskColor, int rThrsh, int gThrsh, int bThrsh ) { + + QImage image(bgRootDir + bgImageFileName); + OpenCVprocessor * cvProcessor = new OpenCVprocessor(); + + image = cvProcessor->normalizeImage(&image, qRed(maskColor), qGreen(maskColor), qBlue(maskColor), rThrsh, gThrsh, bThrsh); + QPixmap maskPixmap = QPixmap::fromImage(image); + + QPixmap myPixmap(bgRootDir + bgImageFileName); + QImage resultImage = QImage(myPixmap.width(), myPixmap.height(), QImage::Format_ARGB32_Premultiplied); + QPainter painter(&resultImage); + + // draw background - black + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(resultImage.rect(), Qt::black); + + // draw background masked from OpenCV + myPixmap.setMask(maskPixmap.createMaskFromColor(Qt::black)); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + painter.drawPixmap(0, 0, myPixmap); + + painter.end(); + + return resultImage; +} + diff --git a/layercomposer.h b/layercomposer.h new file mode 100644 index 0000000..832b3c4 --- /dev/null +++ b/layercomposer.h @@ -0,0 +1,40 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file layercomposer.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef LAYERCOMPOSER_H +#define LAYERCOMPOSER_H + +#include +#include + +#include "opencvprocessor.h" + +// singleton +#include "project.h" + +class LayerComposer : public QMainWindow +{ + Q_OBJECT +public: + explicit LayerComposer(QWidget *parent = 0); + QImage composeLayers (std::vector importedLayers, + std::vector analysingLayersLayers, + std::vector importedIndexes, + std::vector analysingIndexes, + QString &bgRootDir, + QString &overLayRootDir); + QImage maskSelectedLayer(QString &bgImageFileName, QString &bgRootDir, QRgb maskColor, int rThrsh, int gThrsh, int bThrsh); + QImage composeHistograms (QImage * bgImage); + +signals: + +public slots: + +}; + +#endif // LAYERCOMPOSER_H diff --git a/layerrecord.cpp b/layerrecord.cpp new file mode 100644 index 0000000..c124ec4 --- /dev/null +++ b/layerrecord.cpp @@ -0,0 +1,42 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file layerrecord.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include "layerrecord.h" + +LayerRecord::LayerRecord(QObject *parent) : QObject(parent) { +} + +LayerRecord::LayerRecord(bool b, QString s1, QString s2) { + this->checkBox = b; + this->name = s1; + this->opacity = s2; +} + +void LayerRecord::setCheckBox (bool b) { + this->checkBox = b; +} + +bool LayerRecord::getCheckBox (void) { + return this->checkBox; +} + +void LayerRecord::setName (QString s) { + this->name = s; +} + +QString LayerRecord::getName (void) { + return this->name; +} + +void LayerRecord::setOpacity (QString s) { + this->opacity = s; +} + +QString LayerRecord::getOpacity (void) { + return this->opacity; +} diff --git a/layerrecord.h b/layerrecord.h new file mode 100644 index 0000000..c7def25 --- /dev/null +++ b/layerrecord.h @@ -0,0 +1,43 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file layerrecord.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef LAYERRECORD_H +#define LAYERRECORD_H + +#include +#include + +class LayerRecord : public QObject +{ + Q_OBJECT + +public: + explicit LayerRecord(QObject *parent = 0); + explicit LayerRecord(bool b, QString s1, QString s2); + + void setCheckBox (bool b); + bool getCheckBox (void); + + void setName (QString s); + QString getName (void); + + void setOpacity (QString s); + QString getOpacity (void); + +signals: + +public slots: + +private: + bool checkBox; + QString name; + QString opacity; + +}; + +#endif // LAYERRECORD_H diff --git a/libs/staticsingleton.h b/libs/staticsingleton.h new file mode 100644 index 0000000..97a6169 --- /dev/null +++ b/libs/staticsingleton.h @@ -0,0 +1,183 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file static_singleton.hpp + * \date 6.8.2009 + * \author Potěšil Josef xpotes03 + * \brief Soubor obsahuje šablonu třídy cStaticSingleton. + */ +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef _STATIC_SINGLETON_HPP_ +#define _STATIC_SINGLETON_HPP_ + +#include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Předdefinovaná třída podporující model větvení do vláken pro + * spolupráci s šablonou cStaticSingleton pro použití ve vícevláknových + * aplikacích. Využívá zámky z knihovny Boost::Threads. + */ +//////////////////////////////////////////////////////////////////////////////// +struct MultiThreading +{ + typedef boost::mutex mutex; + typedef boost::mutex::scoped_lock scoped_lock; +}; + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Předdefinovaná třída pro spolupráci s šablonou cStaticSingleton pro + * použití v jednovláknových aplikacích. + */ +//////////////////////////////////////////////////////////////////////////////// +class SingleThreading +{ + struct empty {}; + struct scoped_guard + { + scoped_guard(empty& ) {} + }; +public: + typedef empty mutex; + typedef scoped_guard scoped_lock; +}; + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Šablonová třída obsahující jednoduchou implementaci návrhového vzoru + * Singleton, která umožňuje vytvořit jedináčka z jakékoli třídy, která + * má bezparametrový konstruktor. + */ +//////////////////////////////////////////////////////////////////////////////// +template +class cStaticSingleton +{ +public: + static Host* Instance(); + static Host& GetInstance(); + +private: + cStaticSingleton(); + cStaticSingleton(const cStaticSingleton& s); + cStaticSingleton& operator=(const cStaticSingleton& s); + ~cStaticSingleton(); + static Host& Create(); + static Host& Access(); + + typedef Host& (*access_function)(); + + static Host* _instance; + static bool _destroyed; + static access_function _access; + static typename ThreadingModel::mutex _mutex; +}; + + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Funkce pro přístup k jediné instanci třídy. + * \return Ukazatele na instanci. + */ +//////////////////////////////////////////////////////////////////////////////// +template +inline Host* cStaticSingleton::Instance() +{ + return &(GetInstance()); +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Funkce pro přístup k jediné instanci třídy. + * \return Referenci instanci. + */ +//////////////////////////////////////////////////////////////////////////////// +template +inline Host& cStaticSingleton::GetInstance() +{ + return _access(); +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Konstruktor. + */ +//////////////////////////////////////////////////////////////////////////////// +template +cStaticSingleton::cStaticSingleton() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Destruktor. + */ +//////////////////////////////////////////////////////////////////////////////// +template +cStaticSingleton::~cStaticSingleton() +{ + _instance = 0; + _destroyed = true; + _access = &cStaticSingleton::Create; +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Interní funkce třídy vytvářející samotnou instanci objektu. + * Pro korektní práci ve vícevláknovém prostředí je potřeba + * odkomentovat/upravit testující a uzamykací část + */ +//////////////////////////////////////////////////////////////////////////////// +template +Host& cStaticSingleton::Create() +{ + typename ThreadingModel::scoped_lock scoped_lock(_mutex); + if (!_instance) + { + if (!_destroyed) + { // Vytvoř jedinou instanci a změň ukazatele _access, kterým byla + // tato metoda zavolána, aby se již nezavolala a místo toho + // se volala funkce zpřístupňující samotnou instanci + static Host staticInstance; + _instance = &staticInstance; + _access = &cStaticSingleton::Access; + } + else + { // Došlo k přístupu k již zničenému jedináčkovi + throw std::runtime_error("Access to dead reference of an object."); + } + } + return *_instance; +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Funkce zpřístupňující instanci hostující třídy. + */ +//////////////////////////////////////////////////////////////////////////////// +template +Host& cStaticSingleton::Access() +{ + return *_instance; +} + +//////////////////////////////////////////////////////////////////////////////// +// Jedináčkova data +//////////////////////////////////////////////////////////////////////////////// +template + Host* cStaticSingleton::_instance = 0; + +template + bool cStaticSingleton::_destroyed = false; + +template typename cStaticSingleton::access_function + cStaticSingleton::_access = &cStaticSingleton::Create; + +template typename ThreadingModel::mutex + cStaticSingleton::_mutex; + +#endif // _STATIC_SINGLETON_HPP_ diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..81c7046 --- /dev/null +++ b/main.cpp @@ -0,0 +1,26 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file main.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + a.setOrganizationName("FIT BUT in Brno"); + a.setApplicationName("microAnalyzer"); + + MainWindow microAnalyzer; + microAnalyzer.setWindowTitle("microAnalyzer :: imalcik at FIT BUT in Brno"); + + microAnalyzer.showMaximized(); + + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..aeaeb87 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,1022 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file mainwindow.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include "projectwizard.h" +#include "xmlparser.h" +#include "layercomposer.h" +#include "customgraphicsview.h" + + +#include +#include +#include +#include + +// CONSTS +const QString MainWindow::APPL_NAME = QString("microAnalyzer ::"); + +// -------------------------------------------- +/** + * @brief = CONSTRUCTOR + */ +// -------------------------------------------- +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + // signals + connect(cProject::Instance(), SIGNAL(imagesValueChanged()), this, SLOT(reloadImagesList())); + connect(cProject::Instance(), SIGNAL(layersValueChanged()), this, SLOT(reloadLayersList())); + + imageView = new CustomGraphicsView(); + imageView->setBackgroundRole(QPalette::Dark); + imageView->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + setCentralWidget(imageView); + + connect(imageView, SIGNAL(colorPickerPosition(int, int)), this, SLOT(graphicsClicked(int, int))); + connect(this, SIGNAL(colorPickerPosition(int, int)), this, SLOT(graphicsClicked(int, int))); + + histogramBtn = false; + + // init values + initStageAndValues(); + + // limit cache + QPixmapCache::setCacheLimit(4194304); + + // statusbar init + statusBar()->showMessage("To activate function do Open project or Open image action."); // + tr("%1").arg(QPixmapCache::cacheLimit() +} + +void MainWindow::initStageAndValues() { + + // disable functions that are available only after a project is loaded + menuChangeAvailability(false); + + openedNewProjDialog = false; + + // setup of bitmap layers table + bitmapLayersTBL = NULL; + bitmapLayersTBL = new TableFormat(); + ui->bitmapTableView->setModel(bitmapLayersTBL); + ui->bitmapTableView->resizeRowsToContents(); // Adjust the row height. + ui->bitmapTableView->resizeColumnsToContents(); // Adjust the column width. + ui->bitmapTableView->setColumnWidth( 0, 20 ); + ui->bitmapTableView->setColumnWidth( 1, 150 ); + ui->bitmapTableView->setColumnWidth( 2, 20 ); + + // setup of vector layers table + vectorLayersTBL = NULL; + vectorLayersTBL = new TableFormat(); + ui->vectorTableView->setModel(vectorLayersTBL); + ui->vectorTableView->resizeRowsToContents(); // Adjust the row height. + ui->vectorTableView->resizeColumnsToContents(); // Adjust the column width. + ui->vectorTableView->setColumnWidth( 0, 20 ); + ui->vectorTableView->setColumnWidth( 1, 150 ); + ui->vectorTableView->setColumnWidth( 2, 20 ); + + // init the dial element + lastDialValue = 0; + onOpenNew_dialReset(); + + // colorpicker initial reset + QImage tmpImg(1,1, QImage::Format_ARGB32); + actualizeGraphicsView(&tmpImg); + + ui->frame->setStyleSheet("QFrame {border: 1px solid #828790;}"); + actualColor = qRgb(255,255,255); + actualizeFrameColor(); + + imageView->resetMatrix(); + + // channel correction sliders + ui->rLabel->setStyleSheet("QLabel { background-color: red; color: white;}"); + ui->gLabel->setStyleSheet("QLabel { background-color: green; color: white;}"); + ui->bLabel->setStyleSheet("QLabel { background-color: blue; color: white;}"); + + // colour analysis button + for (int i = 0; i < ui->menuTools->actions().count(); i++) { + if (ui->menuTools->actions().at(i)->isCheckable()) { + ui->menuTools->actions().at(i)->setChecked(false); + } + } + + resetSlidersValues(); +} + +void MainWindow::resetSlidersValues() { + ui->rSlider->setValue(DEF_SLIDER_VALUE); + ui->gSlider->setValue(DEF_SLIDER_VALUE); + ui->bSlider->setValue(DEF_SLIDER_VALUE); +} + +void MainWindow::closeThisProject() { + // project init + cProject::Instance()->valueInit(); + initStageAndValues(); + } + + +bool MainWindow::importImage(QString &imageFileName, bool addToVector) { + if (imageFileName.isEmpty()) { + return false; + } + else { + + if (addToVector) { + // add an image to project + cProject::Instance()->addToImages(imageFileName); + cProject::Instance()->setFileImported(true); + } + + QImage image(imageFileName); + + if (image.isNull()) { + return false; + } + + actualizeGraphicsView(&image); + + // align an image to center after import + imageResizer(0.99999999999999); + imageView->resetMatrix(); + + onOpenNew_dialReset(); + + // allow functions from menu + menuChangeAvailability(true); + + return true; + } +} + +void MainWindow::menuChangeAvailability(bool setting, bool sliders) { + + ui->imageDial->setEnabled(setting); + + ui->rSlider->setEnabled(sliders); + ui->gSlider->setEnabled(sliders); + ui->bSlider->setEnabled(sliders); + + ui->bitmapTableView->setEnabled(!sliders); + ui->vectorTableView->setEnabled(!sliders); +} + + + +// -------------------------------------------- +/** + * @brief = DESTRUKTOR + */ +// -------------------------------------------- +MainWindow::~MainWindow() +{ + delete ui; +} + +// -------------------------------------------- +/** + * @brief = TLACITKO EXIT + */ +// -------------------------------------------- +void MainWindow::on_actionExit_triggered() { + close(); +} + +bool MainWindow::saveAskDialog() { + + return true; + +} + + +// -------------------------------------------- +/** + * + */ +// -------------------------------------------- +void MainWindow::on_actionHelp_triggered() +{ + QMessageBox::about(this, APPL_NAME + tr(" HELP"), tr("


Under construction.

")); +} + + +// -------------------------------------------- +/** + * + */ +// -------------------------------------------- +void MainWindow::on_actionAbout_microAnalyzer_triggered() +{ + QMessageBox::about(this, APPL_NAME + tr(" About"), + QString::fromLocal8Bit("

 

microAnalyzer.

" + "

Author: Ing. Dominik Malci­k

" + "

E-mail: imalcik@fit.vutbr.cz

" + "

Year: 2014-2016

 

")); +} + + +// -------------------------------------------- +/** + * + */ +// -------------------------------------------- +void MainWindow::on_actionOpen_Image_triggered() +{ + QString imageFileName = QFileDialog::getOpenFileName(this, tr("Open Image"), QDir::currentPath(), "*.bmp *.png *.tif *.jpg *.jpeg"); + + if (importImage(imageFileName, true)) { + statusBar()->showMessage("Image loaded."); + menuChangeAvailability(true); + } + else { + QMessageBox::critical(this, APPL_NAME + tr(" ERROR"), tr("Error: The image %1 could not be loaded.").arg(imageFileName)); + } +} + +void MainWindow::onOpenNew_dialReset() { + ui->imageDial->setValue(0); +} + + +// -------------------------------------------- +/** + * + */ +// -------------------------------------------- +void MainWindow::on_actionZoom_in_25_triggered() +{ + imageResizer (1.2); +} + + +// -------------------------------------------- +/** + * + */ +// -------------------------------------------- +void MainWindow::on_actionZoom_out_25_triggered() +{ + imageResizer (0.8); +} + + +// -------------------------------------------- +/** + * + */ +// -------------------------------------------- +void MainWindow::imageResizer(double resizeCoeff) +{ + imageView->scale(resizeCoeff, resizeCoeff); + + QString statusMessage = " OUT -" + tr("%1").arg((1.0 - resizeCoeff) * 100) + " %"; + if (resizeCoeff > 1.0) { + statusMessage = " IN +" + tr("%1").arg((resizeCoeff - 1.0) * 100) + " %"; + } + statusBar()->showMessage("Zoom" + statusMessage); +} + +// -------------------------------------------- +/** + * + */ +// -------------------------------------------- +void MainWindow::on_actionFit_in_Window_triggered() +{ + imageView->fitInView(imageView->scene()->sceneRect(), Qt::KeepAspectRatio); + statusBar()->showMessage("Fit in window"); +} + +// -------------------------------------------- +/** + * + */ +// -------------------------------------------- +void MainWindow::on_actionOriginal_Size_triggered() +{ + imageView->resetMatrix(); + statusBar()->showMessage("Original size."); +} + +// -------------------------------------------- +/** + * @brief = ZMENA VELIKOSTI OBRAZKU NA ZAKLADE POHYBU DIALU + */ +// -------------------------------------------- +void MainWindow::on_imageDial_actionTriggered(int action) { + double newRatio = 1.0; + int dialValue = ui->imageDial->value(); + + int difference = lastDialValue - dialValue; + lastDialValue = dialValue; + + newRatio += ((double)(difference * (-1.0)) / 10000.0); + + if (newRatio <= 1.1 && newRatio >= 0.9) { + imageResizer (newRatio); + } +} + +void MainWindow::invertOpenedDialog_slot() { + openedNewProjDialog = !openedNewProjDialog; + this->setEnabled(true); +} + +void MainWindow::on_actionNew_Project_triggered() { + ProjectWizard * pw = new ProjectWizard; + + if (!openedNewProjDialog) { + openedNewProjDialog = true; + Qt::WindowFlags flags = pw->windowFlags(); + pw->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint); + pw->show(); + + this->setEnabled(false); + + connect(pw, SIGNAL(accepted()), this, SLOT(openProject_slot())); + connect(pw, SIGNAL(rejected()), this, SLOT(invertOpenedDialog_slot())); + } +} + +/* + * SLOT after accepting of the wizard + */ +void MainWindow::openProject_slot() { + + invertOpenedDialog_slot(); + + menuChangeAvailability(true); + openProject(cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getProjectFileName()); +} + +void MainWindow::on_actionOpen_Project_triggered() { + + QString projectFileName = QFileDialog::getOpenFileName(this, tr("Open microAnalyzer Project"), QDir::currentPath(), "*.mapro"); + + if (!projectFileName.isEmpty()) { + openProject(projectFileName); + } +} + +void MainWindow::openProject(QString projectFileName) { + + // if a project file was chosen + if (!projectFileName.isEmpty()) { + + // close currently opened project + closeThisProject(); + + QFile projFile(projectFileName); + + // set root directory of the project + QFileInfo fi(projFile); + cProject::Instance()->setProjectRootDir(fi.path()); + + // open file for reading + if(!projFile.open(QIODevice::ReadOnly)) { + QMessageBox::critical(0, APPL_NAME + " ERROR", projFile.errorString()); + } + else { + + XMLparser * xml = new XMLparser; + + if (!xml->read(&projFile)) { + QMessageBox::critical(0, APPL_NAME + " ERROR", "Project could not be loaded!"); + statusBar()->showMessage(tr("Error within project loading! Try again, please."), 3000); + } + else { + // import bitmap layers + if (cProject::Instance()->getFileImported()) { + for (uint i = 0; i < cProject::Instance()->getImages().size(); i++) { + QString imageFileNameToOpen = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getImagesDir() + "/" + cProject::Instance()->getImages()[i]; + importImage(imageFileNameToOpen, false); + } + } + + menuChangeAvailability(true); + + setWindowTitle(APPL_NAME + " project - " + projectFileName); + statusBar()->showMessage(tr("Project loaded ...")); + } + + projFile.close(); + } + } + +} + + +// --------------------------------------------------------------------- +// --------------------------------------------------------------------- + +void MainWindow::on_actionSave_Project_triggered() { + bool removeSubDirs = false; + saveProjectToDest(cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getProjectFileName(), removeSubDirs); +} + +void MainWindow::on_actionSave_Project_As_triggered() { + + QString saveFileName = QFileDialog::getSaveFileName(this, "Save file", "", "*" + Project::PROJ_FILE_EXT); + + if (!saveFileName.isEmpty()) { + bool removeSubDirs = true; + saveProjectToDest(saveFileName, removeSubDirs); + } +} + +void MainWindow::saveProjectToDest(QString projectFileName_withPath, bool removeSubDirs) { + + QFile projFile(projectFileName_withPath); + QFileInfo fi(projFile); + + cProject::Instance()->prepareProject(fi.path(), fi.baseName(), + fi.fileName(), cProject::Instance()->getFileImported(), + cProject::Instance()->getImages(), + cProject::Instance()->getLayers()); + + // attempt to save + appropriate reaction + if (!cProject::Instance()->saveToFile(removeSubDirs)) { + QMessageBox::critical(0, APPL_NAME + " ERROR", "Project could not be saved!"); + statusBar()->showMessage(tr("Error within project saving! Try again, please."), 3000); + } + else { + statusBar()->showMessage(tr("Project saved to ") + projectFileName_withPath); + setWindowTitle(APPL_NAME + " project - " + projectFileName_withPath); + } +} + +void MainWindow::reloadImagesList() { + + // show updated list/table of images + TableFormat * thisTable = reloadTableList(TABLE_BITMAPS); + bitmapLayersTBL = thisTable; + ui->bitmapTableView->setModel(thisTable); + ui->bitmapTableView->setStyleSheet("QTableView {selection-background-color: #D10000; selection-color: #FFFFFF;}"); +} + +void MainWindow::reloadLayersList() { + + // show updated list/table of images + TableFormat * thisTable = reloadTableList(TABLE_LAYERS); + vectorLayersTBL = thisTable; + ui->vectorTableView->setModel(thisTable); + ui->vectorTableView->setStyleSheet("QTableView {selection-background-color: #2D60ED; selection-color: #FFFFFF;}"); +} + +TableFormat * MainWindow::reloadTableList(int tableSpec) { + + QString name = ""; + QString opacity = "100"; + + TableFormat * table = new TableFormat; + + unsigned int size = 0; + if (tableSpec == TABLE_LAYERS) { + size = cProject::Instance()->getLayers().size(); + } + else { + size = cProject::Instance()->getImages().size(); + } + + for (int i = (size - 1); i >= 0; i--) { + + if (tableSpec == TABLE_LAYERS) { + name = cProject::Instance()->getSelectedLayer(i); + } + else { + name = cProject::Instance()->getSelectedImage(i); + } + + // insert row + table->insertRows(0, 1, QModelIndex()); + + // insert information to the row + QModelIndex index = table->index(0, 0, QModelIndex()); + table->setData(index, QVariant(Qt::Checked), Qt::CheckStateRole); + + index = table->index(0, 1, QModelIndex()); + table->setData(index, name, Qt::EditRole); + + index = table->index(0, 2, QModelIndex()); + table->setData(index, opacity, Qt::EditRole); + } + + return table; +} + + + +void MainWindow::on_bitmapTableView_activated(QModelIndex index) +{ + std::vector selectedIndexes = getImportedIndexes(); + if (selectedIndexes.size() > 0) { + + QString imageName = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getImagesDir() + "/"; + // !!!!! MAGIC 0 > we are allowing only one layer !! + imageName += cProject::Instance()->getSelectedImage (selectedIndexes[0]); + + // load image + QImage image(imageName); + actualizeGraphicsView(&image); + } +} + +std::vector MainWindow::getImportedIndexes () { + QModelIndexList indexes = ui->bitmapTableView->selectionModel()->selectedRows(1); + + return getSelectedIndexes(indexes); +} + +std::vector MainWindow::getAnalysingIndexes () { + QModelIndexList indexes = ui->vectorTableView->selectionModel()->selectedRows(1); + + return getSelectedIndexes(indexes); +} + + +std::vector MainWindow::getSelectedIndexes (QModelIndexList indexes) { + std::vector selectedIndexes; + + for (int i = 0; i < indexes.count(); ++i) { + QModelIndex index = indexes.at(i); + selectedIndexes.push_back(index.row()); + } + + return selectedIndexes; +} + + + + +void MainWindow::on_actionClose_Project_Image_triggered() +{ + switch( QMessageBox::question( + this, + APPL_NAME + tr(" Close project?"), + tr("Do you really want to close this project?"), + + QMessageBox::Yes | + QMessageBox::Cancel, + + QMessageBox::Cancel ) ) + { + case QMessageBox::Yes: { + closeThisProject(); + break; + } + case QMessageBox::Cancel: { + } + default: { + break; + } + } +} + + + + + + +void MainWindow::on_actionAnalyze_edges_triggered() +{ + if (cProject::Instance()->getImages().size() > 0) { + + std::vector selectedIdx = getImportedIndexes(); + if (!(selectedIdx.size() > 0)) { + QMessageBox::information(this, APPL_NAME + " No bitmap layer selected.", tr("Please select a BACKGROUND layer in the left tools panel." + " Click on the demanded layer and try again.")); + } + else { + QString fileName = cProject::Instance()->getImages()[ selectedIdx[0] ]; + QString test = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getImagesDir() + "/" + fileName; + QImage imgToAnalyze( test ); + + if (imgToAnalyze.isNull()) { + QMessageBox::critical(this, APPL_NAME + " ERROR", "Bad file name or out of memory limit - shrink the image resolution please!\n\n" + test); + } + else { + + // ram limit !!! + if ( (imgToAnalyze.width() / 1000) * (imgToAnalyze.height() / 1000) <= 75) { + + OpenCVprocessor * openCVproc = new OpenCVprocessor(); + int resultDialog = getIntDialog(); + bool edgeSearch = true; + if (resultDialog >= 0) { + QImage result = openCVproc->processThreshold_Edges(&imgToAnalyze, edgeSearch, resultDialog); + + // ---------------- SAVE + int number = cProject::Instance()->layersCount(); + QString dstDir = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getLayersDir() + "/"; + QString ext = ".png"; + QString addition = "_E"; + QString destFileName = saveAnalysingImageToDir(fileName, dstDir, ext, addition, number); + + result.save(dstDir + destFileName, "PNG"); + cProject::Instance()->addToLayers(destFileName); + + // autoSave + on_actionSave_Project_triggered(); + // ---------------- // SAVE + + // show saved image + actualizeGraphicsView(&result); + + statusBar()->showMessage(tr("Edges found ...")); + } + } + else { + QMessageBox::critical(this, APPL_NAME + " TOO BIG IMAGE", "The selected image is too big, please shrink resolution. Max. total amount of pixels is 75 mil (for example 10000 x 7500)."); + } + } + } + } +} + + +void MainWindow::on_actionHough_triggered() { + makeCvFunction(2, -1); +} + +void MainWindow::on_actionThreshold_triggered() { + int resultDialog = getIntDialog(); + if (resultDialog >= 0) { + makeCvFunction(1, resultDialog); + } +} + +void MainWindow::makeCvFunction(int number, int param = 0) { + + std::vector selectedIdx = getImportedIndexes(); + + QString fileName = cProject::Instance()->getImages()[selectedIdx[0]]; + QImage imgToAnalyze(cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getImagesDir() + "/" + fileName); + + OpenCVprocessor * openCVproc = new OpenCVprocessor(); + + QImage result; + QString suffix = ""; + switch(number) { + case 0: { + break; + } + case 1: { + statusBar()->showMessage(tr("Threshold found ...")); + bool edgeSearch = false; + result = openCVproc->processThreshold_Edges(&imgToAnalyze, edgeSearch, param); + suffix = "TH"; + break; + } + case 2: { + statusBar()->showMessage(tr("Hough proceded ...")); + bool edgeSearch = true; + result = openCVproc->processThreshold_Edges(&imgToAnalyze, edgeSearch, param); + suffix = "H"; + break; + } + default: { + break; + } + } + + QFileInfo fi(fileName); + QString newPngFile = fi.baseName() + suffix + ".png"; + result.save(cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getImagesDir() + "/" + newPngFile, "PNG"); + + cProject::Instance()->addToImages(newPngFile); + + actualizeGraphicsView(&result); + + // autoSave + on_actionSave_Project_triggered(); +} + + + + + + + +int MainWindow::getIntDialog() { + bool ok; + int i = QInputDialog::getInt(this, tr("QInputDialog::getInteger()"), + tr("Threshold value"), 100, 0, 255, 1, &ok); + if (ok) { + return i; + } + + return -1; +} + + +void MainWindow::closeEvent(QCloseEvent *event) { + + if (!openedNewProjDialog && saveAskDialog()) { + // close window + event->accept(); + } + else { + // push cancel - does not close the window + event->ignore(); + } + +} + + + + + +void MainWindow::on_pushButton_2_clicked() { + + LayerComposer * composer = new LayerComposer(); + + importedIndexes = getImportedIndexes(); + analysingIndexes = getAnalysingIndexes(); + + if (importedIndexes.size() > 0 && analysingIndexes.size() > 0) { + + // merging of selected layers + QString bgRootDir = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getImagesDir() + "/"; + QString overlayRootDir = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getLayersDir() + "/"; + QImage result = composer->composeLayers(cProject::Instance()->getImages(), + cProject::Instance()->getLayers(), + importedIndexes, analysingIndexes, + bgRootDir, overlayRootDir); + + actualizeGraphicsView(&result); + + statusBar()->showMessage("Layers merged ..."); + } + else { + statusBar()->showMessage("Layers NOT merged, select layers to merge first, please."); + } +} + + +void MainWindow::on_pushButton_clicked() { + LayerComposer * composer = new LayerComposer(); + + analysingIndexes = getAnalysingIndexes(); + + if (analysingIndexes.size() > 0) { + + std::vector bgVector; + bgVector.push_back(analysingIndexes[0]); // !!!!!!! 0 v indexu + + std::vector analysingVector; + for (unsigned int i = 1; i < analysingIndexes.size(); i++) { + analysingVector.push_back(analysingIndexes[i]); + } + + // merging of selected layers + QString bgRootDir = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getLayersDir() + "/"; + QString overlayRootDir = bgRootDir; + QImage result = composer->composeLayers(cProject::Instance()->getLayers(), + cProject::Instance()->getLayers(), + bgVector, analysingVector, bgRootDir, overlayRootDir); + + actualizeGraphicsView(&result); + + statusBar()->showMessage("Layers merged ..."); + } + else { + statusBar()->showMessage("Layers NOT merged, select layers to merge first, please."); + } + +} + +void MainWindow::on_actionAnalyze_Colors_triggered() { + + bool setting = ui->imageDial->isEnabled(); + bool sliders = !(ui->rSlider->isEnabled()); + + menuChangeAvailability(setting, sliders); + + if (sliders) { + makeColorAnalyzeStep(); + } + else { + QString bgImageFileName = cProject::Instance()->getSelectedImage(importedIndexes[0]); // !!!!!! 0 + + switch( QMessageBox::question( + this, + APPL_NAME + tr(" Save this layer?"), + tr("

Would you like to save this layer?

Choose Yes to proceed, No to abort.

"), + + QMessageBox::Yes | + QMessageBox::No, + + QMessageBox::Yes ) ) + { + case QMessageBox::Yes: { + // ---------------- SAVE + int number = cProject::Instance()->layersCount(); + QString dstDir = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getLayersDir() + "/"; + QString ext = ".png"; + QString addition = "_C"; + QString destFileName = saveAnalysingImageToDir(bgImageFileName, dstDir, ext, addition, number); + + visibleImage.save(dstDir + destFileName, "PNG"); + cProject::Instance()->addToLayers(destFileName); + + // autoSave + on_actionSave_Project_triggered(); + // ---------------- // SAVE + + statusBar()->showMessage("Layer SAVED ..."); + + break; + } + case QMessageBox::No: { + } + default: { + QString srcDir = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getImagesDir() + "/"; + QImage image(srcDir + bgImageFileName); + if (!(image.isNull())) { + actualizeGraphicsView(&image); + } + statusBar()->showMessage("Layer saving aborted ..."); + } + } + } + + resetSlidersValues(); +} + +void MainWindow::on_rSlider_valueChanged(int value) { + if (ui->rSlider->isEnabled()) { + makeColorAnalyzeStep(); + } +} + +void MainWindow::on_gSlider_valueChanged(int value) { + if (ui->gSlider->isEnabled()) { + makeColorAnalyzeStep(); + } +} + +void MainWindow::on_bSlider_valueChanged(int value) { + if (ui->bSlider->isEnabled()) { + makeColorAnalyzeStep(); + } +} + + +void MainWindow::makeColorAnalyzeStep () { + + importedIndexes = getImportedIndexes(); + if (importedIndexes.size() > 0) { + + QString bgRootDir = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getImagesDir() + "/"; + QString bgImageFileName = cProject::Instance()->getSelectedImage(importedIndexes[0]); // !!!!!! 0 + QRgb maskColor = actualColor; + + LayerComposer * composer = new LayerComposer(); + visibleImage = composer->maskSelectedLayer(bgImageFileName, bgRootDir, maskColor, ui->rSlider->value(), ui->gSlider->value(), ui->bSlider->value()); + + actualizeGraphicsView(&visibleImage); + + statusBar()->showMessage("Layer processed ..."); + } +} + + + +void MainWindow::graphicsClicked(int xPos, int yPos) { + + if (!(ui->rSlider->isEnabled())) { + + // find coordinates of the cursor position + QPointF point = imageView->mapToScene(xPos, yPos); + + actualColor = visibleImage.pixel(point.x(), point.y()); + actualizeFrameColor(); + } +} + +void MainWindow::actualizeFrameColor() { + + QPalette palette = ui->frame->palette(); + palette.setColor( backgroundRole(), actualColor); + + ui->frame->setPalette(palette); + ui->frame->setAutoFillBackground(true); + +} + +void MainWindow::actualizeGraphicsView(QImage * toShow) { + QPixmapCache::clear(); + QPixmap pm = QPixmap::fromImage(*toShow); + QPixmapCache::insert("loadedImage", pm); + + // show result + visibleImage = *toShow; + QGraphicsScene * thisScene = new QGraphicsScene; + thisScene->addPixmap(pm); + + if (histogramBtn) { + // DOES NOT WORK YET + } + + imageView->setScene(thisScene); +} + + + +QString MainWindow::saveAnalysingImageToDir(QString origFN, QString dstDir, QString ext, QString addition, int number) { + + QFileInfo fi(origFN); + + QString newExt = ext; + QString newPngFile = fi.baseName() + addition; + QString numStr = QString::number(number); + + + while (1) { + QFile destFile(dstDir + newPngFile + numStr + newExt); + + if (!destFile.exists()) { + newPngFile = newPngFile + numStr + newExt; + break; + } + else { + number++; + } + + numStr = QString::number(number); + } + + return newPngFile; +} + + + +bool MainWindow::deleteDialog(QString layerType) { + switch( QMessageBox::question( + this, + APPL_NAME + tr(" Delete selected layers?"), + tr("

Do you really want to permanently remove selected ") + layerType + tr(" layers.

"), + + QMessageBox::Yes | + QMessageBox::No, + + QMessageBox::No ) ) + { + case QMessageBox::Yes: { + return true; + } + case QMessageBox::No: { + } + default: { + return false; + } + } +} + +// delete analysing +void MainWindow::on_pushButton_3_clicked() { + QString layerType = "ANALYSING"; + + if (deleteDialog(layerType)) { + analysingIndexes = getAnalysingIndexes(); + + for (unsigned int i = 0; i < analysingIndexes.size(); i++) { + cProject::Instance()->deleteAnalysing(analysingIndexes[i]); + } + } + + cProject::Instance()->emitDeleteAnalysings(); + + // autoSave + on_actionSave_Project_triggered(); +} + +// delete imported +void MainWindow::on_pushButton_4_clicked() { + QString layerType = "BACKGROUND"; + + if (deleteDialog(layerType)) { + importedIndexes = getImportedIndexes(); + + for (unsigned int i = 0; i < importedIndexes.size(); i++) { + cProject::Instance()->deleteImported(importedIndexes[i]); + } + } + + cProject::Instance()->emitDeleteImported(); + + // autoSave + on_actionSave_Project_triggered(); +} + +void MainWindow::on_actionHistogram_triggered() { + histogramBtn = !histogramBtn; +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..3690424 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,155 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file mainwindow.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// openCV +#include "opencv/cv.h" + +#include "opencvprocessor.h" +#include "tableformat.h" + +// singleton +#include "project.h" + +class QLabel; + +namespace Ui { + class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + static const QString APPL_NAME; + static const int TABLE_BITMAPS = 0; + static const int TABLE_LAYERS = 1; + static const int DEF_SLIDER_VALUE = 20; + + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private slots: + // File menu + void on_actionNew_Project_triggered(); + void on_actionOpen_Project_triggered(); + void on_actionSave_Project_triggered(); + void on_actionOpen_Image_triggered(); + void on_actionClose_Project_Image_triggered(); + void on_actionExit_triggered(); + void on_actionSave_Project_As_triggered(); + + // Tools menu + void on_actionZoom_in_25_triggered(); + void on_actionZoom_out_25_triggered(); + void on_actionFit_in_Window_triggered(); + void on_actionOriginal_Size_triggered(); + + // Tools menu > analyza + void on_actionAnalyze_edges_triggered(); + void on_actionHough_triggered(); + void on_actionThreshold_triggered(); + + void on_actionAnalyze_Colors_triggered(); + void on_rSlider_valueChanged(int value); + void on_gSlider_valueChanged(int value); + void on_bSlider_valueChanged(int value); + + // Help menu + void on_actionHelp_triggered(); + void on_actionAbout_microAnalyzer_triggered(); + + // Layers buttons + void on_pushButton_2_clicked(); // add ANALYSING + void on_pushButton_clicked(); // show only ANALYSING + void on_pushButton_3_clicked(); // delete ANALYSING + void on_pushButton_4_clicked(); // delete IMPORTED + + // Additional slots + void on_imageDial_actionTriggered(int action); + void openProject_slot(); + + void reloadImagesList(); + void reloadLayersList(); + + void graphicsClicked(int xPos, int yPos); + + void on_bitmapTableView_activated(QModelIndex index); + + // Wizard - singleton instance + void invertOpenedDialog_slot(); + + void on_actionHistogram_triggered(); + +private: + Ui::MainWindow *ui; + void menuChangeAvailability(bool setting, bool sliders = false); + void imageResizer(double resizeCoeff); + void onOpenNew_dialReset(); + bool importImage(QString &imageFileName, bool addToVector); + void saveProjectToDest(QString projectFileName_withPath, bool removeSubDirs); + + QString saveAnalysingImageToDir(QString origFN, QString dstDir, QString ext, QString addition, int number); + + bool deleteDialog(QString layerType); + void actualizeGraphicsView(QImage * toShow); + void actualizeFrameColor(); + + // tableView indexes (imported / analysing) + std::vector getImportedIndexes (); + std::vector getAnalysingIndexes (); + std::vector getSelectedIndexes (QModelIndexList indexes); + + void makeColorAnalyzeStep(); + + void makeCvFunction(int number, int param); + + int getIntDialog(); + + void closeThisProject(); + void initStageAndValues(); + void resetSlidersValues(); + + void closeEvent(QCloseEvent *event); + bool saveAskDialog(); + + void openProject(QString projectFileName); + + TableFormat * reloadTableList(int tableSpec); + + std::vector importedIndexes; + std::vector analysingIndexes; + + QImage visibleImage; + QRgb actualColor; + QGraphicsView * imageView; + + int lastDialValue; + bool openedNewProjDialog; + + TableFormat *bitmapLayersTBL; + TableFormat *vectorLayersTBL; + + bool histogramBtn; +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..4961c4c --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,870 @@ + + + MainWindow + + + + 0 + 0 + 724 + 704 + + + + MainWindow + + + + + + 0 + 0 + 724 + 25 + + + + + File + + + + + + + + + + + + + + + Tools + + + + + + + + + + + + + + + Help + + + + + + + + + + + + + + 250 + 625 + + + + false + + + QDockWidget::NoDockWidgetFeatures + + + Tools + + + 1 + + + + + Arial + + + + + + 26 + 19 + 201 + 151 + + + + -999 + + + 999 + + + 10 + + + 0 + + + 0 + + + true + + + Qt::Vertical + + + true + + + 10.000000000000000 + + + true + + + + + + 10 + 170 + 220 + 20 + + + + Qt::Horizontal + + + + + + 10 + 187 + 191 + 16 + + + + + Sans + 10 + + + + Background layers (dbl click) + + + + + + 14 + 299 + 111 + 16 + + + + + Sans + 10 + + + + Analysing layers + + + + + + 92 + 0 + 71 + 16 + + + + + Sans + 10 + 50 + false + + + + Fine zoom + + + + + + 10 + 209 + 221 + 71 + + + + + Arial + 9 + 50 + false + + + + false + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + Qt::DashLine + + + false + + + false + + + true + + + 140 + + + false + + + 25 + + + false + + + true + + + false + + + 19 + + + false + + + 15 + + + + + + 10 + 279 + 220 + 20 + + + + Qt::Horizontal + + + + + + 10 + 320 + 221 + 161 + + + + + Arial + 9 + 50 + false + + + + false + + + true + + + QAbstractItemView::MultiSelection + + + QAbstractItemView::SelectRows + + + Qt::DashLine + + + false + + + false + + + true + + + 140 + + + false + + + 25 + + + false + + + true + + + false + + + 19 + + + false + + + 15 + + + + + + 165 + 295 + 31 + 21 + + + + Show only selected Analysing layers (blue) + + + + + + + images/icons/btn_analyzeLayers.pngimages/icons/btn_analyzeLayers.png + + + + + + 200 + 295 + 31 + 21 + + + + Add selected Analysing layers (blue) to selected Imported layers (red) + + + + + + + images/icons/btn_addLayers.pngimages/icons/btn_addLayers.png + + + + + + 150 + 499 + 81 + 21 + + + + true + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + 13 + 501 + 131 + 16 + + + + + Sans + 10 + + + + Mask colour: + + + + + + 10 + 480 + 220 + 20 + + + + Qt::Horizontal + + + + + + 130 + 295 + 31 + 21 + + + + Delete selected ANALYSING layers (blue ones) + + + + + + + images/icons/delete.pngimages/icons/delete.png + + + + + + 200 + 184 + 31 + 21 + + + + Delete selected IMPORTED layers (blue ones) + + + + + + + images/icons/delete.pngimages/icons/delete.png + + + + + + 70 + 529 + 160 + 19 + + + + -5 + + + 45 + + + 5 + + + 5 + + + Qt::Horizontal + + + + + + 70 + 553 + 160 + 19 + + + + -5 + + + 45 + + + 5 + + + 5 + + + Qt::Horizontal + + + + + + 70 + 578 + 160 + 19 + + + + -5 + + + 45 + + + 5 + + + 5 + + + Qt::Horizontal + + + + + + 13 + 530 + 46 + 16 + + + + + Sans + 10 + 50 + false + + + + Red + + + Qt::AlignCenter + + + + + + 13 + 553 + 46 + 16 + + + + + Sans + 10 + + + + Green + + + Qt::AlignCenter + + + + + + 13 + 577 + 46 + 16 + + + + + Sans + 10 + + + + Blue + + + Qt::AlignCenter + + + + + + + + 0 + 32 + + + + false + + + TopToolBarArea + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + images/icons/newProject.pngimages/icons/newProject.png + + + New Project + + + Ctrl+N + + + + + + images/icons/openProject.pngimages/icons/openProject.png + + + Open Project + + + Ctrl+O + + + + + + images/icons/save.pngimages/icons/save.png + + + Save Project + + + Ctrl+S + + + + + + images/icons/openImage.pngimages/icons/openImage.png + + + Import Image + + + Ctrl+I + + + + + + images/icons/exit.pngimages/icons/exit.png + + + Exit + + + Ctrl+Q + + + + + + images/icons/zoom-in.pngimages/icons/zoom-in.png + + + Zoom in (+ 20 %) + + + Ctrl++ + + + + + + images/icons/zoom-out.pngimages/icons/zoom-out.png + + + Zoom out (- 20 %) + + + Ctrl+- + + + + + + images/icons/zoom-fit.pngimages/icons/zoom-fit.png + + + Fit in Window + + + Ctrl+Enter + + + + + + images/icons/zoom-orig.pngimages/icons/zoom-orig.png + + + Original Size + + + Ctrl+0 + + + + + + images/icons/help.pngimages/icons/help.png + + + Help + + + F1 + + + + + About microAnalyzer + + + + + Analyze Edges + + + + + Threshold + + + + + + images/icons/save-as.pngimages/icons/save-as.png + + + Save Project As + + + Ctrl+Shift+S + + + + + show project + + + + + + images/icons/close.pngimages/icons/close.png + + + Close Project / Image + + + Ctrl+W + + + + + Hough + + + + + true + + + Analyze Colour + + + + + true + + + false + + + false + + + Histogram + + + + + + + diff --git a/microAnalyzer.pro b/microAnalyzer.pro new file mode 100644 index 0000000..6ecd674 --- /dev/null +++ b/microAnalyzer.pro @@ -0,0 +1,38 @@ +TEMPLATE = app +TARGET = microAnalyzer +DEPENDPATH += . + +# OpenCV +LIBS += -lopencv_core -lopencv_imgproc -lboost_system + +INCLUDEPATH += . + +QT += widgets +QT += xml + +# Input +HEADERS += layerrecord.h \ + mainwindow.h \ + project.h \ + projectwizard.h \ + ./libs/staticsingleton.h \ + tableformat.h \ + xmlparser.h \ + opencvprocessor.h \ + layercomposer.h \ + customgraphicsview.h + + +FORMS += mainwindow.ui +SOURCES += layerrecord.cpp \ + main.cpp \ + mainwindow.cpp \ + project.cpp \ + projectwizard.cpp \ + tableformat.cpp \ + xmlparser.cpp \ + opencvprocessor.cpp \ + layercomposer.cpp \ + customgraphicsview.cpp + +RC_FILE = microAnalyzer.rc diff --git a/microAnalyzer.rc b/microAnalyzer.rc new file mode 100644 index 0000000..a20295d --- /dev/null +++ b/microAnalyzer.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "images/application.ico" \ No newline at end of file diff --git a/opencvprocessor.cpp b/opencvprocessor.cpp new file mode 100644 index 0000000..559ac64 --- /dev/null +++ b/opencvprocessor.cpp @@ -0,0 +1,164 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file opencvprocessor.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include "opencvprocessor.h" + +#include "string.h" +#include +#include + +OpenCVprocessor::OpenCVprocessor(QWidget *parent) : + QMainWindow(parent) +{ +} + +IplImage * OpenCVprocessor::qImageToCvImage(QImage *qimg) { + + IplImage *imgHeader = cvCreateImageHeader( cvSize(qimg->width(), qimg->height()), IPL_DEPTH_8U, 4); + imgHeader->imageData = (char*) qimg->bits(); + + uchar* newdata = (uchar*) malloc(sizeof(uchar) * qimg->byteCount()); + memcpy(newdata, qimg->bits(), qimg->byteCount()); + imgHeader->imageData = (char*) newdata; + + return imgHeader; +} + +QImage OpenCVprocessor::cvImageToQImage(const IplImage *iplImage) { + int height = iplImage->height; + int width = iplImage->width; + + if (iplImage->depth == IPL_DEPTH_8U && iplImage->nChannels == 3) { + const uchar *qImageBuffer = (const uchar*)iplImage->imageData; + + QImage img(qImageBuffer, width, height, QImage::Format_RGB888); + return img.rgbSwapped(); + + } else if (iplImage->depth == IPL_DEPTH_8U && iplImage->nChannels == 1){ + + const uchar *qImageBuffer = (const uchar*)iplImage->imageData; + QImage img(qImageBuffer, width, height, QImage::Format_Indexed8); + + QVector colorTable; + for (int i = 0; i < 256; i++){ + colorTable.push_back(qRgb(i, i, i)); + } + + img.setColorTable(colorTable); + return img; + + }else{ + return QImage(); + } +} + +QImage OpenCVprocessor::processThreshold_Edges(QImage * input, bool processEdges, int threshValue) { + + IplImage * img = NULL; + img = qImageToCvImage(input); + + // transform source image to greyscale + IplImage *dst = cvCreateImage( cvSize( img->width, img->height ), IPL_DEPTH_8U, 1 ); + cvCvtColor( img, dst, CV_RGB2GRAY ); + + // make threshold + cvThreshold(dst, dst, threshValue, 255, CV_THRESH_BINARY); + + if (processEdges) { + cvCanny( dst, dst, 1.0, 1.0, 3); + } + + QImage qEdges = cvImageToQImage(dst); + cvReleaseImage(&dst); + cvReleaseImage(&img); + return qEdges; +} + + +QImage OpenCVprocessor::normalizeImage(QImage * input, int red, int green, int blue, int rThrs, int gThrs, int bThrs) { + + // load image + IplImage * img = NULL; + img = qImageToCvImage(input); + + // prepare particular channels + IplImage* imgRed = cvCreateImage(cvGetSize(img), 8, 1); + IplImage* imgGreen = cvCreateImage(cvGetSize(img), 8, 1); + IplImage* imgBlue = cvCreateImage(cvGetSize(img), 8, 1); + + // split channels + cvSplit(img, imgBlue, imgGreen, imgRed, NULL); + + // change to bitmask! + int lowRed = red-rThrs; + if (lowRed < 0) { + lowRed = 0; + } + if (lowRed > 255) { + lowRed = 255; + } + + int highRed = red+rThrs; + if (highRed < 0) { + highRed = 0; + } + if (highRed > 255) { + highRed = 255; + } + + int lowGreen = green-gThrs; + if (lowGreen < 0) { + lowGreen = 0; + } + if (lowGreen > 255) { + lowGreen = 255; + } + + int highGreen = green+gThrs; + if (highGreen < 0) { + highGreen = 0; + } + if (highGreen > 255) { + highGreen = 255; + } + + int lowBlue = blue-bThrs; + if (lowBlue < 0) { + lowBlue = 0; + } + if (lowBlue > 255) { + lowBlue = 255; + } + + int highBlue = blue+bThrs; + if (highBlue < 0) { + highBlue = 0; + } + if (highBlue > 255) { + highBlue = 255; + } + + // mask each channle + cvInRangeS(imgRed, cvScalar(lowRed), cvScalar(highRed), imgRed); + cvInRangeS(imgGreen, cvScalar(lowGreen), cvScalar(highGreen), imgGreen); + cvInRangeS(imgBlue, cvScalar(lowBlue), cvScalar(highBlue), imgBlue); + + cvMul(imgRed, imgGreen, imgRed); + cvMul(imgRed, imgBlue, imgRed); + + // transform result to QImage format + QImage qOutput = cvImageToQImage(imgRed); + + // release memory + cvReleaseImage(&img); + cvReleaseImage(&imgRed); + cvReleaseImage(&imgGreen); + cvReleaseImage(&imgBlue); + return qOutput; +} + diff --git a/opencvprocessor.h b/opencvprocessor.h new file mode 100644 index 0000000..98bdde4 --- /dev/null +++ b/opencvprocessor.h @@ -0,0 +1,44 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file opencvprocessor.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef OPENCVPROCESSOR_H +#define OPENCVPROCESSOR_H + +#include +#include "opencv/cv.h" +#include "opencv/highgui.h" + +class OpenCVprocessor : public QMainWindow +{ + Q_OBJECT +public: + explicit OpenCVprocessor(QWidget *parent = 0); + IplImage * qImageToCvImage(QImage *qimg); + QImage cvImageToQImage(const IplImage *iplImage); + + QImage processThreshold_Edges(QImage * input, bool processEdges, int threshValue); + QImage normalizeImage(QImage * input, int red, int green, int blue, int rThrs, int gThrs, int bThrs); + + QImage detectDrawQuads(QImage * input); + + + + std::vector makeHistogram(QImage * input); + IplImage* DrawHistogram(CvHistogram *hist, float scaleX=1, float scaleY=1); + +signals: + +public slots: + +private: + IplImage * cvImage; + QImage qtImage; + +}; + +#endif // OPENCVPROCESSOR_H diff --git a/project.cpp b/project.cpp new file mode 100644 index 0000000..52b1bca --- /dev/null +++ b/project.cpp @@ -0,0 +1,456 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file project.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include "project.h" +#include "mainwindow.h" +#include "xmlparser.h" + +// Konstanty +const QString Project::PROJVERSION = QString("1.0"); +const QString Project::PROJSUBDIR_IMAGES = QString("images"); +const QString Project::PROJSUBDIR_LAYERS = QString("layers"); +const QString Project::PROJ_FILE_EXT = QString(".mapro"); +const QString Project::XML_TRUE = QString("1"); +const QString Project::XML_FALSE = QString("0"); + +// -------------------------------------------- +/** + * @brief = KONSTRUKTOR + */ +// -------------------------------------------- +Project::Project(QObject *parent) : QObject(parent){ + valueInit(); +} + +// -------------------------------------------- +/** + * @brief = DESTRUKTOR + */ +// -------------------------------------------- +Project::~Project() +{ +} + +void Project::valueInit() { + setProjectName(""); + setProjectFileName(""); + setProjectRootDir(""); + setProjectRootDir_old(""); + setImagesDir(PROJSUBDIR_IMAGES); + setLayersDir(PROJSUBDIR_LAYERS); + setFileImported(false); + std::vector imgs; + setImages(imgs); + std::vector lrs; + setLayers(lrs); +} + +void Project::setProjectName (QString s) { + this->projectName = s; +} + +QString Project::getProjectName (void) { + return this->projectName; +} + +void Project::setProjectFileName (QString s) { + this->projectFileName = s; +} + +QString Project::getProjectFileName (void) { + return this->projectFileName; +} + +void Project::setProjectRootDir (QString s) { + this->projectRootDir = s; +} + +QString Project::getProjectRootDir (void) { + return this->projectRootDir; +} + +void Project::setProjectRootDir_old (QString s) { + this->projectRootDir_old = s; +} + +QString Project::getProjectRootDir_old (void) { + return this->projectRootDir_old; +} + +void Project::setImagesDir (QString s) { + this->imagesDir = s; +} + +QString Project::getImagesDir (void) { + return this->imagesDir; +} + +void Project::setLayersDir (QString s) { + this->layersDir = s; +} + +QString Project::getLayersDir (void) { + return this->layersDir; +} + +void Project::setFileImported (bool i) { + this->fileImported = i; +} + +bool Project::getFileImported (void) { + return this->fileImported; +} + + +void Project::setImages (std::vector i) { + if (i != getImages()) { + this->images = i; + emit imagesValueChanged(); + } +} + +std::vector Project::getImages (void) { + return this->images; +} + +void Project::addToImages (QString s) { + this->images.push_back(s); + emit imagesValueChanged(); +} + +QString Project::getSelectedImage (unsigned int index) { + if (images.size() > index) { + return this->images[index]; + } + else { + return "ERROR"; + } +} + +void Project::eraseSelectedImage(unsigned int index) { + if (images.size() > index) { + std::vector::iterator it = images.begin(); + it += index; + images.erase(it); + } +} + +void Project::emitDeleteImported() { + emit imagesValueChanged(); +} + + + + +void Project::setLayers (std::vector i) { + if (i != getLayers()) { + this->layers = i; + emit layersValueChanged(); + } +} + +std::vector Project::getLayers (void) { + return this->layers; +} + +void Project::addToLayers (QString s) { + this->layers.push_back(s); + emit layersValueChanged(); +} + +QString Project::getSelectedLayer (unsigned int index) { + if (layers.size() > index) { + return this->layers[index]; + } + else { + return "ERROR"; + } +} + +void Project::eraseSelectedLayer(unsigned int index) { + if (layers.size() > index) { + std::vector::iterator it = layers.begin(); + it += index; + layers.erase(it); + } +} + +void Project::emitDeleteAnalysings() { + emit layersValueChanged(); +} + +int Project::layersCount() { + return this->layers.size(); +} + + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + +void Project::prepareProject(QString rootDir, QString projectName, QString projectFileName, + bool fileImported, std::vector images, std::vector layers) { + + setProjectRootDir_old(getProjectRootDir()); + setProjectRootDir(rootDir); + setProjectName(projectName); + setProjectFileName(projectFileName); + setFileImported(fileImported); + setImagesDir(Project::PROJSUBDIR_IMAGES); + setLayersDir(Project::PROJSUBDIR_LAYERS); + setImages(images); + setLayers(layers); +} + +bool Project::fileCopy(QString fileName, QString destDir, QString destFilename, QString * newFileName) { + + // remembering of the filename + QFileInfo fi(fileName); + + // get the number for filename (filename_number.ext) + QDir dir(destDir); + int number = dir.count(); + number--; + + while (1) { + QString numStr = QString::number(number); + QFile destFile(destDir + "/" + destFilename + "_" + numStr + "." + fi.completeSuffix()); + + if (!destFile.exists()) { + break; + } + else { + number++; + } + } + + // copy the file to the project directory with a specified filename + QString numStr = QString::number(number); + QString finalDestFileString = destDir + "/" + destFilename + "_" + numStr + "." + fi.completeSuffix(); + QFile sourceFile(fileName); + QFile finalDestFile(finalDestFileString); + + QFileInfo finalFi(finalDestFileString); + *newFileName = finalFi.baseName() + "." + finalFi.completeSuffix(); + + if (sourceFile.exists()) { + if (!sourceFile.copy(finalDestFile.fileName())) { + return false; + } + } + + return true; +} + +bool Project::removeDir(QString dirName) { + bool result = true; + QDir dir(dirName); + + if (dir.exists(dirName)) { + Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) { + if (info.isDir()) { + result = this->removeDir(info.absoluteFilePath()); + } + else { + result = QFile::remove(info.absoluteFilePath()); + } + + if (!result) { + return result; + } + } + result = dir.rmdir(dirName); + } + + return result; +} + + +bool Project::saveToFile(bool removeSubDirs) { + + if (getProjectRootDir() == getProjectRootDir_old()) { + removeSubDirs = false; + } + + QFile mapro(getProjectRootDir() + "/" + getProjectFileName()); + if (mapro.exists()) { + if (!mapro.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + return false; + } + } + else { + if (!mapro.open(QIODevice::ReadWrite)) { + return false; + } + } + + // make an entry in XML for an imported image + QString importedInt = XML_FALSE; + if (getFileImported()) { + importedInt = XML_TRUE; + } + + // prepare directory structure for the project + QString projImages_dir = getProjectRootDir(); + projImages_dir.append("/").append(getImagesDir()); + QString projLayers_dir = getProjectRootDir(); + projLayers_dir.append("/").append(getLayersDir()); + + if (removeSubDirs) { + if (QDir(projImages_dir).exists()) { + removeDir(projImages_dir); + } + QDir().mkpath(projImages_dir); + + if (QDir(projLayers_dir).exists()) { + removeDir(projLayers_dir); + } + QDir().mkpath(projLayers_dir); + } + else { + if (!QDir(projImages_dir).exists()) { + QDir().mkpath(projImages_dir); + } + + if (!QDir(projLayers_dir).exists()) { + QDir().mkpath(projLayers_dir); + } + } + + // copying of the files and creating an XML entry + // BACKGROUNDs + QString importedImageFilesXML = ""; + std::vector tmpB = getImages(); + for (uint i = 0; i < getImages().size(); i++) { + QString scrImage = getImages()[i]; // source file + QFileInfo scrFi(scrImage); + + // if the file is already in the right place, do not perform the copying + bool fileFromProjectDir = false; + if (scrImage == (scrFi.baseName() + "." + scrFi.completeSuffix())) { + scrImage = getProjectRootDir_old() + "/" + getImagesDir() + "/" + scrImage; + fileFromProjectDir = true; + } + + QString destAddr = getProjectRootDir() + "/" + getImagesDir(); // destination directory + QString newFileName_part = "pict"; // renaming of the file + QString newFileName_whole; // final file name for XML entry + + // for SAVE it does not copy files that already exist in the project + bool makeCopy = true; + QFile testExist(scrImage); + if (!removeSubDirs && fileFromProjectDir && testExist.exists()) { + makeCopy = false; + newFileName_whole = getImages()[i]; + } + + if (makeCopy && !fileCopy(scrImage, destAddr, newFileName_part, &newFileName_whole)) { + removeDir(getProjectRootDir()); + return false; + } + + if (makeCopy) { + tmpB[i] = newFileName_whole; + } + + importedImageFilesXML += "\t\t" + newFileName_whole + "\n"; + } + setImages(tmpB); + + + // copying of the files and creating an XML entry + // LAYERs + QString importedLayerFilesXML = ""; + std::vector tmpL = getLayers(); + for (uint i = 0; i < getLayers().size(); i++) { + + QString scrImage = getLayers()[i]; // source file + QFileInfo scrFi(scrImage); + + bool fileFromProjectDir = false; + if (scrImage == (scrFi.baseName() + "." + scrFi.completeSuffix())) { + scrImage = getProjectRootDir_old() + "/" + getLayersDir() + "/" + scrImage; + fileFromProjectDir = true; + } + + QString destAddr = getProjectRootDir() + "/" + getLayersDir(); // destination directory + QString newFileName_part = scrFi.baseName(); // renaming of the file + QString newFileName_whole; // final file name for XML entry + + // for SAVE it does not copy files that already exist in the project + bool makeCopy = true; + QFile testExist(scrImage); + if (!removeSubDirs && fileFromProjectDir && testExist.exists()) { + makeCopy = false; + newFileName_whole = getLayers()[i]; + } + + if (makeCopy && !fileCopy(scrImage, destAddr, newFileName_part, &newFileName_whole)) { + removeDir(getProjectRootDir()); + return false; + } + + if (makeCopy) { + tmpL[i] = newFileName_whole; + } + + importedLayerFilesXML += "\t\t" + newFileName_whole + "\n"; + } + setLayers(tmpL); + + + // XML format of the project file + QTextStream ts( &mapro ); + ts << "" << endl << + "\t" + PROJVERSION + "" << endl << + "\t" + getProjectName() + "" << endl << + "\t" + importedInt + "" << endl << + "\t" + getImagesDir() + "" << endl << + "\t" + getLayersDir() + "" << endl << + "\t" << endl; + if (importedImageFilesXML.length() > 0) { + ts << importedImageFilesXML; + } + ts << "\t" << endl << + "\t" << endl; + if (importedLayerFilesXML.length() > 0) { + ts << importedLayerFilesXML; + } + ts << "\t" << endl << + "" << endl; + + mapro.close(); + return true; +} + +bool Project::deleteAnalysing(int index) { + // prepare path for removing of a file + QString fileToRemove = getProjectRootDir() + "/"; + fileToRemove += getLayersDir() + "/"; + fileToRemove += getSelectedLayer(index); + + // remove file from LAYERs + eraseSelectedLayer(index); + return QFile::remove(fileToRemove); +} + + +bool Project::deleteImported(int index) { + // prepare path for removing of a file + QString fileToRemove = getProjectRootDir() + "/"; + fileToRemove += getImagesDir() + "/"; + fileToRemove += getSelectedImage(index); + + // remove file from BACKGROUNDs + eraseSelectedImage(index); + + // samotne smazani souboru + return QFile::remove(fileToRemove); +} + + diff --git a/project.h b/project.h new file mode 100644 index 0000000..c01f23b --- /dev/null +++ b/project.h @@ -0,0 +1,104 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file project.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef PROJECT_H +#define PROJECT_H + +#include +#include +#include +#include +#include + +#include + +// singleton +#include "./libs/staticsingleton.h" + +class Project : public QObject +{ + Q_OBJECT + +public: + static const QString PROJVERSION; + static const QString PROJSUBDIR_IMAGES; + static const QString PROJSUBDIR_LAYERS; + static const QString XML_TRUE; + static const QString XML_FALSE; + static const QString PROJ_FILE_EXT; + + void valueInit(); + + void setProjectName (QString name); + QString getProjectName (void); + void setProjectFileName (QString name); + QString getProjectFileName (void); + void setProjectRootDir (QString s); + QString getProjectRootDir (void); + void setProjectRootDir_old (QString s); + QString getProjectRootDir_old (void); + void setImagesDir (QString s); + QString getImagesDir (void); + void setLayersDir (QString s); + QString getLayersDir (void); + void setFileImported (bool i); + bool getFileImported (void); + + void setImages (std::vector i); + std::vector getImages (void); + void addToImages (QString s); + QString getSelectedImage (unsigned int index); + void eraseSelectedImage(unsigned int index); + void emitDeleteImported(); + + void setLayers (std::vector i); + std::vector getLayers (void); + void addToLayers (QString s); + QString getSelectedLayer (unsigned int index); + void eraseSelectedLayer(unsigned int index); + void emitDeleteAnalysings(); + int layersCount(); + + void prepareProject(QString rootDir, QString projectName, + QString projectFileName, bool fileImported, + std::vector images, std::vector layers); + bool saveToFile(bool removeSubDirs); + bool fileCopy(QString fileName, QString destDir, QString destFilename, QString * newFileName); + bool removeDir(QString dirName); + + bool deleteAnalysing(int index); + bool deleteImported(int index); + +signals: + void imagesValueChanged(); + void layersValueChanged(); + +public slots: + +private: + // constructor, destructor private = singleton + explicit Project(QObject *parent = 0); + ~Project(); + // friend allows singleton to be created by this object + friend class cStaticSingleton; + + QString projectRootDir; + QString projectRootDir_old; + QString projectFileName; + QString projectName; + bool fileImported; + QString imagesDir; + QString layersDir; + std::vector images; + std::vector layers; +}; + +// singleton instance of the project +typedef cStaticSingleton cProject; + +#endif // PROJECT_H diff --git a/projectwizard.cpp b/projectwizard.cpp new file mode 100644 index 0000000..65e7117 --- /dev/null +++ b/projectwizard.cpp @@ -0,0 +1,148 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file projectwizard.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include "projectwizard.h" +#include "xmlparser.h" +#include "mainwindow.h" + +ProjectWizard::ProjectWizard(QWidget *parent) : QWizard(parent) { + + addPage(new WelcomePage); + addPage(new ProjectInfoPage); + + setWindowTitle(tr("New Project Wizard")); +} + +void ProjectWizard::accept() { + + QString projectName = field("projectName").toString(); + QString projectDir = field("projectDir").toString(); + bool checkBox = field("importFileCheck").toBool(); + QString imageFileName = field("imageFile").toString(); + + std::vector imagesVect; + std::vector layersVect; + + // import of a file + if (checkBox) { + imagesVect.push_back(imageFileName); + } + + QString projectFileName = projectName + Project::PROJ_FILE_EXT; + + // make the new project file in the project root + cProject::Instance()->prepareProject(projectDir, projectName, projectFileName, checkBox, imagesVect, layersVect); + bool removeSubDirs = true; + cProject::Instance()->saveToFile(removeSubDirs); + + QDialog::accept(); + + QMessageBox::information(this, tr("microAnalyzer :: PROJECT CREATED"), tr("The project \"%1\" was successfully created.").arg(projectName)); +} + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- + +WelcomePage::WelcomePage(QWidget *parent): QWizardPage(parent) { + + setTitle(tr("Welcome to New Project Wizard!")); + + label = new QLabel(tr("

This wizard will create a New Project directory " + "with basic configuration. It is needed to fill only few information.

" + "

Click next to continue, please.

")); + + label->setWordWrap(true); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(label); + setLayout(layout); +} + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- + +ProjectInfoPage::ProjectInfoPage(QWidget *parent): QWizardPage(parent) { + + setTitle(tr("Project details
")); + + // name of the project + projectNameLabel = new QLabel(tr("Project name:")); + projectNameLineEdit = new QLineEdit; + projectNameLabel->setBuddy(projectNameLineEdit); + + // root dir of the project + projectDirLabel = new QLabel(tr("Choose &project root directory:")); + projectDirLineEdit = new QLineEdit; + projectDirLabel->setBuddy(projectDirLineEdit); + chooseDirBtn = new QPushButton("Choose dir"); + connect(chooseDirBtn, SIGNAL(clicked()), this, SLOT(browseDirs())); + + // image import + imageImportLabel = new QLabel(tr("Choose &image file to import:")); + imageImportLineEdit = new QLineEdit; + imageImportLineEdit->setEnabled(false); + imageImportLabel->setBuddy(imageImportLineEdit); + importFileCheckBox = new QCheckBox(tr("Import image file now.")); + importImageBtn = new QPushButton("Import image"); + importImageBtn->setEnabled(false); + connect(importImageBtn, SIGNAL(clicked()), this, SLOT(openImageFile())); + connect(importFileCheckBox, SIGNAL(toggled(bool)), importImageBtn, SLOT(setEnabled(bool))); + connect(importFileCheckBox, SIGNAL(toggled(bool)), imageImportLineEdit, SLOT(setEnabled(bool))); + + registerField("projectName*", projectNameLineEdit); + registerField("projectDir*", projectDirLineEdit); + registerField("importFileCheck", importFileCheckBox); + registerField("imageFile", imageImportLineEdit); + + // UI wizard + QGridLayout *layout = new QGridLayout; + layout->addWidget(projectNameLabel, 0, 0); + layout->addWidget(projectNameLineEdit, 0, 1, 1, 3); + + QLabel *separatorLabel1 = new QLabel(tr(" ")); + layout->addWidget(separatorLabel1, 1, 0); + + layout->addWidget(projectDirLabel, 2, 0); + layout->addWidget(projectDirLineEdit, 3, 0, 1, 3); + layout->addWidget(chooseDirBtn, 3, 3); + + QLabel *separatorLabel = new QLabel(tr(" ")); + layout->addWidget(separatorLabel, 4, 0); + + layout->addWidget(importFileCheckBox, 5, 0); + layout->addWidget(imageImportLabel, 6, 0); + layout->addWidget(imageImportLineEdit, 7, 0, 1, 3); + layout->addWidget(importImageBtn, 7, 3); + + setLayout(layout); +} + + +void ProjectInfoPage::browseDirs() { + QString directory = QFileDialog::getExistingDirectory(0 , "Choose project root directory", QDir::currentPath()); + if (!directory.isEmpty()) { + projectDirLineEdit->setText(directory); + } +} + +/* + * Load image + */ +void ProjectInfoPage::openImageFile() { + QString imageFileName = QFileDialog::getOpenFileName(this, tr("Open Image"), QDir::currentPath(), "*.bmp *.png *.tif *.jpg *.jpeg"); + if (!imageFileName.isEmpty()) { + imageImportLineEdit->setText(imageFileName); + } +} + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- diff --git a/projectwizard.h b/projectwizard.h new file mode 100644 index 0000000..e79b99e --- /dev/null +++ b/projectwizard.h @@ -0,0 +1,81 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file projectwizard.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef PROJECTWIZARD_H +#define PROJECTWIZARD_H + +#include + +// singleton +#include "project.h" + +class QCheckBox; +class QMessageBox; +class QGroupBox; +class QLabel; +class QLineEdit; +class QRadioButton; +class QPushButton; +class MainWindow; + +class ProjectWizard : public QWizard +{ + Q_OBJECT + +public: + explicit ProjectWizard(QWidget *parent = 0); + void accept(); + +signals: + +public slots: + +}; + +// -------------------------------------------- +class WelcomePage : public QWizardPage +{ + Q_OBJECT + +public: + WelcomePage(QWidget *parent = 0); + +private: + QLabel *label; +}; + +// -------------------------------------------- +class ProjectInfoPage : public QWizardPage +{ + Q_OBJECT + +public: + ProjectInfoPage(QWidget *parent = 0); + +private slots: + void openImageFile(); + void browseDirs(); + +private: + QLabel *projectNameLabel; + QLineEdit *projectNameLineEdit; + + QLabel *projectDirLabel; + QLineEdit *projectDirLineEdit; + + QCheckBox *importFileCheckBox; + QGroupBox *groupBox; + + QLabel *imageImportLabel; + QLineEdit *imageImportLineEdit; + + QPushButton *importImageBtn; + QPushButton *chooseDirBtn; +}; + +#endif // PROJECTWIZARD_H diff --git a/tableformat.cpp b/tableformat.cpp new file mode 100644 index 0000000..304e3f2 --- /dev/null +++ b/tableformat.cpp @@ -0,0 +1,146 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file tebleformat.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include "tableformat.h" + +TableFormat::TableFormat(QObject *parent): QAbstractTableModel(parent) { +} + +TableFormat::TableFormat(QList pairs, QObject *parent) : QAbstractTableModel(parent) { + listOfPairs = pairs; +} + +Qt::ItemFlags TableFormat::flags(const QModelIndex &index) const { + + Qt::ItemFlags result = QAbstractTableModel::flags(index); + if (index.column() == 0) { + result = Qt::ItemIsUserCheckable | Qt::ItemIsEditable | Qt::ItemIsEnabled; + return result; + } + + if (!index.isValid()) { + return Qt::ItemIsEnabled; + } + + return QAbstractTableModel::flags(index); +} + +int TableFormat::rowCount(const QModelIndex &parent) const { + Q_UNUSED(parent); + return listOfPairs.size(); +} + +int TableFormat::columnCount(const QModelIndex &parent) const { + Q_UNUSED(parent); + return 3; +} + +QVariant TableFormat::data(const QModelIndex &index, int role) const { + if (!index.isValid()) { + return QVariant(); + } + + if (index.row() >= listOfPairs.size() || index.row() < 0) { + return QVariant(); + } + + LayerRecord * currentRow = listOfPairs.at(index.row()); + if (role == Qt::CheckStateRole && index.column() == 0) { + return currentRow->getCheckBox(); + } + + if (role == Qt::DisplayRole) { + if (index.column() == 0) { + // checkBox + } + else if (index.column() == 1) { + return currentRow->getName(); + } + else if (index.column() == 2) { + return currentRow->getOpacity(); + } + } + return QVariant(); +} + +QVariant TableFormat::headerData(int section, Qt::Orientation orientation, int role) const { + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) { + switch (section) { + case 0: + return tr(""); + case 1: + return tr("Layer"); + case 2: + return tr("%"); + + default: + return QVariant(); + } + } + return QVariant(); +} + +bool TableFormat::insertRows(int position, int rows, const QModelIndex &index) { + Q_UNUSED(index); + beginInsertRows(QModelIndex(), position, position+rows-1); + + for (int row = 0; row < rows; row++) { + QString s1 = " "; + listOfPairs.insert(0, new LayerRecord(true, s1, s1)); + } + + endInsertRows(); + return true; +} + +bool TableFormat::removeRows(int position, int rows, const QModelIndex &index) { + Q_UNUSED(index); + beginRemoveRows(QModelIndex(), position, position+rows-1); + + for (int row=0; row < rows; ++row) { + listOfPairs.removeAt(position); + } + + endRemoveRows(); + return true; +} + +bool TableFormat::setData(const QModelIndex &index, const QVariant &value, int role) { + + if (index.isValid() && role == Qt::EditRole) { + int row = index.row(); + + LayerRecord * p = listOfPairs.value(row); + + if (index.column() == 0) { + } + else if (index.column() == 1) { + p->setName(value.toString()); + } + else if (index.column() == 2) { + p->setOpacity(value.toString()); + } + else { + return false; + } + + listOfPairs.replace(row, p); + emit(dataChanged(index, index)); + + return true; + } + + return false; +} + +QList TableFormat::getList() { + return listOfPairs; +} diff --git a/tableformat.h b/tableformat.h new file mode 100644 index 0000000..e2be16a --- /dev/null +++ b/tableformat.h @@ -0,0 +1,41 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file tableformat.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef TABLEFORMAT_H +#define TABLEFORMAT_H + +#include +#include + +#include "layerrecord.h" + + class TableFormat : public QAbstractTableModel + { + Q_OBJECT + + public: + TableFormat(QObject *parent=0); + TableFormat(QList listofPairs, QObject *parent=0); + + Qt::ItemFlags flags(const QModelIndex &index) const; + + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + + bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole); + bool insertRows(int position, int rows, const QModelIndex &index=QModelIndex()); + bool removeRows(int position, int rows, const QModelIndex &index=QModelIndex()); + QList getList(); + + private: + QList listOfPairs; + }; + +#endif // TABLEFORMAT_H diff --git a/xmlparser.cpp b/xmlparser.cpp new file mode 100644 index 0000000..01bb39d --- /dev/null +++ b/xmlparser.cpp @@ -0,0 +1,87 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file xmlparser.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include "xmlparser.h" +#include "project.h" +#include "mainwindow.h" + +XMLparser::XMLparser(QWidget *parent) : + QMainWindow(parent) +{ +} + +bool XMLparser::read(QIODevice *device) { + + QString errorStr; + int errorLine; + int errorColumn; + + if (!domDocument.setContent(device, true, &errorStr, &errorLine, &errorColumn)) { + QMessageBox::information(this, tr("microAnalyzer :: ERROR"), + tr("Project file parse error at line %1, column %2:\n%3") + .arg(errorLine) + .arg(errorColumn) + .arg(errorStr)); + return false; + } + + QDomElement root = domDocument.documentElement(); + + if (root.tagName() != "ma_project") { + QMessageBox::critical(window(), tr("microAnalyzer :: ERROR"), tr("The file is not a microAnalyzer project file.")); + return false; + } else if (root.hasAttribute("version") && root.attribute("version") != "1.0") { + QMessageBox::critical(window(), tr("microAnalyzer :: ERROR"), tr("The file is not a microAnalyzer project file version 1.0.")); + return false; + } + + // basic values + QString childName = root.firstChildElement("name").text(); + QString childFileImported = root.firstChildElement("fileImported").text(); + QString childImagesDir = root.firstChildElement("imagesDir").text(); + QString childLayersDir = root.firstChildElement("layersDir").text(); + + // load information from xml to the project instance + cProject::Instance()->setProjectName(childName); + cProject::Instance()->setFileImported((childFileImported == Project::XML_TRUE) ? true : false); + cProject::Instance()->setImagesDir(childImagesDir); + cProject::Instance()->setLayersDir(childLayersDir); + cProject::Instance()->setProjectFileName(cProject::Instance()->getProjectName() + Project::PROJ_FILE_EXT); + + // load imported images for backgrounds + std::vector imgVect; + if (childFileImported == Project::XML_TRUE) { + + QDomElement childImagesRoot = root.firstChildElement("images"); + if (!childImagesRoot.isNull()) { + + QDomElement childImages = childImagesRoot.firstChildElement("image"); + while (!childImages.isNull()) { + imgVect.push_back(childImages.text()); + childImages = childImages.nextSiblingElement("image"); + } + } + } + cProject::Instance()->setImages(imgVect); + + // load imported layers + std::vector layers; + QDomElement childLayersRoot = root.firstChildElement("layers"); + if (!childLayersRoot.isNull()) { + + QDomElement childLayers = childLayersRoot.firstChildElement("layer"); + while (!childLayers.isNull()) { + layers.push_back(childLayers.text()); + childLayers = childLayers.nextSiblingElement("layer"); + } + } + cProject::Instance()->setLayers(layers); + + return true; +} + diff --git a/xmlparser.h b/xmlparser.h new file mode 100644 index 0000000..2a1ed13 --- /dev/null +++ b/xmlparser.h @@ -0,0 +1,37 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file xmlparser.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef XMLPARSER_H +#define XMLPARSER_H + +#include +#include +#include +#include + +// singleton +#include "project.h" + +class XMLparser : public QMainWindow +{ + Q_OBJECT + +public: + explicit XMLparser(QWidget *parent = 0); + bool read(QIODevice *file); + +signals: + +public slots: + +private: + QDomDocument domDocument; + +}; + +#endif // XMLPARSER_H