diff --git a/scripts_to_build/make.bat b/scripts_to_build/make.bat new file mode 100644 index 0000000..7aacb31 --- /dev/null +++ b/scripts_to_build/make.bat @@ -0,0 +1,6 @@ +cd build +cd x64 +cmake --build . --config Release +cmake --build . --config Release --target make_zip + +PAUSE \ No newline at end of file diff --git a/scripts_to_build/win_make_vc14_x64_abreheret_qt5.10.bat b/scripts_to_build/win_make_vc14_x64_abreheret_qt5.10.bat new file mode 100644 index 0000000..b46d7f8 --- /dev/null +++ b/scripts_to_build/win_make_vc14_x64_abreheret_qt5.10.bat @@ -0,0 +1,8 @@ +mkdir build +cd build +mkdir x64 +cd x64 +cmake -DQT5_DIR=D:/dev/Qt/5.10.0/msvc2015_64/lib/cmake -DCMAKE_PREFIX_PATH="D:/DEV/git/pl_all/pl_3rdparty/package" -G "Visual Studio 14 Win64" ../../.. +REM cmake --build . --config Release + +PAUSE \ No newline at end of file diff --git a/src/image_canvas.cpp b/src/image_canvas.cpp index 1c7ed3a..b1d5e15 100644 --- a/src/image_canvas.cpp +++ b/src/image_canvas.cpp @@ -5,12 +5,14 @@ #include #include -ImageCanvas::ImageCanvas(QWidget * parent, MainWindow *ui) : - QLabel(parent) , +ImageCanvas::ImageCanvas(MainWindow *ui) : + QLabel() , _ui(ui), _alpha(0.5), _pen_size(30) { + _scroll_parent = new QScrollArea(ui); + setParent(_scroll_parent); resize(800,600); _scale = 1.0; _initPixmap(); @@ -21,6 +23,14 @@ ImageCanvas::ImageCanvas(QWidget * parent, MainWindow *ui) : _undo_list.clear(); _undo_index = 0; _undo = false; + + _scroll_parent->setBackgroundRole(QPalette::Dark); + _scroll_parent->setWidget(this); + +} + +ImageCanvas::~ImageCanvas() { + _scroll_parent->deleteLater(); } void ImageCanvas::_initPixmap() { @@ -52,7 +62,7 @@ void ImageCanvas::loadImage(const QString &filename) { _undo_index = 0; if (QFile(_mask_file).exists()) { _mask = ImageMask(_mask_file,_ui->id_labels); - emit(_ui->button_watershed->released()); + _ui->runWatershed(this);// button_watershed->released()); _ui->checkbox_manuel_mask->setChecked(true); _undo_list.push_back(_mask); _undo_index++; @@ -72,12 +82,18 @@ void ImageCanvas::saveMask() { _mask.id.save(_mask_file); if (!_watershed.id.isNull()) { - QImage watershed_without_border = removeBorder(_watershed.id, _ui->id_labels); - watershed_without_border.save(_watershed_file); + QImage watershed = _watershed.id; + if (!_ui->checkbox_border_ws->isChecked()) { + watershed = removeBorder(_watershed.id, _ui->id_labels); + } + watershed.save(_watershed_file); QFileInfo file(_img_file); QString color_file = file.dir().absolutePath() + "/" + file.baseName() + "_color_mask.png"; - idToColor(watershed_without_border, _ui->id_labels).save(color_file); + idToColor(watershed, _ui->id_labels).save(color_file); } + _undo_list.clear(); + _undo_index = 0; + _ui->setStarAtNameOfTab(false); } void ImageCanvas::scaleChanged(double scale) { @@ -154,6 +170,7 @@ void ImageCanvas::mouseReleaseEvent(QMouseEvent * e) { } _undo_list.push_back(_mask); _undo_index++; + _ui->setStarAtNameOfTab(true); _ui->undo_action->setEnabled(true); } @@ -208,15 +225,14 @@ void ImageCanvas::clearMask() { void ImageCanvas::wheelEvent(QWheelEvent * event) { int delta = event->delta() > 0 ? 1 : -1; if (Qt::ShiftModifier == event->modifiers()) { - _ui->scroll_area->verticalScrollBar()->setEnabled(false); + _scroll_parent->verticalScrollBar()->setEnabled(false); int value = _ui->spinbox_pen_size->value() + delta * _ui->spinbox_pen_size->singleStep(); _ui->spinbox_pen_size->setValue(value); emit(_ui->spinbox_pen_size->valueChanged(value)); setSizePen(value); repaint(); } else if (Qt::ControlModifier == event->modifiers()) { - QScrollArea * sc = _ui->scroll_area; - sc->verticalScrollBar()->setEnabled(false); + _scroll_parent->verticalScrollBar()->setEnabled(false); double value = _ui->spinbox_scale->value() + delta * _ui->spinbox_scale->singleStep(); value = std::min(_ui->spinbox_scale->maximum(),value); value = std::max(_ui->spinbox_scale->minimum(), value); @@ -225,7 +241,7 @@ void ImageCanvas::wheelEvent(QWheelEvent * event) { scaleChanged(value); repaint(); } else { - _ui->scroll_area->verticalScrollBar()->setEnabled(true); + _scroll_parent->verticalScrollBar()->setEnabled(true); } } diff --git a/src/image_canvas.h b/src/image_canvas.h index be9b464..3d3322d 100644 --- a/src/image_canvas.h +++ b/src/image_canvas.h @@ -6,6 +6,7 @@ #include #include +#include class MainWindow; @@ -14,7 +15,8 @@ class ImageCanvas : public QLabel { public: - ImageCanvas(QWidget * parent, MainWindow *ui); + ImageCanvas(MainWindow *ui); + ~ImageCanvas(); void setId(int id); void setMask(const ImageMask & mask); @@ -26,6 +28,8 @@ class ImageCanvas : public QLabel { void refresh(); void updateMaskColor(const Id2Labels & labels) { _mask.updateColor(labels); } void loadImage(const QString &file); + QScrollArea * getScrollParent() const { return _scroll_parent; } + bool isNotSaved() const { return _undo_list.size() > 1; } protected: void mouseMoveEvent(QMouseEvent * event) override; @@ -46,9 +50,11 @@ public slots : private: MainWindow *_ui; + void _initPixmap(); void _drawFillCircle(QMouseEvent * e); + QScrollArea *_scroll_parent ; double _scale ; double _alpha ; QImage _image ; diff --git a/src/main_window.cpp b/src/main_window.cpp index 4cd08e9..653470e 100644 --- a/src/main_window.cpp +++ b/src/main_window.cpp @@ -1,6 +1,6 @@ #include "main_window.h" #include "utils.h" - +#include #include #include #include @@ -24,54 +24,67 @@ MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags) setupUi(this); setWindowTitle(QApplication::translate("MainWindow", "PixelAnnotationTool " PIXEL_ANNOTATION_TOOL_GIT_TAG, Q_NULLPTR)); list_label->setSpacing(1); - - scroll_area = new QScrollArea; - image_canvas = new ImageCanvas(scroll_area, this); + image_canvas = NULL; save_action = new QAction(tr("&Save current image"), this); + close_tab_action = new QAction(tr("&Close current tab"), this); undo_action = new QAction(tr("&Undo"), this); redo_action = new QAction(tr("&Redo"), this); undo_action->setShortcuts(QKeySequence::Undo); redo_action->setShortcuts(QKeySequence::Redo); save_action->setShortcut(Qt::CTRL+Qt::Key_S); + close_tab_action->setShortcut(Qt::CTRL + Qt::Key_W); undo_action->setEnabled(false); redo_action->setEnabled(false); menuFile->addAction(save_action); + menuEdit->addAction(close_tab_action); menuEdit->addAction(undo_action); menuEdit->addAction(redo_action); - image_canvas->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); - image_canvas->setScaledContents(true); - - scroll_area->setBackgroundRole(QPalette::Dark); - scroll_area->setWidget(image_canvas); - - setCentralWidget(scroll_area); - - connect(spinbox_scale, SIGNAL(valueChanged(double)), image_canvas, SLOT(scaleChanged(double))); - connect(spinbox_alpha, SIGNAL(valueChanged(double)), image_canvas, SLOT(alphaChanged(double))); - connect(spinbox_pen_size, SIGNAL(valueChanged(int)), image_canvas, SLOT(setSizePen(int))); - connect(button_watershed, SIGNAL(released()), this, SLOT(runWatershed())); - connect(checkbox_watershed_mask, SIGNAL(clicked()), image_canvas, SLOT(update())); - connect(checkbox_manuel_mask, SIGNAL(clicked()), image_canvas, SLOT(update())); - connect(actionClear, SIGNAL(triggered()), image_canvas, SLOT(clearMask())); - - connect(actionOpen_config_file, SIGNAL(triggered()), this, SLOT(loadConfigFile())); - connect(actionSave_config_file, SIGNAL(triggered()), this, SLOT(saveConfigFile())); - - connect(undo_action, SIGNAL(triggered()), image_canvas, SLOT(undo())); - connect(redo_action, SIGNAL(triggered()), image_canvas, SLOT(redo())); - connect(save_action, SIGNAL(triggered()), image_canvas, SLOT(saveMask())); - + tabWidget->clear(); + + connect(button_watershed , SIGNAL(released()) , this, SLOT(runWatershed() )); + connect(actionOpen_config_file, SIGNAL(triggered()) , this, SLOT(loadConfigFile())); + connect(actionSave_config_file, SIGNAL(triggered()) , this, SLOT(saveConfigFile())); + connect(close_tab_action , SIGNAL(triggered()) , this, SLOT(closeCurrentTab())); + connect(tabWidget , SIGNAL(tabCloseRequested(int)) , this, SLOT(closeTab(int) )); + connect(tabWidget , SIGNAL(currentChanged(int)) , this, SLOT(updateConnect(int))); + connect(tree_widget_img , SIGNAL(itemClicked(QTreeWidgetItem *,int)), this, SLOT(treeWidgetClicked())); + labels = defaulfLabels(); loadConfigLabels(); connect(list_label, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this, SLOT(changeLabel(QListWidgetItem*, QListWidgetItem*))); connect(list_label, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(changeColor(QListWidgetItem*))); +} - +void MainWindow::closeCurrentTab() { + int index = tabWidget->currentIndex(); + if(index>=0) + closeTab(index); } + +void MainWindow::closeTab(int index) { + ImageCanvas * ic = getImageCanvas(index); + if (ic == NULL) + throw std::logic_error("error index"); + + if (ic->isNotSaved()) { + QMessageBox::StandardButton reply = QMessageBox::question(this, "Current image is not saved", + "You will close the current image, Would you like saved image before ?", QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::Yes) { + ic->saveMask(); + } + } + + tabWidget->removeTab(index); + delete ic; + if (tabWidget->count() == 0 ) { + image_canvas = NULL; + } +} + void MainWindow::loadConfigLabels() { list_label->clear(); QMapIterator it(labels); @@ -131,11 +144,98 @@ void MainWindow::changeLabel(QListWidgetItem* current, QListWidgetItem* previous image_canvas->setId(labels[key].id); } -void MainWindow::runWatershed() { - image_canvas->setWatershedMask(watershed(image_canvas->getImage(), image_canvas->getMask().id)); +void MainWindow::runWatershed(ImageCanvas * ic) { + ic->setWatershedMask(watershed(ic->getImage(), ic->getMask().id)); checkbox_watershed_mask->setCheckState(Qt::CheckState::Checked); - //checkbox_manuel_mask->setCheckState(Qt::CheckState::Unchecked); - image_canvas->update(); + ic->update(); +} + +void MainWindow::runWatershed() { + ImageCanvas * ic = image_canvas; + if( ic != NULL) + runWatershed(ic); +} + +void MainWindow::setStarAtNameOfTab(bool star) { + if (tabWidget->count() > 0) { + int index = tabWidget->currentIndex(); + QString name = tabWidget->tabText(index); + if (star && !name.endsWith("*")) { //add star + name += "*"; + tabWidget->setTabText(index, name); + } else if (!star && name.endsWith("*")) { //remove star + int pos = name.lastIndexOf('*'); + name = name.left(pos); + tabWidget->setTabText(index, name); + } + } +} + +void MainWindow::updateConnect(const ImageCanvas * ic) { + if (ic == NULL) return; + connect(spinbox_scale, SIGNAL(valueChanged(double)), ic, SLOT(scaleChanged(double))); + connect(spinbox_alpha, SIGNAL(valueChanged(double)), ic, SLOT(alphaChanged(double))); + connect(spinbox_pen_size, SIGNAL(valueChanged(int)), ic, SLOT(setSizePen(int))); + connect(checkbox_watershed_mask, SIGNAL(clicked()), ic, SLOT(update())); + connect(checkbox_manuel_mask, SIGNAL(clicked()), ic, SLOT(update())); + connect(actionClear, SIGNAL(triggered()), ic, SLOT(clearMask())); + connect(undo_action, SIGNAL(triggered()), ic, SLOT(undo())); + connect(redo_action, SIGNAL(triggered()), ic, SLOT(redo())); + connect(save_action, SIGNAL(triggered()), ic, SLOT(saveMask())); + connect(checkbox_border_ws, SIGNAL(clicked()), ic, SLOT(update())); + +} + +void MainWindow::allDisconnnect(const ImageCanvas * ic) { + if (ic == NULL) return; + disconnect(spinbox_scale, SIGNAL(valueChanged(double)), ic, SLOT(scaleChanged(double))); + disconnect(spinbox_alpha, SIGNAL(valueChanged(double)), ic, SLOT(alphaChanged(double))); + disconnect(spinbox_pen_size, SIGNAL(valueChanged(int)), ic, SLOT(setSizePen(int))); + disconnect(checkbox_watershed_mask, SIGNAL(clicked()), ic, SLOT(update())); + disconnect(checkbox_manuel_mask, SIGNAL(clicked()), ic, SLOT(update())); + disconnect(actionClear, SIGNAL(triggered()), ic, SLOT(clearMask())); + disconnect(undo_action, SIGNAL(triggered()), ic, SLOT(undo())); + disconnect(redo_action, SIGNAL(triggered()), ic, SLOT(redo())); + disconnect(save_action, SIGNAL(triggered()), ic, SLOT(saveMask())); + disconnect(checkbox_border_ws, SIGNAL(clicked()), ic, SLOT(update())); +} + +ImageCanvas * MainWindow::newImageCanvas() { + ImageCanvas * ic = new ImageCanvas( this); + ic->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + ic->setScaledContents(true); + updateConnect(ic); + return ic; +} + +void MainWindow::updateConnect(int index) { + if (index < 0 || index >= tabWidget->count()) + return; + allDisconnnect(image_canvas); + image_canvas = getImageCanvas(index); + updateConnect(image_canvas); +} + +ImageCanvas * MainWindow::getImageCanvas(int index) { + QScrollArea * scroll_area = static_cast(tabWidget->widget(index)); + ImageCanvas * ic = static_cast(scroll_area->widget()); + return ic; +} + +int MainWindow::getImageCanvas(QString name, ImageCanvas * ic) { + for (int i = 0; i < tabWidget->count(); i++) { + if (tabWidget->tabText(i).startsWith(name) ) { + ic = getImageCanvas(i); + return i; + } + } + ic = newImageCanvas(); + QString iDir = currentDir(); + QString filepath(iDir + "/" + name); + ic->loadImage(filepath); + int index = tabWidget->addTab(ic->getScrollParent(), name); + + return index; } QString MainWindow::currentDir() const { @@ -154,14 +254,22 @@ QString MainWindow::currentFile() const { return current->text(0); } -void MainWindow::on_tree_widget_img_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) { - QString iFile = currentFile(); - QString iDir = currentDir(); - if (iFile.isEmpty() || iDir.isEmpty()) - return; - QString filepath(iDir + "/" + iFile); - image_canvas->loadImage(filepath); + +void MainWindow::treeWidgetClicked() { + QString iFile = currentFile(); + QString iDir = currentDir(); + if (iFile.isEmpty() || iDir.isEmpty()) + return; + allDisconnnect(image_canvas); + int index = getImageCanvas(iFile, image_canvas); + updateConnect(image_canvas); + tabWidget->setCurrentIndex(index); + +} + +void MainWindow::on_tree_widget_img_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) { + treeWidgetClicked(); } void MainWindow::on_actionOpenDir_triggered() { diff --git a/src/main_window.h b/src/main_window.h index e1f4a71..e354ec8 100644 --- a/src/main_window.h +++ b/src/main_window.h @@ -30,21 +30,31 @@ class MainWindow : public QMainWindow, public Ui::MainWindow { MainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0); private: - ImageCanvas * image_canvas; + void loadConfigLabels(); + ImageCanvas * newImageCanvas(); + int getImageCanvas(QString name, ImageCanvas *ic) ; + ImageCanvas * getImageCanvas(int index); public: + ImageCanvas * image_canvas ; + //std::vector _image_canvas; + //QScrollArea * scroll_area ; - QScrollArea * scroll_area ; Name2Labels labels ; Id2Labels id_labels ; QAction * save_action ; + QAction * close_tab_action; QAction * undo_action ; QAction * redo_action ; QString curr_open_dir; public: QString currentDir() const; QString currentFile() const; + void updateConnect(const ImageCanvas * ic); + void allDisconnnect(const ImageCanvas * ic); + void runWatershed(ImageCanvas * ic); + void setStarAtNameOfTab(bool star); public slots: @@ -55,8 +65,12 @@ public slots: void runWatershed(); void on_tree_widget_img_currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *); void on_actionOpenDir_triggered(); + //void on_actionOpen_jsq_triggered(); void on_actionAbout_triggered(); - + void closeTab(int index); + void closeCurrentTab(); + void updateConnect(int index); + void treeWidgetClicked(); }; #endif diff --git a/src/main_window.ui b/src/main_window.ui index 16a6247..ddecd81 100644 --- a/src/main_window.ui +++ b/src/main_window.ui @@ -6,20 +6,88 @@ 0 0 - 1524 - 786 + 1511 + 967 PixelAnnotationTool - + + Qt::ToolButtonIconOnly + + + true + + + true + + + true + + + QMainWindow::AllowNestedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks|QMainWindow::ForceTabbedDocks|QMainWindow::GroupedDragging|QMainWindow::VerticalTabs + + + + + 2 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + QTabWidget::Triangular + + + 0 + + + Qt::ElideLeft + + + false + + + false + + + true + + + true + + + + Tab 1 + + + + + Tab 2 + + + + + + 0 0 - 1524 + 1511 21 @@ -65,6 +133,21 @@ + + 2 + + + 2 + + + 2 + + + 2 + + + 2 + @@ -145,6 +228,13 @@ + + + + keep border provide by the watershed + + + @@ -183,6 +273,21 @@ + + 2 + + + 2 + + + 2 + + + 2 + + + 2 + @@ -251,6 +356,11 @@ About + + + Open JSQ + +