From 226d24d2fa70fef91486ad38d126a2dcdfc49649 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Wed, 29 Jan 2020 09:57:48 -0300 Subject: [PATCH 01/29] WIP - read json files --- src/ui/annotatorwidget.cpp | 12 ++++++++ src/ui/annotatorwidget.h | 3 ++ src/ui/mark.cpp | 39 +++++++++++++++++++++++-- src/ui/mark.h | 2 ++ src/ui/serializer.cpp | 58 +++++++++++++++++++++++++++++++++++++- src/ui/serializer.h | 4 +++ 6 files changed, 115 insertions(+), 3 deletions(-) diff --git a/src/ui/annotatorwidget.cpp b/src/ui/annotatorwidget.cpp index 5916b83..10cfe7c 100644 --- a/src/ui/annotatorwidget.cpp +++ b/src/ui/annotatorwidget.cpp @@ -223,3 +223,15 @@ void AnnotatorWidget::clearScene() { m_ui->graphicsView->scene()->clear(); } +/* +void AnnotatorWidget::readPolygonsFromXml(const QByteArray& data) +{ + m_savedPolygons = Serializer::readXML(data, m_currentImage->pos()); + repaint(); +} +*/ +void AnnotatorWidget::readPolygonsFromJson(const QByteArray& data) +{ + m_savedPolygons = Serializer::readJSON(data, m_currentImage->pos()); + repaint(); +} diff --git a/src/ui/annotatorwidget.h b/src/ui/annotatorwidget.h index 8619efe..4c2273c 100644 --- a/src/ui/annotatorwidget.h +++ b/src/ui/annotatorwidget.h @@ -20,6 +20,7 @@ #include "ui/mark.h" #include "image/polygon.h" +#include "ui/serializer.h" #include #include @@ -39,6 +40,8 @@ public: public: QVector savedPolygons() const; + void readPolygonsFromJson(const QByteArray& data); + //void readPolygonsFromXml(const QByteArray& data); void mousePressEvent(QMouseEvent* event) override; diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 48f84e1..b63f5e8 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -34,8 +34,6 @@ #include #include -#include - marK::marK(QWidget *parent) : QMainWindow(parent), m_ui(new Ui::marK), @@ -58,6 +56,10 @@ marK::marK(QWidget *parent) : QAction *toJson = exportMenu->addAction("JSON"); connect(toJson, &QAction::triggered, this, &marK::saveToJson); + QAction *importData = fileMenu->addAction("Import"); + importData->setShortcut(QKeySequence(Qt::Modifier::CTRL + Qt::Key::Key_I)); + connect(importData, &QAction::triggered, this, &marK::importData); + QMenu *editMenu = m_ui->menuBar->addMenu("Edit"); QAction *undoAction = editMenu->addAction("Undo"); @@ -247,4 +249,37 @@ void marK::savePolygons(OutputType type) } } +void marK::importData() +{ + QString filepath = QFileDialog::getOpenFileName(this, "Select File", QDir::homePath(), + "JSON files (*.json)");// add later "XML files (*.xml)" + + QByteArray data = Serializer::getData(filepath); + + if (filepath.endsWith(".json")) + m_ui->annotatorWidget->readPolygonsFromJson(data); + + //else if (filepath.endsWith(".xml")) + //m_ui->annotatorWidget->readPolygonsFromXml(data); + + for (const auto& polygon : m_ui->annotatorWidget->savedPolygons()) + addClass(polygon.polygonClass()); + + // TODO: warning if failed +} + +void marK::addClass(MarkedClass* markedClass) +{ + int classQt = m_polygonClasses.size(); + m_polygonClasses << markedClass; + + QPixmap colorPix(70, 45); + colorPix.fill(markedClass->color()); + + m_ui->comboBox->addItem(QIcon(colorPix), markedClass->name()); + m_ui->comboBox->setCurrentIndex(classQt); + + m_ui->annotatorWidget->setCurrentPolygonClass(markedClass); +} + marK::~marK() = default; diff --git a/src/ui/mark.h b/src/ui/mark.h index 08c7d69..291500f 100644 --- a/src/ui/mark.h +++ b/src/ui/mark.h @@ -54,6 +54,7 @@ public: void changeShape(marK::Shape shape); void updateFiles(); void savePolygons(OutputType type); + void addClass(MarkedClass* markedClass); public slots: void changeItem(QListWidgetItem *current, QListWidgetItem *previous); @@ -62,6 +63,7 @@ public slots: void selectClassColor(); void saveToJson() { savePolygons(OutputType::JSON); }; void saveToXml() { savePolygons(OutputType::XML); }; + void importData(); private: QScopedPointer m_ui; diff --git a/src/ui/serializer.cpp b/src/ui/serializer.cpp index e969489..f72348e 100644 --- a/src/ui/serializer.cpp +++ b/src/ui/serializer.cpp @@ -16,13 +16,15 @@ *************************************************************************/ #include "serializer.h" +#include "markedclass.h" #include -#include #include #include #include #include +#include +#include QString Serializer::toXML(const QVector& annotatedPolygons) { @@ -109,3 +111,57 @@ QString Serializer::toJSON(const QVector& annotatedPolygons) return doc.toJson(); } + +QVector Serializer::readJSON(const QByteArray& data, const QPointF& offset) +{ + QJsonParseError errorptr; + QJsonDocument doc = QJsonDocument::fromJson(data, &errorptr); + if (doc.isNull()) { + qDebug() << errorptr.errorString(); + } + + QJsonArray polygonArray = doc.array(); + QVector savedPolygons; + + for (const auto& classObj : polygonArray) + { + Polygon polygon; + MarkedClass polygonClass(classObj.toObject().value("Class").toString()); + + polygon.setPolygonClass(&polygonClass); + QJsonArray polygonArray = classObj.toObject().value("Polygon").toArray(); + + for (const auto& polygonObj : polygonArray) + { + auto ptObj = polygonObj.toObject().value("pt").toObject(); + + double x = ptObj.value("x").toString().toDouble(); + double y = ptObj.value("y").toString().toDouble(); + + polygon.append(QPointF(x,y) + offset); + } + + savedPolygons.append(polygon); + } + + return savedPolygons; +} +/* +QVector Serializer::readXML(const QByteArray& data, const QPointF& offset) +{ + QVector savedPolygons; + return savedPolygons; +} +*/ +QByteArray Serializer::getData(const QString& filepath) +{ + QString filename(filepath); + filename.replace(QRegularExpression(".jpg|.png|.xpm"), ".json"); + + QFile file(filename); + file.open(QIODevice::ReadOnly|QIODevice::Text); + QByteArray data = file.readAll(); + file.close(); + + return data; +} diff --git a/src/ui/serializer.h b/src/ui/serializer.h index ce95668..a54a937 100644 --- a/src/ui/serializer.h +++ b/src/ui/serializer.h @@ -22,11 +22,15 @@ #include #include +#include class Serializer { public: static QString toJSON(const QVector& annotatedPolygons); static QString toXML(const QVector& annotatedPolygons); + static QVector readJSON(const QByteArray& data, const QPointF& offset); + //static QVector readXML(const QByteArray& data, const QPointF& offset); + static QByteArray getData(const QString& filepath); }; #endif // SERIALIZER_H -- GitLab From 4104a291629444c6005bfba16e4817be8d727f0e Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Wed, 29 Jan 2020 10:14:49 -0300 Subject: [PATCH 02/29] move position of importAction --- src/ui/mark.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index b63f5e8..219f22c 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -48,6 +48,10 @@ marK::marK(QWidget *parent) : openDirAction->setShortcut(QKeySequence(Qt::Modifier::CTRL + Qt::Key::Key_O)); connect(openDirAction, &QAction::triggered, this, &marK::changeDirectory); + QAction *importData = fileMenu->addAction("Import"); + importData->setShortcut(QKeySequence(Qt::Modifier::CTRL + Qt::Key::Key_I)); + connect(importData, &QAction::triggered, this, &marK::importData); + QMenu *exportMenu = fileMenu->addMenu("Export"); QAction *toXML = exportMenu->addAction("XML"); @@ -56,10 +60,6 @@ marK::marK(QWidget *parent) : QAction *toJson = exportMenu->addAction("JSON"); connect(toJson, &QAction::triggered, this, &marK::saveToJson); - QAction *importData = fileMenu->addAction("Import"); - importData->setShortcut(QKeySequence(Qt::Modifier::CTRL + Qt::Key::Key_I)); - connect(importData, &QAction::triggered, this, &marK::importData); - QMenu *editMenu = m_ui->menuBar->addMenu("Edit"); QAction *undoAction = editMenu->addAction("Undo"); @@ -254,6 +254,7 @@ void marK::importData() QString filepath = QFileDialog::getOpenFileName(this, "Select File", QDir::homePath(), "JSON files (*.json)");// add later "XML files (*.xml)" + // TODO: fix crash when there is no image loaded QByteArray data = Serializer::getData(filepath); if (filepath.endsWith(".json")) @@ -261,10 +262,10 @@ void marK::importData() //else if (filepath.endsWith(".xml")) //m_ui->annotatorWidget->readPolygonsFromXml(data); - +/* TODO: addClass to each of polygons for (const auto& polygon : m_ui->annotatorWidget->savedPolygons()) addClass(polygon.polygonClass()); - +*/ // TODO: warning if failed } -- GitLab From 27507013f1c99ab7bf02f2c5347b8314187263d5 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Sat, 1 Feb 2020 08:00:08 -0300 Subject: [PATCH 03/29] WIP - change class Serializer to not be static --- src/ui/annotatorwidget.cpp | 12 ++----- src/ui/annotatorwidget.h | 3 +- src/ui/mark.cpp | 17 +++++----- src/ui/mark.h | 2 +- src/ui/serializer.cpp | 68 ++++++++++++++++++++++++++++---------- src/ui/serializer.h | 22 +++++++++--- 6 files changed, 82 insertions(+), 42 deletions(-) diff --git a/src/ui/annotatorwidget.cpp b/src/ui/annotatorwidget.cpp index 10cfe7c..393c372 100644 --- a/src/ui/annotatorwidget.cpp +++ b/src/ui/annotatorwidget.cpp @@ -223,15 +223,9 @@ void AnnotatorWidget::clearScene() { m_ui->graphicsView->scene()->clear(); } -/* -void AnnotatorWidget::readPolygonsFromXml(const QByteArray& data) -{ - m_savedPolygons = Serializer::readXML(data, m_currentImage->pos()); - repaint(); -} -*/ -void AnnotatorWidget::readPolygonsFromJson(const QByteArray& data) + +void AnnotatorWidget::setPolygons(QVector polygons) { - m_savedPolygons = Serializer::readJSON(data, m_currentImage->pos()); + m_savedPolygons = polygons; repaint(); } diff --git a/src/ui/annotatorwidget.h b/src/ui/annotatorwidget.h index 4c2273c..6ad92e5 100644 --- a/src/ui/annotatorwidget.h +++ b/src/ui/annotatorwidget.h @@ -40,8 +40,7 @@ public: public: QVector savedPolygons() const; - void readPolygonsFromJson(const QByteArray& data); - //void readPolygonsFromXml(const QByteArray& data); + void setPolygons(QVector polygons); void mousePressEvent(QMouseEvent* event) override; diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 219f22c..0eadbff 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -77,7 +77,7 @@ marK::marK(QWidget *parent) : connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, static_cast(&marK::updateFiles)); - connect(m_ui->newClassButton, &QPushButton::clicked, this, &marK::addNewClass); + connect(m_ui->newClassButton, &QPushButton::clicked, this, qOverload<>(&marK::addNewClass)); connect(m_ui->undoButton, &QPushButton::clicked, m_ui->annotatorWidget, &AnnotatorWidget::undo); connect(m_ui->resetButton, &QPushButton::clicked, m_ui->annotatorWidget, &AnnotatorWidget::reset); @@ -227,11 +227,12 @@ void marK::selectClassColor() void marK::savePolygons(OutputType type) { QString document; + Serializer serialize(m_ui->annotatorWidget->savedPolygons()); if (type == OutputType::XML) - document = Serializer::toXML(m_ui->annotatorWidget->savedPolygons()); + document = serialize.serialize(OutputType::XML); else if (type == OutputType::JSON) - document = Serializer::toJSON(m_ui->annotatorWidget->savedPolygons()); + document = serialize.serialize(OutputType::JSON); if (!document.isEmpty()) { @@ -255,21 +256,21 @@ void marK::importData() "JSON files (*.json)");// add later "XML files (*.xml)" // TODO: fix crash when there is no image loaded - QByteArray data = Serializer::getData(filepath); + Serializer serializer(filepath); if (filepath.endsWith(".json")) - m_ui->annotatorWidget->readPolygonsFromJson(data); + m_ui->annotatorWidget->setPolygons(serializer.read(OutputType::JSON)); //else if (filepath.endsWith(".xml")) //m_ui->annotatorWidget->readPolygonsFromXml(data); -/* TODO: addClass to each of polygons +/* for (const auto& polygon : m_ui->annotatorWidget->savedPolygons()) - addClass(polygon.polygonClass()); + addNewClass(polygon.polygonClass()); */ // TODO: warning if failed } -void marK::addClass(MarkedClass* markedClass) +void marK::addNewClass(MarkedClass* markedClass) { int classQt = m_polygonClasses.size(); m_polygonClasses << markedClass; diff --git a/src/ui/mark.h b/src/ui/mark.h index 291500f..6d1f8fe 100644 --- a/src/ui/mark.h +++ b/src/ui/mark.h @@ -54,7 +54,7 @@ public: void changeShape(marK::Shape shape); void updateFiles(); void savePolygons(OutputType type); - void addClass(MarkedClass* markedClass); + void addNewClass(MarkedClass* markedClass); public slots: void changeItem(QListWidgetItem *current, QListWidgetItem *previous); diff --git a/src/ui/serializer.cpp b/src/ui/serializer.cpp index f72348e..487dcf5 100644 --- a/src/ui/serializer.cpp +++ b/src/ui/serializer.cpp @@ -25,10 +25,43 @@ #include #include #include +Serializer::Serializer(const QString& filepath) : + m_filepath(filepath) +{ +} + +Serializer::Serializer(const QVector items) : + m_items(items) +{ +} -QString Serializer::toXML(const QVector& annotatedPolygons) +QVector Serializer::read(marK::OutputType output_type) { - if (annotatedPolygons.isEmpty()) + QVector objects; + + if(output_type == marK::OutputType::XML) + objects = this->readXML(); + + else if (output_type == marK::OutputType::JSON) + objects = this->readJSON(); + + return objects; +} + +QString Serializer::serialize(marK::OutputType output_type) +{ + if (output_type == marK::OutputType::XML) + return this->toXML(); + + else if (output_type == marK::OutputType::JSON) + return this->toJSON(); + + return nullptr; +} + +QString Serializer::toXML() +{ + if (m_items.isEmpty()) return nullptr; QString xmldoc; @@ -38,7 +71,7 @@ QString Serializer::toXML(const QVector& annotatedPolygons) xmlWriter.writeStartElement("annotation"); - for (const Polygon& item : annotatedPolygons) { + for (const Polygon& item : m_items) { xmlWriter.writeStartElement("object"); xmlWriter.writeStartElement("class"); @@ -77,14 +110,14 @@ QString Serializer::toXML(const QVector& annotatedPolygons) return xmldoc; } -QString Serializer::toJSON(const QVector& annotatedPolygons) +QString Serializer::toJSON() { - if(annotatedPolygons.isEmpty()) + if(m_items.isEmpty()) return nullptr; QJsonArray classesArray; - for (const Polygon& item : annotatedPolygons) { + for (const Polygon& item : m_items) { QJsonObject recordObject; recordObject.insert("Class", item.polygonClass()->name()); @@ -112,8 +145,10 @@ QString Serializer::toJSON(const QVector& annotatedPolygons) return doc.toJson(); } -QVector Serializer::readJSON(const QByteArray& data, const QPointF& offset) +QVector Serializer::readJSON() { + QByteArray data = getData(); + QJsonParseError errorptr; QJsonDocument doc = QJsonDocument::fromJson(data, &errorptr); if (doc.isNull()) { @@ -123,7 +158,7 @@ QVector Serializer::readJSON(const QByteArray& data, const QPointF& off QJsonArray polygonArray = doc.array(); QVector savedPolygons; - for (const auto& classObj : polygonArray) + for (const QJsonValue& classObj : polygonArray) { Polygon polygon; MarkedClass polygonClass(classObj.toObject().value("Class").toString()); @@ -131,14 +166,14 @@ QVector Serializer::readJSON(const QByteArray& data, const QPointF& off polygon.setPolygonClass(&polygonClass); QJsonArray polygonArray = classObj.toObject().value("Polygon").toArray(); - for (const auto& polygonObj : polygonArray) + for (const QJsonValue& polygonObj : polygonArray) { auto ptObj = polygonObj.toObject().value("pt").toObject(); double x = ptObj.value("x").toString().toDouble(); double y = ptObj.value("y").toString().toDouble(); - polygon.append(QPointF(x,y) + offset); + polygon.append(QPointF(x,y)); } savedPolygons.append(polygon); @@ -146,19 +181,18 @@ QVector Serializer::readJSON(const QByteArray& data, const QPointF& off return savedPolygons; } -/* -QVector Serializer::readXML(const QByteArray& data, const QPointF& offset) + +QVector Serializer::readXML() { QVector savedPolygons; return savedPolygons; } -*/ -QByteArray Serializer::getData(const QString& filepath) + +QByteArray Serializer::getData() { - QString filename(filepath); - filename.replace(QRegularExpression(".jpg|.png|.xpm"), ".json"); + m_filepath.replace(QRegularExpression(".jpg|.png|.xpm"), ".json"); - QFile file(filename); + QFile file(m_filepath); file.open(QIODevice::ReadOnly|QIODevice::Text); QByteArray data = file.readAll(); file.close(); diff --git a/src/ui/serializer.h b/src/ui/serializer.h index a54a937..46dd5c5 100644 --- a/src/ui/serializer.h +++ b/src/ui/serializer.h @@ -19,6 +19,7 @@ #define SERIALIZER_H #include "image/polygon.h" +#include "mark.h" #include #include @@ -27,10 +28,21 @@ class Serializer { public: - static QString toJSON(const QVector& annotatedPolygons); - static QString toXML(const QVector& annotatedPolygons); - static QVector readJSON(const QByteArray& data, const QPointF& offset); - //static QVector readXML(const QByteArray& data, const QPointF& offset); - static QByteArray getData(const QString& filepath); + explicit Serializer(const QString& filepath); + explicit Serializer(const QVector items); + QString serialize(marK::OutputType output_type); + QVector read(marK::OutputType output_type); + +private: + QByteArray getData(); + QString toJSON(); + QString toXML(); + QVector readJSON(); + QVector readXML(); + +private: + // put it to work with MarkedObject + QVector m_items; + QString m_filepath; }; #endif // SERIALIZER_H -- GitLab From d0983d2ac5a5fa88d8f722de3283eb7c8e845e95 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Sat, 1 Feb 2020 15:36:10 -0300 Subject: [PATCH 04/29] WIP - support to read xml files --- src/ui/mark.cpp | 6 ++--- src/ui/serializer.cpp | 52 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 0eadbff..e830791 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -253,7 +253,7 @@ void marK::savePolygons(OutputType type) void marK::importData() { QString filepath = QFileDialog::getOpenFileName(this, "Select File", QDir::homePath(), - "JSON files (*.json)");// add later "XML files (*.xml)" + "JSON and XML files (*.json *.xml)");// add later "" // TODO: fix crash when there is no image loaded Serializer serializer(filepath); @@ -261,8 +261,8 @@ void marK::importData() if (filepath.endsWith(".json")) m_ui->annotatorWidget->setPolygons(serializer.read(OutputType::JSON)); - //else if (filepath.endsWith(".xml")) - //m_ui->annotatorWidget->readPolygonsFromXml(data); + else if (filepath.endsWith(".xml")) + m_ui->annotatorWidget->setPolygons(serializer.read(OutputType::XML)); /* for (const auto& polygon : m_ui->annotatorWidget->savedPolygons()) addNewClass(polygon.polygonClass()); diff --git a/src/ui/serializer.cpp b/src/ui/serializer.cpp index 487dcf5..0fba9a4 100644 --- a/src/ui/serializer.cpp +++ b/src/ui/serializer.cpp @@ -184,8 +184,56 @@ QVector Serializer::readJSON() QVector Serializer::readXML() { - QVector savedPolygons; - return savedPolygons; + QVector savedObjects; + QByteArray data = getData(); + + QXmlStreamReader xmlReader(data); + xmlReader.readNextStartElement(); // going to first element + + while (!xmlReader.atEnd()) + { + QXmlStreamReader::TokenType token = xmlReader.readNext(); + if (token == QXmlStreamReader::StartElement) + { + Polygon object; + xmlReader.readNextStartElement(); + + if (xmlReader.name() == "class") + { + MarkedClass markedClass(xmlReader.readElementText()); + object.setPolygonClass(&markedClass); + } + + xmlReader.readNextStartElement(); // closing "class" and going to "polygon" + if (xmlReader.name() == "polygon") + { + xmlReader.readNextStartElement(); // going to "pt" + + while (xmlReader.name() == "pt") + { + xmlReader.readNextStartElement(); // going to "x" value + + double x = xmlReader.readElementText().toDouble(); + + xmlReader.readNextStartElement(); // closing "x" value and going to "y" value + + double y = xmlReader.readElementText().toDouble(); + + object.append(QPointF(x, y)); + + xmlReader.readNextStartElement(); // closing "y" value + + xmlReader.readNextStartElement(); // closing "pt" value + } + } + savedObjects.append(object); + } + } + + if(xmlReader.hasError()) + qDebug() << xmlReader.error(); + + return savedObjects; } QByteArray Serializer::getData() -- GitLab From 463f7610c7ac050dc458cacd1a1464e723347c41 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Sun, 2 Feb 2020 20:02:28 -0300 Subject: [PATCH 05/29] use offset to get the right position of polygons --- src/ui/annotatorwidget.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ui/annotatorwidget.cpp b/src/ui/annotatorwidget.cpp index 393c372..9c86ac0 100644 --- a/src/ui/annotatorwidget.cpp +++ b/src/ui/annotatorwidget.cpp @@ -183,11 +183,8 @@ void AnnotatorWidget::reset() void AnnotatorWidget::changeItem(QString itemPath) { - // TODO: create a temp file where the polygons from this image will be temporary stored, so they can be loaded again when - // the image is reopened - m_savedPolygons.clear(); m_items.clear(); - m_currentPolygon.clear(); + reset(); QGraphicsScene *scene = m_ui->graphicsView->scene(); scene->setSceneRect(0, 0, 850, 640); @@ -226,6 +223,11 @@ void AnnotatorWidget::clearScene() void AnnotatorWidget::setPolygons(QVector polygons) { + QPointF offset = m_currentImage->pos(); + for (Polygon& polygon : polygons) + for (QPointF& point : polygon) + point += offset; + m_savedPolygons = polygons; repaint(); } -- GitLab From c38d9b0b3ff9597996b14c41ef6aceb9260d6c01 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Sun, 2 Feb 2020 20:07:27 -0300 Subject: [PATCH 06/29] fix bug on read of a MarkedClass and better readability --- src/ui/serializer.cpp | 16 +++++++++------- src/ui/serializer.h | 1 + 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/ui/serializer.cpp b/src/ui/serializer.cpp index 0fba9a4..fcf90bf 100644 --- a/src/ui/serializer.cpp +++ b/src/ui/serializer.cpp @@ -25,6 +25,7 @@ #include #include #include + Serializer::Serializer(const QString& filepath) : m_filepath(filepath) { @@ -38,6 +39,7 @@ Serializer::Serializer(const QVector items) : QVector Serializer::read(marK::OutputType output_type) { QVector objects; + m_output_type = output_type; if(output_type == marK::OutputType::XML) objects = this->readXML(); @@ -161,14 +163,14 @@ QVector Serializer::readJSON() for (const QJsonValue& classObj : polygonArray) { Polygon polygon; - MarkedClass polygonClass(classObj.toObject().value("Class").toString()); + auto polygonClass = new MarkedClass(classObj["Class"].toString()); - polygon.setPolygonClass(&polygonClass); - QJsonArray polygonArray = classObj.toObject().value("Polygon").toArray(); + polygon.setPolygonClass(polygonClass); + QJsonArray polygonArray = classObj["Polygon"].toArray(); for (const QJsonValue& polygonObj : polygonArray) { - auto ptObj = polygonObj.toObject().value("pt").toObject(); + QJsonObject ptObj = polygonObj["pt"].toObject(); double x = ptObj.value("x").toString().toDouble(); double y = ptObj.value("y").toString().toDouble(); @@ -200,8 +202,8 @@ QVector Serializer::readXML() if (xmlReader.name() == "class") { - MarkedClass markedClass(xmlReader.readElementText()); - object.setPolygonClass(&markedClass); + auto markedClass = new MarkedClass(xmlReader.readElementText()); + object.setPolygonClass(markedClass); } xmlReader.readNextStartElement(); // closing "class" and going to "polygon" @@ -238,7 +240,7 @@ QVector Serializer::readXML() QByteArray Serializer::getData() { - m_filepath.replace(QRegularExpression(".jpg|.png|.xpm"), ".json"); + m_filepath.replace(QRegularExpression(".jpg|.png|.xpm"), (m_output_type == marK::OutputType::XML ? ".xml" : ".json")); QFile file(m_filepath); file.open(QIODevice::ReadOnly|QIODevice::Text); diff --git a/src/ui/serializer.h b/src/ui/serializer.h index 46dd5c5..51356e7 100644 --- a/src/ui/serializer.h +++ b/src/ui/serializer.h @@ -44,5 +44,6 @@ private: // put it to work with MarkedObject QVector m_items; QString m_filepath; + marK::OutputType m_output_type; }; #endif // SERIALIZER_H -- GitLab From 8815f226bfba5efe7770f9ca3912f88c7fbb4958 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Sun, 2 Feb 2020 20:09:00 -0300 Subject: [PATCH 07/29] add support to temporary files --- src/ui/mark.cpp | 74 ++++++++++++++++++++++++++++++++++++++++++++----- src/ui/mark.h | 3 ++ 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index e830791..fc56a8f 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -161,8 +161,10 @@ void marK::changeItem(QListWidgetItem *current, QListWidgetItem *previous) QString itemPath = QDir(m_currentDirectory).filePath(current->text()); if (itemPath != m_filepath) { + makeTempFile(); m_filepath = itemPath; m_ui->annotatorWidget->changeItem(itemPath); + retrieveTempFile(itemPath); } } } @@ -257,16 +259,20 @@ void marK::importData() // TODO: fix crash when there is no image loaded Serializer serializer(filepath); + QVector objects; if (filepath.endsWith(".json")) - m_ui->annotatorWidget->setPolygons(serializer.read(OutputType::JSON)); + objects = serializer.read(OutputType::JSON); else if (filepath.endsWith(".xml")) - m_ui->annotatorWidget->setPolygons(serializer.read(OutputType::XML)); -/* - for (const auto& polygon : m_ui->annotatorWidget->savedPolygons()) - addNewClass(polygon.polygonClass()); -*/ + objects = serializer.read(OutputType::XML); + + m_ui->annotatorWidget->setPolygons(objects); + + // add new classes to comboBox + for (const auto& object : objects) + addNewClass(object.polygonClass()); + // TODO: warning if failed } @@ -284,4 +290,58 @@ void marK::addNewClass(MarkedClass* markedClass) m_ui->annotatorWidget->setCurrentPolygonClass(markedClass); } -marK::~marK() = default; +void marK::makeTempFile() +{ + QDir tempDir(QDir::tempPath()); + + QString tempFilename(m_filepath); + tempFilename.replace("/", "_"); + tempFilename.replace(QRegularExpression(".jpg|.png|.xpm"), ".json"); + tempFilename.prepend(QDir::tempPath() + "/mark"); + + QVector objects = m_ui->annotatorWidget->savedPolygons(); + if (!objects.isEmpty()) + { + QFile tempFile(tempFilename); + tempFile.open(QIODevice::WriteOnly|QIODevice::Text); + + Serializer serializer(m_ui->annotatorWidget->savedPolygons()); + QString document = serializer.serialize(OutputType::JSON); // writing in JSON + tempFile.write(document.toUtf8()); + tempFile.close(); + + m_tempFiles.append(tempFilename); + } +} + +void marK::retrieveTempFile(const QString& itempath) +{ + QDir tempDir(QDir::tempPath()); + + QString savedTempFile(itempath); + savedTempFile.replace("/", "_"); + savedTempFile.replace(QRegularExpression(".jpg|.png|.xpm"), ".json"); + savedTempFile.prepend(QDir::tempPath() + "/mark"); + + if (tempDir.exists(savedTempFile)) + { + Serializer serializer(savedTempFile); + + QVector objects = serializer.read(OutputType::JSON); // reading in JSON + m_ui->annotatorWidget->setPolygons(objects); + + //adding the new classes to comboBox + for (const auto& object : objects) + addNewClass(object.polygonClass()); + } +} + +marK::~marK() +{ + // cleaning temp files + for (const QString& filename : m_tempFiles) + { + QFile tempfile(filename); + tempfile.remove(); + } +} diff --git a/src/ui/mark.h b/src/ui/mark.h index 6d1f8fe..7601b47 100644 --- a/src/ui/mark.h +++ b/src/ui/mark.h @@ -55,6 +55,8 @@ public: void updateFiles(); void savePolygons(OutputType type); void addNewClass(MarkedClass* markedClass); + void makeTempFile(); + void retrieveTempFile(const QString& itempath); public slots: void changeItem(QListWidgetItem *current, QListWidgetItem *previous); @@ -71,6 +73,7 @@ private: QString m_currentDirectory; QString m_filepath; QVector m_polygonClasses; + QVector m_tempFiles; }; #endif // MARK_H -- GitLab From 9c2cf1284a4ffc3009a7f8036a846f7631c34e0f Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Mon, 3 Feb 2020 10:49:28 -0300 Subject: [PATCH 08/29] warning if failed to load the file --- src/ui/mark.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index fc56a8f..a7ab934 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -33,6 +33,7 @@ #include #include #include +#include marK::marK(QWidget *parent) : QMainWindow(parent), @@ -255,7 +256,7 @@ void marK::savePolygons(OutputType type) void marK::importData() { QString filepath = QFileDialog::getOpenFileName(this, "Select File", QDir::homePath(), - "JSON and XML files (*.json *.xml)");// add later "" + "JSON and XML files (*.json *.xml)"); // TODO: fix crash when there is no image loaded Serializer serializer(filepath); @@ -267,13 +268,21 @@ void marK::importData() else if (filepath.endsWith(".xml")) objects = serializer.read(OutputType::XML); + if (objects.empty()) + { + QMessageBox msgBox; + msgBox.setText("failed to load annotation"); + msgBox.setIcon(QMessageBox::Warning); + msgBox.exec(); + return; + } + m_ui->annotatorWidget->setPolygons(objects); // add new classes to comboBox for (const auto& object : objects) addNewClass(object.polygonClass()); - // TODO: warning if failed } void marK::addNewClass(MarkedClass* markedClass) -- GitLab From b57be645913621e8502469f250a3b9cf614b5d3b Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Wed, 5 Feb 2020 16:30:22 -0300 Subject: [PATCH 09/29] supporting import and export of annotation in images equal or bigger than 1280 X 960 --- src/ui/annotatorwidget.cpp | 18 ++++++++++++++++++ src/ui/annotatorwidget.h | 3 +-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/ui/annotatorwidget.cpp b/src/ui/annotatorwidget.cpp index 9c86ac0..b3187ef 100644 --- a/src/ui/annotatorwidget.cpp +++ b/src/ui/annotatorwidget.cpp @@ -195,6 +195,7 @@ void AnnotatorWidget::changeItem(QString itemPath) if (image.height() >= 1280) scaledImage = image.scaledToHeight(int(1280 * 0.8)); + if (image.width() >= 960) scaledImage = image.scaledToWidth(int(960 * 0.8)); @@ -203,6 +204,11 @@ void AnnotatorWidget::changeItem(QString itemPath) m_scaleH = qreal(scaledImage.height()) / qreal(image.height()); image = scaledImage; } + else + { + m_scaleW = 1.0; + m_scaleH = 1.0; + } QGraphicsPixmapItem *pixmapItem = scene->addPixmap(image); @@ -225,9 +231,21 @@ void AnnotatorWidget::setPolygons(QVector polygons) { QPointF offset = m_currentImage->pos(); for (Polygon& polygon : polygons) + { for (QPointF& point : polygon) + { + point = QPointF(point.x() * m_scaleW, point.y() * m_scaleH); point += offset; + } + } m_savedPolygons = polygons; repaint(); } + +QPointF AnnotatorWidget::scaledPoint(const QPointF& point) const +{ + qreal scaledX = point.x() / m_scaleW; + qreal scaledY = point.y() / m_scaleH; + return QPointF(scaledX, scaledY); +} diff --git a/src/ui/annotatorwidget.h b/src/ui/annotatorwidget.h index 6ad92e5..b5cf155 100644 --- a/src/ui/annotatorwidget.h +++ b/src/ui/annotatorwidget.h @@ -53,8 +53,7 @@ public: void setCurrentPolygonClass(MarkedClass* polygonClass) { m_currentPolygon.setPolygonClass(polygonClass); repaint(); } void setShape(marK::Shape shape) { m_shape = shape; m_currentPolygon.clear(); repaint(); } - // TODO: scale a point - QPointF scaledPoint(const QPointF& point) const { return QPointF(point.x(), point.y()); } + QPointF scaledPoint(const QPointF& point) const; public slots: void undo(); -- GitLab From 20e4985132fdfe6eea25807e79e3c83c61439d30 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Wed, 5 Feb 2020 17:44:28 -0300 Subject: [PATCH 10/29] style --- src/image/polygon.cpp | 2 +- src/image/polygon.h | 8 +++--- src/ui/annotatorwidget.cpp | 40 +++++++++++++++------------- src/ui/mark.cpp | 54 +++++++++++++++++++++----------------- src/ui/serializer.cpp | 52 ++++++++++++++++++------------------ 5 files changed, 82 insertions(+), 74 deletions(-) diff --git a/src/image/polygon.cpp b/src/image/polygon.cpp index c92c3b7..997b4ac 100644 --- a/src/image/polygon.cpp +++ b/src/image/polygon.cpp @@ -17,7 +17,7 @@ #include "polygon.h" -Polygon::Polygon(MarkedClass* polygonClass) : +Polygon::Polygon(MarkedClass *polygonClass) : m_polygonClass(polygonClass) { } diff --git a/src/image/polygon.h b/src/image/polygon.h index 06d43f5..4521765 100644 --- a/src/image/polygon.h +++ b/src/image/polygon.h @@ -28,13 +28,13 @@ class QGraphicsItem; class Polygon : public MarkedObject, public QPolygonF { public: - Polygon(MarkedClass* polygonClass = nullptr); + Polygon(MarkedClass *polygonClass = nullptr); - MarkedClass* polygonClass() const { return m_polygonClass; } - void setPolygonClass(MarkedClass* polygonClass) { m_polygonClass = polygonClass; } + MarkedClass *polygonClass() const { return m_polygonClass; } + void setPolygonClass(MarkedClass *polygonClass) { m_polygonClass = polygonClass; } private: - MarkedClass* m_polygonClass; + MarkedClass *m_polygonClass; }; #endif // POLYGON_H diff --git a/src/ui/annotatorwidget.cpp b/src/ui/annotatorwidget.cpp index b3187ef..9ec3649 100644 --- a/src/ui/annotatorwidget.cpp +++ b/src/ui/annotatorwidget.cpp @@ -53,8 +53,8 @@ QVector AnnotatorWidget::savedPolygons() const { QVector copyPolygons(m_savedPolygons); - for (Polygon& polygon : copyPolygons) { - for (QPointF& point : polygon) { + for (Polygon &polygon : copyPolygons) { + for (QPointF &point : polygon) { point -= m_currentImage->pos(); point = scaledPoint(point); } @@ -73,7 +73,7 @@ void AnnotatorWidget::mousePressEvent(QMouseEvent* event) if (m_shape == marK::Shape::Polygon) { auto savedPolClicked = std::find_if( m_savedPolygons.begin(), m_savedPolygons.end(), - [&](const Polygon& pol) { + [&](const Polygon &pol) { return pol.containsPoint(clickedPoint, Qt::OddEvenFill); } ); @@ -89,8 +89,9 @@ void AnnotatorWidget::mousePressEvent(QMouseEvent* event) QPointF cPolFirstPt = m_currentPolygon.first(); QRectF cPolFirstPtRect(cPolFirstPt, QPointF(cPolFirstPt.x() + 10, cPolFirstPt.y() + 10)); isPolFirstPtClicked = cPolFirstPtRect.contains(clickedPoint); - if (isPolFirstPtClicked) + if (isPolFirstPtClicked) { clickedPoint = QPointF(cPolFirstPt); + } } if (isSavedPolClicked || isPolFirstPtClicked || isImageClicked) { @@ -106,8 +107,9 @@ void AnnotatorWidget::mousePressEvent(QMouseEvent* event) } else if (m_shape == marK::Shape::Rectangle) { if (isImageClicked) { - if (m_currentPolygon.empty()) + if (m_currentPolygon.empty()) { m_currentPolygon << clickedPoint; + } else { QPointF firstPt = m_currentPolygon.first(); m_currentPolygon << QPointF(clickedPoint.x(), firstPt.y()) << clickedPoint << QPointF(firstPt.x(), clickedPoint.y()) << firstPt; @@ -125,18 +127,20 @@ void AnnotatorWidget::mousePressEvent(QMouseEvent* event) void AnnotatorWidget::repaint() { - for (QGraphicsItem* item : m_items) + for (QGraphicsItem* item : m_items) { m_ui->graphicsView->scene()->removeItem(item); + } m_items.clear(); - for (Polygon& polygon : m_savedPolygons) + for (Polygon &polygon : m_savedPolygons) { paintPolygon(polygon); + } paintPolygon(m_currentPolygon); } -void AnnotatorWidget::paintPolygon(Polygon& polygon) +void AnnotatorWidget::paintPolygon(Polygon &polygon) { QGraphicsScene *scene = m_ui->graphicsView->scene(); @@ -157,8 +161,9 @@ void AnnotatorWidget::paintPolygon(Polygon& polygon) item = scene->addRect((*it).x(), (*it).y(), 10, 10, QPen(brush, 2), brush); } - else + else { item = scene->addLine(QLineF(*(it - 1), *it), QPen(QBrush(polygon.polygonClass()->color()), 2)); + } m_items << item; } @@ -193,19 +198,20 @@ void AnnotatorWidget::changeItem(QString itemPath) QPixmap image(itemPath); QPixmap scaledImage; - if (image.height() >= 1280) + if (image.height() >= 1280) { scaledImage = image.scaledToHeight(int(1280 * 0.8)); + } - if (image.width() >= 960) + if (image.width() >= 960) { scaledImage = image.scaledToWidth(int(960 * 0.8)); + } if (!scaledImage.isNull()) { m_scaleW = qreal(scaledImage.width()) / qreal(image.width()); m_scaleH = qreal(scaledImage.height()) / qreal(image.height()); image = scaledImage; } - else - { + else { m_scaleW = 1.0; m_scaleH = 1.0; } @@ -230,10 +236,8 @@ void AnnotatorWidget::clearScene() void AnnotatorWidget::setPolygons(QVector polygons) { QPointF offset = m_currentImage->pos(); - for (Polygon& polygon : polygons) - { - for (QPointF& point : polygon) - { + for (Polygon &polygon : polygons) { + for (QPointF &point : polygon) { point = QPointF(point.x() * m_scaleW, point.y() * m_scaleH); point += offset; } @@ -243,7 +247,7 @@ void AnnotatorWidget::setPolygons(QVector polygons) repaint(); } -QPointF AnnotatorWidget::scaledPoint(const QPointF& point) const +QPointF AnnotatorWidget::scaledPoint(const QPointF &point) const { qreal scaledX = point.x() / m_scaleW; qreal scaledY = point.y() / m_scaleH; diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index a7ab934..1b9bb43 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -116,8 +116,9 @@ void marK::updateFiles(const QString &path) { QListWidgetItem *previousSelectedItem = m_ui->listWidget->currentItem(); QString previousText; - if (previousSelectedItem != nullptr) + if (previousSelectedItem != nullptr) { previousText = previousSelectedItem->text(); + } m_ui->listWidget->clear(); @@ -128,10 +129,12 @@ void marK::updateFiles(const QString &path) for (const QString &item : items) { QPixmap item_pix; - if (item.endsWith(".txt") || item.endsWith(".TXT")) + if (item.endsWith(".txt") || item.endsWith(".TXT")) { item_pix = QIcon::fromTheme("document-edit-sign").pixmap(20, 20); - else + } + else { item_pix = QPixmap(resDirectory.filePath(item)); + } item_pix = item_pix.scaledToWidth(20); @@ -145,8 +148,9 @@ void marK::updateFiles(const QString &path) } } - if (previousText == "") + if (previousText == "") { m_ui->annotatorWidget->clearScene(); + } } void marK::changeItem(int currentRow) @@ -181,8 +185,9 @@ void marK::changeDirectory() QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (!path.isEmpty()) { - if (m_currentDirectory != "") + if (m_currentDirectory != "") { m_watcher->removePath(m_currentDirectory); + } m_currentDirectory = path; m_watcher->addPath(m_currentDirectory); updateFiles(); @@ -232,20 +237,22 @@ void marK::savePolygons(OutputType type) QString document; Serializer serialize(m_ui->annotatorWidget->savedPolygons()); - if (type == OutputType::XML) + if (type == OutputType::XML) { document = serialize.serialize(OutputType::XML); - else if (type == OutputType::JSON) + } + else if (type == OutputType::JSON) { document = serialize.serialize(OutputType::JSON); + } - if (!document.isEmpty()) - { + if (!document.isEmpty()) { QString outputFile(m_filepath); outputFile.replace(QRegularExpression(".jpg|.png|.xpm"), (type == OutputType::XML ? ".xml" : ".json")); QFile fileOut(outputFile); - if (!fileOut.open(QIODevice::WriteOnly | QIODevice::Text)) + if (!fileOut.open(QIODevice::WriteOnly | QIODevice::Text)) { return; + } fileOut.write(document.toUtf8()); @@ -262,14 +269,15 @@ void marK::importData() Serializer serializer(filepath); QVector objects; - if (filepath.endsWith(".json")) + if (filepath.endsWith(".json")) { objects = serializer.read(OutputType::JSON); + } - else if (filepath.endsWith(".xml")) + else if (filepath.endsWith(".xml")) { objects = serializer.read(OutputType::XML); + } - if (objects.empty()) - { + if (objects.empty()) { QMessageBox msgBox; msgBox.setText("failed to load annotation"); msgBox.setIcon(QMessageBox::Warning); @@ -280,9 +288,9 @@ void marK::importData() m_ui->annotatorWidget->setPolygons(objects); // add new classes to comboBox - for (const auto& object : objects) + for (const auto &object : objects) { addNewClass(object.polygonClass()); - + } } void marK::addNewClass(MarkedClass* markedClass) @@ -309,8 +317,7 @@ void marK::makeTempFile() tempFilename.prepend(QDir::tempPath() + "/mark"); QVector objects = m_ui->annotatorWidget->savedPolygons(); - if (!objects.isEmpty()) - { + if (!objects.isEmpty()) { QFile tempFile(tempFilename); tempFile.open(QIODevice::WriteOnly|QIODevice::Text); @@ -323,7 +330,7 @@ void marK::makeTempFile() } } -void marK::retrieveTempFile(const QString& itempath) +void marK::retrieveTempFile(const QString &itempath) { QDir tempDir(QDir::tempPath()); @@ -332,24 +339,23 @@ void marK::retrieveTempFile(const QString& itempath) savedTempFile.replace(QRegularExpression(".jpg|.png|.xpm"), ".json"); savedTempFile.prepend(QDir::tempPath() + "/mark"); - if (tempDir.exists(savedTempFile)) - { + if (tempDir.exists(savedTempFile)) { Serializer serializer(savedTempFile); QVector objects = serializer.read(OutputType::JSON); // reading in JSON m_ui->annotatorWidget->setPolygons(objects); //adding the new classes to comboBox - for (const auto& object : objects) + for (const auto &object : objects) { addNewClass(object.polygonClass()); + } } } marK::~marK() { // cleaning temp files - for (const QString& filename : m_tempFiles) - { + for (const QString& filename : m_tempFiles) { QFile tempfile(filename); tempfile.remove(); } diff --git a/src/ui/serializer.cpp b/src/ui/serializer.cpp index fcf90bf..de8508c 100644 --- a/src/ui/serializer.cpp +++ b/src/ui/serializer.cpp @@ -26,7 +26,7 @@ #include #include -Serializer::Serializer(const QString& filepath) : +Serializer::Serializer(const QString &filepath) : m_filepath(filepath) { } @@ -41,30 +41,33 @@ QVector Serializer::read(marK::OutputType output_type) QVector objects; m_output_type = output_type; - if(output_type == marK::OutputType::XML) + if (output_type == marK::OutputType::XML) { objects = this->readXML(); - - else if (output_type == marK::OutputType::JSON) + } + else if (output_type == marK::OutputType::JSON) { objects = this->readJSON(); + } return objects; } QString Serializer::serialize(marK::OutputType output_type) { - if (output_type == marK::OutputType::XML) + if (output_type == marK::OutputType::XML) { return this->toXML(); - - else if (output_type == marK::OutputType::JSON) + } + else if (output_type == marK::OutputType::JSON) { return this->toJSON(); + } return nullptr; } QString Serializer::toXML() { - if (m_items.isEmpty()) + if (m_items.isEmpty()) { return nullptr; + } QString xmldoc; QXmlStreamWriter xmlWriter(&xmldoc); @@ -73,7 +76,7 @@ QString Serializer::toXML() xmlWriter.writeStartElement("annotation"); - for (const Polygon& item : m_items) { + for (const Polygon &item : m_items) { xmlWriter.writeStartElement("object"); xmlWriter.writeStartElement("class"); @@ -82,7 +85,7 @@ QString Serializer::toXML() xmlWriter.writeStartElement("polygon"); - for (const QPointF& point : item) { + for (const QPointF &point : item) { xmlWriter.writeStartElement("pt"); xmlWriter.writeStartElement("x"); @@ -114,12 +117,13 @@ QString Serializer::toXML() QString Serializer::toJSON() { - if(m_items.isEmpty()) + if (m_items.isEmpty()) { return nullptr; + } QJsonArray classesArray; - for (const Polygon& item : m_items) { + for (const Polygon &item : m_items) { QJsonObject recordObject; recordObject.insert("Class", item.polygonClass()->name()); @@ -160,16 +164,14 @@ QVector Serializer::readJSON() QJsonArray polygonArray = doc.array(); QVector savedPolygons; - for (const QJsonValue& classObj : polygonArray) - { + for (const QJsonValue &classObj : polygonArray) { Polygon polygon; auto polygonClass = new MarkedClass(classObj["Class"].toString()); polygon.setPolygonClass(polygonClass); QJsonArray polygonArray = classObj["Polygon"].toArray(); - for (const QJsonValue& polygonObj : polygonArray) - { + for (const QJsonValue &polygonObj : polygonArray) { QJsonObject ptObj = polygonObj["pt"].toObject(); double x = ptObj.value("x").toString().toDouble(); @@ -192,27 +194,22 @@ QVector Serializer::readXML() QXmlStreamReader xmlReader(data); xmlReader.readNextStartElement(); // going to first element - while (!xmlReader.atEnd()) - { + while (!xmlReader.atEnd()) { QXmlStreamReader::TokenType token = xmlReader.readNext(); - if (token == QXmlStreamReader::StartElement) - { + if (token == QXmlStreamReader::StartElement) { Polygon object; xmlReader.readNextStartElement(); - if (xmlReader.name() == "class") - { + if (xmlReader.name() == "class") { auto markedClass = new MarkedClass(xmlReader.readElementText()); object.setPolygonClass(markedClass); } xmlReader.readNextStartElement(); // closing "class" and going to "polygon" - if (xmlReader.name() == "polygon") - { + if (xmlReader.name() == "polygon") { xmlReader.readNextStartElement(); // going to "pt" - while (xmlReader.name() == "pt") - { + while (xmlReader.name() == "pt") { xmlReader.readNextStartElement(); // going to "x" value double x = xmlReader.readElementText().toDouble(); @@ -232,8 +229,9 @@ QVector Serializer::readXML() } } - if(xmlReader.hasError()) + if (xmlReader.hasError()) { qDebug() << xmlReader.error(); + } return savedObjects; } -- GitLab From 247d38fa2469a151eb9826b1bbfd82dc4df917e4 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Thu, 6 Feb 2020 10:33:52 -0300 Subject: [PATCH 11/29] WIP - refator temporary files related --- src/ui/mark.cpp | 44 +++++++++--------------------- src/ui/mark.h | 2 +- src/ui/serializer.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++ src/ui/serializer.h | 9 +++++++ 4 files changed, 85 insertions(+), 32 deletions(-) diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 1b9bb43..5e29caf 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -169,7 +169,7 @@ void marK::changeItem(QListWidgetItem *current, QListWidgetItem *previous) makeTempFile(); m_filepath = itemPath; m_ui->annotatorWidget->changeItem(itemPath); - retrieveTempFile(itemPath); + retrieveTempFile(); } } } @@ -288,6 +288,7 @@ void marK::importData() m_ui->annotatorWidget->setPolygons(objects); // add new classes to comboBox + // TODO: verify class name, if equal do not add for (const auto &object : objects) { addNewClass(object.polygonClass()); } @@ -309,46 +310,27 @@ void marK::addNewClass(MarkedClass* markedClass) void marK::makeTempFile() { - QDir tempDir(QDir::tempPath()); - - QString tempFilename(m_filepath); - tempFilename.replace("/", "_"); - tempFilename.replace(QRegularExpression(".jpg|.png|.xpm"), ".json"); - tempFilename.prepend(QDir::tempPath() + "/mark"); - QVector objects = m_ui->annotatorWidget->savedPolygons(); - if (!objects.isEmpty()) { - QFile tempFile(tempFilename); - tempFile.open(QIODevice::WriteOnly|QIODevice::Text); - Serializer serializer(m_ui->annotatorWidget->savedPolygons()); - QString document = serializer.serialize(OutputType::JSON); // writing in JSON - tempFile.write(document.toUtf8()); - tempFile.close(); + Serializer serializer(objects); - m_tempFiles.append(tempFilename); + QString tempFileName = serializer.writeTempFile(m_filepath); + if (!tempFileName.isEmpty()) { + m_tempFiles.append(tempFileName); } } -void marK::retrieveTempFile(const QString &itempath) +void marK::retrieveTempFile() { - QDir tempDir(QDir::tempPath()); + Serializer serializer(m_filepath); - QString savedTempFile(itempath); - savedTempFile.replace("/", "_"); - savedTempFile.replace(QRegularExpression(".jpg|.png|.xpm"), ".json"); - savedTempFile.prepend(QDir::tempPath() + "/mark"); + QVector objects = serializer.readTempFile(); // reading in JSON - if (tempDir.exists(savedTempFile)) { - Serializer serializer(savedTempFile); - - QVector objects = serializer.read(OutputType::JSON); // reading in JSON - m_ui->annotatorWidget->setPolygons(objects); + m_ui->annotatorWidget->setPolygons(objects); - //adding the new classes to comboBox - for (const auto &object : objects) { - addNewClass(object.polygonClass()); - } + //adding the new classes to comboBox + for (const auto &object : objects) { + addNewClass(object.polygonClass()); } } diff --git a/src/ui/mark.h b/src/ui/mark.h index 7601b47..e568163 100644 --- a/src/ui/mark.h +++ b/src/ui/mark.h @@ -56,7 +56,7 @@ public: void savePolygons(OutputType type); void addNewClass(MarkedClass* markedClass); void makeTempFile(); - void retrieveTempFile(const QString& itempath); + void retrieveTempFile(); public slots: void changeItem(QListWidgetItem *current, QListWidgetItem *previous); diff --git a/src/ui/serializer.cpp b/src/ui/serializer.cpp index de8508c..a677fb0 100644 --- a/src/ui/serializer.cpp +++ b/src/ui/serializer.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include Serializer::Serializer(const QString &filepath) : @@ -247,3 +248,64 @@ QByteArray Serializer::getData() return data; } + +bool Serializer::write(const QString &filepath, marK::OutputType output_type) +{ + if (!m_items.isEmpty()) { + QFile file(filepath); + + QString document = serialize(output_type); + + if (!document.isEmpty()) { + file.open(QIODevice::WriteOnly|QIODevice::Text); + + file.write(document.toUtf8()); + file.close(); + + return true; + } + else { + return false; + } + } + + return false; +} + +QString Serializer::writeTempFile(const QString &originalFileName) +{ + QDir tempDir(QDir::tempPath()); + + QString tempFileName = getTempFileName(originalFileName); + + bool success = write(tempFileName, marK::OutputType::JSON); + if (!success) { + return nullptr; + } + + return tempFileName; +} + +QVector Serializer::readTempFile() +{ + m_filepath = getTempFileName(m_filepath); + QVector objects; + + QDir tempDir = QDir::tempPath(); + + if (tempDir.exists(m_filepath)) { + objects = read(marK::OutputType::JSON); // reading in JSON + } + + return objects; +} + +QString Serializer::getTempFileName(const QString &filepath) +{ + QString tempFileName = filepath; + tempFileName.replace("/", "_"); + tempFileName.replace(QRegularExpression(".jpg|.jpeg|.png|.xpm"), ".json"); + tempFileName.prepend(QDir::tempPath() + "/mark"); + + return tempFileName; +} diff --git a/src/ui/serializer.h b/src/ui/serializer.h index 51356e7..5059f44 100644 --- a/src/ui/serializer.h +++ b/src/ui/serializer.h @@ -30,16 +30,25 @@ class Serializer public: explicit Serializer(const QString& filepath); explicit Serializer(const QVector items); + + bool write(const QString &filepath, marK::OutputType output_type); + QString writeTempFile(const QString &originalFileName); + QString serialize(marK::OutputType output_type); + QVector read(marK::OutputType output_type); + QVector readTempFile(); private: QByteArray getData(); QString toJSON(); QString toXML(); + QVector readJSON(); QVector readXML(); + QString getTempFileName(const QString &filepath); + private: // put it to work with MarkedObject QVector m_items; -- GitLab From 771ce34854c1b58639676e7147ae7b0c5cb9a384 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Thu, 6 Feb 2020 12:00:52 -0300 Subject: [PATCH 12/29] WIP - separating class responsabilities --- src/ui/annotatorwidget.cpp | 81 +++++++++++++++++++++----------------- src/ui/annotatorwidget.h | 6 +-- src/ui/mark.cpp | 46 +++++++++------------- src/ui/serializer.cpp | 26 +++++++++--- src/ui/serializer.h | 4 +- 5 files changed, 90 insertions(+), 73 deletions(-) diff --git a/src/ui/annotatorwidget.cpp b/src/ui/annotatorwidget.cpp index 9ec3649..3166031 100644 --- a/src/ui/annotatorwidget.cpp +++ b/src/ui/annotatorwidget.cpp @@ -22,8 +22,6 @@ #include #include -#include - AnnotatorWidget::AnnotatorWidget(QWidget* parent): QWidget(parent), m_ui(new Ui::AnnotatorWidget), @@ -48,21 +46,6 @@ AnnotatorWidget::~AnnotatorWidget() { } -// TODO: improve me and remove this loop -QVector AnnotatorWidget::savedPolygons() const -{ - QVector copyPolygons(m_savedPolygons); - - for (Polygon &polygon : copyPolygons) { - for (QPointF &point : polygon) { - point -= m_currentImage->pos(); - point = scaledPoint(point); - } - } - - return copyPolygons; -} - void AnnotatorWidget::mousePressEvent(QMouseEvent* event) { if (m_currentImage != nullptr) { @@ -72,15 +55,15 @@ void AnnotatorWidget::mousePressEvent(QMouseEvent* event) if (m_shape == marK::Shape::Polygon) { auto savedPolClicked = std::find_if( - m_savedPolygons.begin(), m_savedPolygons.end(), + m_savedObjects.begin(), m_savedObjects.end(), [&](const Polygon &pol) { return pol.containsPoint(clickedPoint, Qt::OddEvenFill); } ); - bool isSavedPolClicked = savedPolClicked != m_savedPolygons.end(); + bool isSavedPolClicked = savedPolClicked != m_savedObjects.end(); if (isSavedPolClicked) { m_currentPolygon = *savedPolClicked; - m_savedPolygons.erase(savedPolClicked); + m_savedObjects.erase(savedPolClicked); m_currentPolygon.pop_back(); } @@ -98,7 +81,7 @@ void AnnotatorWidget::mousePressEvent(QMouseEvent* event) m_currentPolygon << clickedPoint; if (m_currentPolygon.size() > 1 && m_currentPolygon.isClosed()) { - m_savedPolygons << m_currentPolygon; + m_savedObjects << m_currentPolygon; m_currentPolygon.clear(); } @@ -113,7 +96,7 @@ void AnnotatorWidget::mousePressEvent(QMouseEvent* event) else { QPointF firstPt = m_currentPolygon.first(); m_currentPolygon << QPointF(clickedPoint.x(), firstPt.y()) << clickedPoint << QPointF(firstPt.x(), clickedPoint.y()) << firstPt; - m_savedPolygons << m_currentPolygon; + m_savedObjects << m_currentPolygon; m_currentPolygon.clear(); } @@ -133,7 +116,7 @@ void AnnotatorWidget::repaint() m_items.clear(); - for (Polygon &polygon : m_savedPolygons) { + for (Polygon &polygon : m_savedObjects) { paintPolygon(polygon); } @@ -181,7 +164,7 @@ void AnnotatorWidget::undo() void AnnotatorWidget::reset() { - m_savedPolygons.clear(); + m_savedObjects.clear(); m_currentPolygon.clear(); repaint(); } @@ -233,23 +216,49 @@ void AnnotatorWidget::clearScene() m_ui->graphicsView->scene()->clear(); } -void AnnotatorWidget::setPolygons(QVector polygons) +QPointF AnnotatorWidget::scaledPoint(const QPointF &point) const +{ + qreal scaledX = point.x() / m_scaleW; + qreal scaledY = point.y() / m_scaleH; + return QPointF(scaledX, scaledY); +} + +bool AnnotatorWidget::saveObjects(const QString &filepath, marK::OutputType type) { - QPointF offset = m_currentImage->pos(); - for (Polygon &polygon : polygons) { - for (QPointF &point : polygon) { - point = QPointF(point.x() * m_scaleW, point.y() * m_scaleH); - point += offset; + QVector scaledObjects(m_savedObjects); + + // TODO: improve me and remove this loop + for (Polygon &object : scaledObjects) { + for (QPointF &point : object) { + point -= m_currentImage->pos(); + point = scaledPoint(point); } } - m_savedPolygons = polygons; - repaint(); + Serializer serializer(scaledObjects); + + return serializer.write(filepath, type); } -QPointF AnnotatorWidget::scaledPoint(const QPointF &point) const +bool AnnotatorWidget::importObjects(const QString &filepath, marK::OutputType output_type) { - qreal scaledX = point.x() / m_scaleW; - qreal scaledY = point.y() / m_scaleH; - return QPointF(scaledX, scaledY); + Serializer serializer(filepath); + + QVector objects = serializer.read(output_type); + + if (!objects.isEmpty()) { + QPointF offset = m_currentImage->pos(); + + for (Polygon &object : objects) { + for (QPointF &point : object) { + point = QPointF(point.x() * m_scaleW, point.y() * m_scaleH); + point += offset; + } + } + + m_savedObjects = objects; + repaint(); + return true; + } + return false; } diff --git a/src/ui/annotatorwidget.h b/src/ui/annotatorwidget.h index b5cf155..d0a30e0 100644 --- a/src/ui/annotatorwidget.h +++ b/src/ui/annotatorwidget.h @@ -39,8 +39,8 @@ public: ~AnnotatorWidget() override; public: - QVector savedPolygons() const; - void setPolygons(QVector polygons); + bool importObjects(const QString &filepath, marK::OutputType output_type); + bool saveObjects(const QString &filepath, marK::OutputType output_type); void mousePressEvent(QMouseEvent* event) override; @@ -62,7 +62,7 @@ public slots: private: Ui::AnnotatorWidget* m_ui; Polygon m_currentPolygon; - QVector m_savedPolygons; + QVector m_savedObjects; QVector m_items; QGraphicsPixmapItem* m_currentImage; marK::Shape m_shape; diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 5e29caf..3d5e346 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -234,29 +234,14 @@ void marK::selectClassColor() void marK::savePolygons(OutputType type) { - QString document; - Serializer serialize(m_ui->annotatorWidget->savedPolygons()); + bool success = m_ui->annotatorWidget->saveObjects(m_filepath, type); - if (type == OutputType::XML) { - document = serialize.serialize(OutputType::XML); - } - else if (type == OutputType::JSON) { - document = serialize.serialize(OutputType::JSON); - } - - if (!document.isEmpty()) { - QString outputFile(m_filepath); - outputFile.replace(QRegularExpression(".jpg|.png|.xpm"), (type == OutputType::XML ? ".xml" : ".json")); - - QFile fileOut(outputFile); - - if (!fileOut.open(QIODevice::WriteOnly | QIODevice::Text)) { - return; - } - - fileOut.write(document.toUtf8()); - - fileOut.close(); + if (!success) + { + QMessageBox msgBox; + msgBox.setText("failed to save annotation"); + msgBox.setIcon(QMessageBox::Warning); + msgBox.exec(); } } @@ -268,16 +253,17 @@ void marK::importData() // TODO: fix crash when there is no image loaded Serializer serializer(filepath); QVector objects; + bool success; if (filepath.endsWith(".json")) { - objects = serializer.read(OutputType::JSON); + success = m_ui->annotatorWidget->importObjects(filepath, OutputType::JSON); } else if (filepath.endsWith(".xml")) { - objects = serializer.read(OutputType::XML); + success = m_ui->annotatorWidget->importObjects(filepath, OutputType::XML); } - if (objects.empty()) { + if (!success) { QMessageBox msgBox; msgBox.setText("failed to load annotation"); msgBox.setIcon(QMessageBox::Warning); @@ -285,8 +271,6 @@ void marK::importData() return; } - m_ui->annotatorWidget->setPolygons(objects); - // add new classes to comboBox // TODO: verify class name, if equal do not add for (const auto &object : objects) { @@ -310,6 +294,9 @@ void marK::addNewClass(MarkedClass* markedClass) void marK::makeTempFile() { + // FIXME, not writing tempFiles yet + // reason: savedPolygons doesnt exists + /* QVector objects = m_ui->annotatorWidget->savedPolygons(); Serializer serializer(objects); @@ -318,10 +305,14 @@ void marK::makeTempFile() if (!tempFileName.isEmpty()) { m_tempFiles.append(tempFileName); } + */ } void marK::retrieveTempFile() { + // FIXME, not reading yet temp files + // reason: setPolygons doesnt exists + /* Serializer serializer(m_filepath); QVector objects = serializer.readTempFile(); // reading in JSON @@ -332,6 +323,7 @@ void marK::retrieveTempFile() for (const auto &object : objects) { addNewClass(object.polygonClass()); } + */ } marK::~marK() diff --git a/src/ui/serializer.cpp b/src/ui/serializer.cpp index a677fb0..7c2f556 100644 --- a/src/ui/serializer.cpp +++ b/src/ui/serializer.cpp @@ -239,7 +239,7 @@ QVector Serializer::readXML() QByteArray Serializer::getData() { - m_filepath.replace(QRegularExpression(".jpg|.png|.xpm"), (m_output_type == marK::OutputType::XML ? ".xml" : ".json")); + m_filepath = handleFileNameExtension(m_filepath); QFile file(m_filepath); file.open(QIODevice::ReadOnly|QIODevice::Text); @@ -252,12 +252,16 @@ QByteArray Serializer::getData() bool Serializer::write(const QString &filepath, marK::OutputType output_type) { if (!m_items.isEmpty()) { - QFile file(filepath); + QString filename = handleFileNameExtension(filepath); + QFile file(filename); QString document = serialize(output_type); if (!document.isEmpty()) { - file.open(QIODevice::WriteOnly|QIODevice::Text); + bool fileOpened = file.open(QIODevice::WriteOnly|QIODevice::Text); + if (!fileOpened) { + return false; + } file.write(document.toUtf8()); file.close(); @@ -278,7 +282,9 @@ QString Serializer::writeTempFile(const QString &originalFileName) QString tempFileName = getTempFileName(originalFileName); - bool success = write(tempFileName, marK::OutputType::JSON); + m_output_type = marK::OutputType::JSON; + + bool success = write(tempFileName, m_output_type); if (!success) { return nullptr; } @@ -303,9 +309,19 @@ QVector Serializer::readTempFile() QString Serializer::getTempFileName(const QString &filepath) { QString tempFileName = filepath; + + tempFileName = handleFileNameExtension(tempFileName); + tempFileName.replace("/", "_"); - tempFileName.replace(QRegularExpression(".jpg|.jpeg|.png|.xpm"), ".json"); tempFileName.prepend(QDir::tempPath() + "/mark"); return tempFileName; } + +QString Serializer::handleFileNameExtension(const QString &str) +{ + QString filename(str); + filename.replace(QRegularExpression(".jpg|.jpeg|.png|.xpm"), (m_output_type == marK::OutputType::XML ? ".xml" : ".json")); + + return filename; +} diff --git a/src/ui/serializer.h b/src/ui/serializer.h index 5059f44..b77f94b 100644 --- a/src/ui/serializer.h +++ b/src/ui/serializer.h @@ -34,8 +34,6 @@ public: bool write(const QString &filepath, marK::OutputType output_type); QString writeTempFile(const QString &originalFileName); - QString serialize(marK::OutputType output_type); - QVector read(marK::OutputType output_type); QVector readTempFile(); @@ -47,7 +45,9 @@ private: QVector readJSON(); QVector readXML(); + QString serialize(marK::OutputType output_type); QString getTempFileName(const QString &filepath); + QString handleFileNameExtension(const QString &str); private: // put it to work with MarkedObject -- GitLab From 5678ad93d36af45932d3a142ddb80a73a433c047 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Thu, 6 Feb 2020 15:01:29 -0300 Subject: [PATCH 13/29] reading temporary files again --- src/ui/annotatorwidget.cpp | 17 +++++--------- src/ui/annotatorwidget.h | 4 +--- src/ui/mark.cpp | 47 ++++++++++++++------------------------ src/ui/serializer.cpp | 47 ++++++++------------------------------ src/ui/serializer.h | 7 +++--- 5 files changed, 37 insertions(+), 85 deletions(-) diff --git a/src/ui/annotatorwidget.cpp b/src/ui/annotatorwidget.cpp index 3166031..e9bbf38 100644 --- a/src/ui/annotatorwidget.cpp +++ b/src/ui/annotatorwidget.cpp @@ -216,13 +216,6 @@ void AnnotatorWidget::clearScene() m_ui->graphicsView->scene()->clear(); } -QPointF AnnotatorWidget::scaledPoint(const QPointF &point) const -{ - qreal scaledX = point.x() / m_scaleW; - qreal scaledY = point.y() / m_scaleH; - return QPointF(scaledX, scaledY); -} - bool AnnotatorWidget::saveObjects(const QString &filepath, marK::OutputType type) { QVector scaledObjects(m_savedObjects); @@ -231,7 +224,7 @@ bool AnnotatorWidget::saveObjects(const QString &filepath, marK::OutputType type for (Polygon &object : scaledObjects) { for (QPointF &point : object) { point -= m_currentImage->pos(); - point = scaledPoint(point); + point = QPointF(point.x() / m_scaleW, point.y() / m_scaleH); } } @@ -240,11 +233,12 @@ bool AnnotatorWidget::saveObjects(const QString &filepath, marK::OutputType type return serializer.write(filepath, type); } -bool AnnotatorWidget::importObjects(const QString &filepath, marK::OutputType output_type) +QVector AnnotatorWidget::importObjects(const QString &filepath, marK::OutputType output_type) { Serializer serializer(filepath); QVector objects = serializer.read(output_type); + QVector markedClasses; if (!objects.isEmpty()) { QPointF offset = m_currentImage->pos(); @@ -254,11 +248,12 @@ bool AnnotatorWidget::importObjects(const QString &filepath, marK::OutputType ou point = QPointF(point.x() * m_scaleW, point.y() * m_scaleH); point += offset; } + markedClasses.append(object.polygonClass()); } m_savedObjects = objects; repaint(); - return true; } - return false; + + return markedClasses; } diff --git a/src/ui/annotatorwidget.h b/src/ui/annotatorwidget.h index d0a30e0..4166770 100644 --- a/src/ui/annotatorwidget.h +++ b/src/ui/annotatorwidget.h @@ -39,7 +39,7 @@ public: ~AnnotatorWidget() override; public: - bool importObjects(const QString &filepath, marK::OutputType output_type); + QVector importObjects(const QString &filepath, marK::OutputType output_type); bool saveObjects(const QString &filepath, marK::OutputType output_type); void mousePressEvent(QMouseEvent* event) override; @@ -53,8 +53,6 @@ public: void setCurrentPolygonClass(MarkedClass* polygonClass) { m_currentPolygon.setPolygonClass(polygonClass); repaint(); } void setShape(marK::Shape shape) { m_shape = shape; m_currentPolygon.clear(); repaint(); } - QPointF scaledPoint(const QPointF& point) const; - public slots: void undo(); void reset(); diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 3d5e346..2fe7599 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -236,8 +236,7 @@ void marK::savePolygons(OutputType type) { bool success = m_ui->annotatorWidget->saveObjects(m_filepath, type); - if (!success) - { + if (!success) { QMessageBox msgBox; msgBox.setText("failed to save annotation"); msgBox.setIcon(QMessageBox::Warning); @@ -251,19 +250,18 @@ void marK::importData() "JSON and XML files (*.json *.xml)"); // TODO: fix crash when there is no image loaded - Serializer serializer(filepath); - QVector objects; - bool success; + QVector markedClasses; + // TODO: remove these if and else if (filepath.endsWith(".json")) { - success = m_ui->annotatorWidget->importObjects(filepath, OutputType::JSON); + markedClasses = m_ui->annotatorWidget->importObjects(filepath, OutputType::JSON); } else if (filepath.endsWith(".xml")) { - success = m_ui->annotatorWidget->importObjects(filepath, OutputType::XML); + markedClasses = m_ui->annotatorWidget->importObjects(filepath, OutputType::XML); } - if (!success) { + if (markedClasses.isEmpty()) { QMessageBox msgBox; msgBox.setText("failed to load annotation"); msgBox.setIcon(QMessageBox::Warning); @@ -273,8 +271,8 @@ void marK::importData() // add new classes to comboBox // TODO: verify class name, if equal do not add - for (const auto &object : objects) { - addNewClass(object.polygonClass()); + for (MarkedClass *markedClass : markedClasses) { + addNewClass(markedClass); } } @@ -294,36 +292,25 @@ void marK::addNewClass(MarkedClass* markedClass) void marK::makeTempFile() { - // FIXME, not writing tempFiles yet - // reason: savedPolygons doesnt exists - /* - QVector objects = m_ui->annotatorWidget->savedPolygons(); + QString tempFilePath = Serializer::getTempFileName(m_filepath); - Serializer serializer(objects); + bool success = m_ui->annotatorWidget->saveObjects(tempFilePath, OutputType::JSON); - QString tempFileName = serializer.writeTempFile(m_filepath); - if (!tempFileName.isEmpty()) { - m_tempFiles.append(tempFileName); + if (success) { + m_tempFiles.append(tempFilePath); } - */ } void marK::retrieveTempFile() { - // FIXME, not reading yet temp files - // reason: setPolygons doesnt exists - /* - Serializer serializer(m_filepath); - - QVector objects = serializer.readTempFile(); // reading in JSON + QString tempFilePath = Serializer::getTempFileName(m_filepath); + QVector markedClasses; - m_ui->annotatorWidget->setPolygons(objects); + markedClasses = m_ui->annotatorWidget->importObjects(tempFilePath, OutputType::JSON); - //adding the new classes to comboBox - for (const auto &object : objects) { - addNewClass(object.polygonClass()); + for (MarkedClass *markedClass : markedClasses) { + addNewClass(markedClass); } - */ } marK::~marK() diff --git a/src/ui/serializer.cpp b/src/ui/serializer.cpp index 7c2f556..c0abe6c 100644 --- a/src/ui/serializer.cpp +++ b/src/ui/serializer.cpp @@ -42,11 +42,14 @@ QVector Serializer::read(marK::OutputType output_type) QVector objects; m_output_type = output_type; - if (output_type == marK::OutputType::XML) { - objects = this->readXML(); - } - else if (output_type == marK::OutputType::JSON) { - objects = this->readJSON(); + bool fileExists = QFile::exists(m_filepath); + if (fileExists) { + if (output_type == marK::OutputType::XML) { + objects = this->readXML(); + } + else if (output_type == marK::OutputType::JSON) { + objects = this->readJSON(); + } } return objects; @@ -276,36 +279,6 @@ bool Serializer::write(const QString &filepath, marK::OutputType output_type) return false; } -QString Serializer::writeTempFile(const QString &originalFileName) -{ - QDir tempDir(QDir::tempPath()); - - QString tempFileName = getTempFileName(originalFileName); - - m_output_type = marK::OutputType::JSON; - - bool success = write(tempFileName, m_output_type); - if (!success) { - return nullptr; - } - - return tempFileName; -} - -QVector Serializer::readTempFile() -{ - m_filepath = getTempFileName(m_filepath); - QVector objects; - - QDir tempDir = QDir::tempPath(); - - if (tempDir.exists(m_filepath)) { - objects = read(marK::OutputType::JSON); // reading in JSON - } - - return objects; -} - QString Serializer::getTempFileName(const QString &filepath) { QString tempFileName = filepath; @@ -318,10 +291,10 @@ QString Serializer::getTempFileName(const QString &filepath) return tempFileName; } -QString Serializer::handleFileNameExtension(const QString &str) +QString Serializer::handleFileNameExtension(const QString &str, marK::OutputType output_type) { QString filename(str); - filename.replace(QRegularExpression(".jpg|.jpeg|.png|.xpm"), (m_output_type == marK::OutputType::XML ? ".xml" : ".json")); + filename.replace(QRegularExpression(".jpg|.jpeg|.png|.xpm"), (output_type == marK::OutputType::XML ? ".xml" : ".json")); return filename; } diff --git a/src/ui/serializer.h b/src/ui/serializer.h index b77f94b..dd9c9af 100644 --- a/src/ui/serializer.h +++ b/src/ui/serializer.h @@ -32,10 +32,11 @@ public: explicit Serializer(const QVector items); bool write(const QString &filepath, marK::OutputType output_type); - QString writeTempFile(const QString &originalFileName); QVector read(marK::OutputType output_type); - QVector readTempFile(); + + static QString getTempFileName(const QString &filepath); + static QString handleFileNameExtension(const QString &str, marK::OutputType output_type = marK::OutputType::JSON); private: QByteArray getData(); @@ -46,8 +47,6 @@ private: QVector readXML(); QString serialize(marK::OutputType output_type); - QString getTempFileName(const QString &filepath); - QString handleFileNameExtension(const QString &str); private: // put it to work with MarkedObject -- GitLab From 90400ebb05f2e456eb45dc0d4a0b8a5520c14d9a Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Fri, 7 Feb 2020 14:11:24 -0300 Subject: [PATCH 14/29] fix bug in saving xml files --- src/ui/serializer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/serializer.cpp b/src/ui/serializer.cpp index c0abe6c..3112c54 100644 --- a/src/ui/serializer.cpp +++ b/src/ui/serializer.cpp @@ -255,7 +255,7 @@ QByteArray Serializer::getData() bool Serializer::write(const QString &filepath, marK::OutputType output_type) { if (!m_items.isEmpty()) { - QString filename = handleFileNameExtension(filepath); + QString filename = handleFileNameExtension(filepath, output_type); QFile file(filename); QString document = serialize(output_type); -- GitLab From aa151bba6caafd31e874601a300daf1e15f1ed81 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Fri, 7 Feb 2020 14:25:25 -0300 Subject: [PATCH 15/29] added support to auto save in json and xml --- src/ui/annotatorwidget.cpp | 13 ++++++++++-- src/ui/annotatorwidget.h | 6 ++++++ src/ui/mark.cpp | 43 +++++++++++++++++++++++++++++++++++++- src/ui/mark.h | 3 +++ 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/ui/annotatorwidget.cpp b/src/ui/annotatorwidget.cpp index e9bbf38..931f872 100644 --- a/src/ui/annotatorwidget.cpp +++ b/src/ui/annotatorwidget.cpp @@ -28,7 +28,9 @@ AnnotatorWidget::AnnotatorWidget(QWidget* parent): m_currentImage(nullptr), m_shape(marK::Shape::Polygon), m_scaleW(0.0), - m_scaleH(0.0) + m_scaleH(0.0), + m_autoSaveJsonFilePath(""), + m_autoSaveXmlFilePath("") { m_ui->setupUi(this); @@ -134,6 +136,14 @@ void AnnotatorWidget::paintPolygon(Polygon &polygon) QGraphicsPolygonItem *pol = scene->addPolygon(polygon, QPen(polygon.polygonClass()->color(), 2), QBrush(color)); m_items << pol; + + if (!m_autoSaveJsonFilePath.isEmpty()) { + saveObjects(m_autoSaveJsonFilePath, marK::OutputType::JSON); + } + if (!m_autoSaveXmlFilePath.isEmpty()) { + saveObjects(m_autoSaveXmlFilePath, marK::OutputType::XML); + } + } else { for (auto it = polygon.begin(); it != polygon.end(); ++it) { @@ -227,7 +237,6 @@ bool AnnotatorWidget::saveObjects(const QString &filepath, marK::OutputType type point = QPointF(point.x() / m_scaleW, point.y() / m_scaleH); } } - Serializer serializer(scaledObjects); return serializer.write(filepath, type); diff --git a/src/ui/annotatorwidget.h b/src/ui/annotatorwidget.h index 4166770..9a76e30 100644 --- a/src/ui/annotatorwidget.h +++ b/src/ui/annotatorwidget.h @@ -42,6 +42,9 @@ public: QVector importObjects(const QString &filepath, marK::OutputType output_type); bool saveObjects(const QString &filepath, marK::OutputType output_type); + void setAutoSaveJsonFilePath(const QString &str) { m_autoSaveJsonFilePath = str; } + void setAutoSaveXmlFilePath(const QString &str) { m_autoSaveXmlFilePath = str; } + void mousePressEvent(QMouseEvent* event) override; void changeItem(QString itemPath); @@ -67,6 +70,9 @@ private: qreal m_scaleW; qreal m_scaleH; + + QString m_autoSaveJsonFilePath; + QString m_autoSaveXmlFilePath; }; #endif // ANNOTATORWIDGET_H diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 2fe7599..442cd1c 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -67,6 +66,18 @@ marK::marK(QWidget *parent) : undoAction->setShortcut(QKeySequence(Qt::Modifier::CTRL + Qt::Key::Key_Z)); connect(undoAction, &QAction::triggered, m_ui->annotatorWidget, &AnnotatorWidget::undo); + QMenu *autoSaveMenu = editMenu->addMenu("Auto Save"); + + QAction *enableAutoSaveJson = autoSaveMenu->addAction("JSON"); + enableAutoSaveJson->setCheckable(true); + connect(enableAutoSaveJson, &QAction::toggled, this, [=](){ toggleAutoSave(OutputType::JSON); }); + //connect(enableAutoSaveJson, &QAction::toggled, this, qOverload(&marK::toggleAutoSave)); + + QAction *enableAutoSaveXml = autoSaveMenu->addAction("XML"); + enableAutoSaveXml->setCheckable(true); + connect(enableAutoSaveXml, &QAction::toggled, this, [=](){ toggleAutoSave(OutputType::XML); }); + //connect(enableAutoSaveXml, &QAction::toggled, this, qOverload(&marK::toggleAutoSave)); + m_ui->annotatorWidget->setMinimumSize(860, 650); updateFiles(); @@ -170,6 +181,13 @@ void marK::changeItem(QListWidgetItem *current, QListWidgetItem *previous) m_filepath = itemPath; m_ui->annotatorWidget->changeItem(itemPath); retrieveTempFile(); + + if (m_autoSaveJsonIsChecked) { + m_ui->annotatorWidget->setAutoSaveJsonFilePath(itemPath); + } + if (m_autoSaveXmlIsChecked) { + m_ui->annotatorWidget->setAutoSaveXmlFilePath(itemPath); + } } } } @@ -313,6 +331,29 @@ void marK::retrieveTempFile() } } +void marK::toggleAutoSave(OutputType output_type) +{ + if (output_type == marK::OutputType::JSON) { + if (m_autoSaveJsonIsChecked) { + m_ui->annotatorWidget->setAutoSaveJsonFilePath(""); + m_autoSaveJsonIsChecked = false; + return; + } + m_ui->annotatorWidget->setAutoSaveJsonFilePath(m_filepath); + m_autoSaveJsonIsChecked = true; + } + + else if (output_type == marK::OutputType::XML) { + if (m_autoSaveXmlIsChecked) { + m_ui->annotatorWidget->setAutoSaveXmlFilePath(""); + m_autoSaveXmlIsChecked = false; + return; + } + m_ui->annotatorWidget->setAutoSaveXmlFilePath(m_filepath); + m_autoSaveXmlIsChecked = true; + } +} + marK::~marK() { // cleaning temp files diff --git a/src/ui/mark.h b/src/ui/mark.h index e568163..2e7e30c 100644 --- a/src/ui/mark.h +++ b/src/ui/mark.h @@ -57,6 +57,7 @@ public: void addNewClass(MarkedClass* markedClass); void makeTempFile(); void retrieveTempFile(); + void toggleAutoSave(OutputType output_type); public slots: void changeItem(QListWidgetItem *current, QListWidgetItem *previous); @@ -74,6 +75,8 @@ private: QString m_filepath; QVector m_polygonClasses; QVector m_tempFiles; + bool m_autoSaveJsonIsChecked; + bool m_autoSaveXmlIsChecked; }; #endif // MARK_H -- GitLab From edf2d676ac4bd9e5bd6b2cefa7f024f6f54803ae Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Sat, 8 Feb 2020 07:20:03 -0300 Subject: [PATCH 16/29] improve auto save logic --- src/ui/annotatorwidget.cpp | 19 ++++++++++++------- src/ui/annotatorwidget.h | 10 ++++++---- src/ui/mark.cpp | 33 +++++++++++---------------------- src/ui/mark.h | 4 ++-- 4 files changed, 31 insertions(+), 35 deletions(-) diff --git a/src/ui/annotatorwidget.cpp b/src/ui/annotatorwidget.cpp index 931f872..dab69e6 100644 --- a/src/ui/annotatorwidget.cpp +++ b/src/ui/annotatorwidget.cpp @@ -29,8 +29,9 @@ AnnotatorWidget::AnnotatorWidget(QWidget* parent): m_shape(marK::Shape::Polygon), m_scaleW(0.0), m_scaleH(0.0), - m_autoSaveJsonFilePath(""), - m_autoSaveXmlFilePath("") + m_autoSaveFilePath(""), + m_autoSaveJsonIsEnabled(false), + m_autoSaveXmlIsEnabled(false) { m_ui->setupUi(this); @@ -137,13 +138,12 @@ void AnnotatorWidget::paintPolygon(Polygon &polygon) m_items << pol; - if (!m_autoSaveJsonFilePath.isEmpty()) { - saveObjects(m_autoSaveJsonFilePath, marK::OutputType::JSON); + if (m_autoSaveJsonIsEnabled) { + saveObjects(m_autoSaveFilePath, marK::OutputType::JSON); } - if (!m_autoSaveXmlFilePath.isEmpty()) { - saveObjects(m_autoSaveXmlFilePath, marK::OutputType::XML); + if (m_autoSaveXmlIsEnabled) { + saveObjects(m_autoSaveFilePath, marK::OutputType::XML); } - } else { for (auto it = polygon.begin(); it != polygon.end(); ++it) { @@ -266,3 +266,8 @@ QVector AnnotatorWidget::importObjects(const QString &filepath, ma return markedClasses; } + +void AnnotatorWidget::setAutoSaveFilePath(const QString &str) +{ + m_autoSaveFilePath = str; +} diff --git a/src/ui/annotatorwidget.h b/src/ui/annotatorwidget.h index 9a76e30..042cdc2 100644 --- a/src/ui/annotatorwidget.h +++ b/src/ui/annotatorwidget.h @@ -42,8 +42,9 @@ public: QVector importObjects(const QString &filepath, marK::OutputType output_type); bool saveObjects(const QString &filepath, marK::OutputType output_type); - void setAutoSaveJsonFilePath(const QString &str) { m_autoSaveJsonFilePath = str; } - void setAutoSaveXmlFilePath(const QString &str) { m_autoSaveXmlFilePath = str; } + void setAutoSaveFilePath(const QString &str); + void toggleAutoSaveJson() { m_autoSaveJsonIsEnabled = !m_autoSaveJsonIsEnabled; }; + void toggleAutoSaveXml() { m_autoSaveXmlIsEnabled = !m_autoSaveXmlIsEnabled; }; void mousePressEvent(QMouseEvent* event) override; @@ -71,8 +72,9 @@ private: qreal m_scaleW; qreal m_scaleH; - QString m_autoSaveJsonFilePath; - QString m_autoSaveXmlFilePath; + QString m_autoSaveFilePath; + bool m_autoSaveJsonIsEnabled; + bool m_autoSaveXmlIsEnabled; }; #endif // ANNOTATORWIDGET_H diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 442cd1c..d568247 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -38,7 +38,9 @@ marK::marK(QWidget *parent) : QMainWindow(parent), m_ui(new Ui::marK), m_watcher(new QFileSystemWatcher(this)), - m_currentDirectory("") + m_currentDirectory(""), + m_autoSaveJsonIsEnabled(false), + m_autoSaveXmlIsEnabled(false) { m_ui->setupUi(this); @@ -71,12 +73,10 @@ marK::marK(QWidget *parent) : QAction *enableAutoSaveJson = autoSaveMenu->addAction("JSON"); enableAutoSaveJson->setCheckable(true); connect(enableAutoSaveJson, &QAction::toggled, this, [=](){ toggleAutoSave(OutputType::JSON); }); - //connect(enableAutoSaveJson, &QAction::toggled, this, qOverload(&marK::toggleAutoSave)); QAction *enableAutoSaveXml = autoSaveMenu->addAction("XML"); enableAutoSaveXml->setCheckable(true); connect(enableAutoSaveXml, &QAction::toggled, this, [=](){ toggleAutoSave(OutputType::XML); }); - //connect(enableAutoSaveXml, &QAction::toggled, this, qOverload(&marK::toggleAutoSave)); m_ui->annotatorWidget->setMinimumSize(860, 650); @@ -182,11 +182,8 @@ void marK::changeItem(QListWidgetItem *current, QListWidgetItem *previous) m_ui->annotatorWidget->changeItem(itemPath); retrieveTempFile(); - if (m_autoSaveJsonIsChecked) { - m_ui->annotatorWidget->setAutoSaveJsonFilePath(itemPath); - } - if (m_autoSaveXmlIsChecked) { - m_ui->annotatorWidget->setAutoSaveXmlFilePath(itemPath); + if (m_autoSaveJsonIsEnabled || m_autoSaveXmlIsEnabled) { + m_ui->annotatorWidget->setAutoSaveFilePath(itemPath); } } } @@ -334,23 +331,15 @@ void marK::retrieveTempFile() void marK::toggleAutoSave(OutputType output_type) { if (output_type == marK::OutputType::JSON) { - if (m_autoSaveJsonIsChecked) { - m_ui->annotatorWidget->setAutoSaveJsonFilePath(""); - m_autoSaveJsonIsChecked = false; - return; - } - m_ui->annotatorWidget->setAutoSaveJsonFilePath(m_filepath); - m_autoSaveJsonIsChecked = true; + m_ui->annotatorWidget->setAutoSaveFilePath(m_filepath); + m_ui->annotatorWidget->toggleAutoSaveJson(); + m_autoSaveJsonIsEnabled = !m_autoSaveJsonIsEnabled; } else if (output_type == marK::OutputType::XML) { - if (m_autoSaveXmlIsChecked) { - m_ui->annotatorWidget->setAutoSaveXmlFilePath(""); - m_autoSaveXmlIsChecked = false; - return; - } - m_ui->annotatorWidget->setAutoSaveXmlFilePath(m_filepath); - m_autoSaveXmlIsChecked = true; + m_ui->annotatorWidget->setAutoSaveFilePath(m_filepath); + m_ui->annotatorWidget->toggleAutoSaveXml(); + m_autoSaveXmlIsEnabled = !m_autoSaveXmlIsEnabled; } } diff --git a/src/ui/mark.h b/src/ui/mark.h index 2e7e30c..960927b 100644 --- a/src/ui/mark.h +++ b/src/ui/mark.h @@ -75,8 +75,8 @@ private: QString m_filepath; QVector m_polygonClasses; QVector m_tempFiles; - bool m_autoSaveJsonIsChecked; - bool m_autoSaveXmlIsChecked; + bool m_autoSaveJsonIsEnabled; + bool m_autoSaveXmlIsEnabled; }; #endif // MARK_H -- GitLab From bfa2150dc0369f84753827f4b2a6db42e8006040 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Sat, 8 Feb 2020 13:26:11 -0300 Subject: [PATCH 17/29] use up and down keys to navegate between items --- src/ui/mark.cpp | 45 +++++++++++++++++++++++++++++++++++++++------ src/ui/mark.h | 5 ++++- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index d568247..3bc02d3 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -33,12 +33,14 @@ #include #include #include +#include marK::marK(QWidget *parent) : QMainWindow(parent), m_ui(new Ui::marK), m_watcher(new QFileSystemWatcher(this)), m_currentDirectory(""), + m_currentIndex(-1), m_autoSaveJsonIsEnabled(false), m_autoSaveXmlIsEnabled(false) { @@ -78,6 +80,14 @@ marK::marK(QWidget *parent) : enableAutoSaveXml->setCheckable(true); connect(enableAutoSaveXml, &QAction::toggled, this, [=](){ toggleAutoSave(OutputType::XML); }); + QShortcut *nextItemShortcut = new QShortcut(this); + nextItemShortcut->setKey(Qt::Key_Down); + connect(nextItemShortcut, &QShortcut::activated, this, &marK::goToNextItem); + + QShortcut *previousItemShortcut = new QShortcut(this); + previousItemShortcut->setKey(Qt::Key_Up); + connect(previousItemShortcut, &QShortcut::activated, this, &marK::goToPreviousItem); + m_ui->annotatorWidget->setMinimumSize(860, 650); updateFiles(); @@ -152,21 +162,42 @@ void marK::updateFiles(const QString &path) QListWidgetItem *itemW = new QListWidgetItem(item_pix, item); m_ui->listWidget->addItem(itemW); - if (previousText != "" and previousText == item) { + if (!previousText.isEmpty() && previousText == item) { int currentIndex = m_ui->listWidget->count() - 1; - m_ui->listWidget->setCurrentRow(currentIndex); - changeItem(currentIndex); + m_currentIndex = currentIndex; + changeItem(); } } - if (previousText == "") { + if (previousText.isEmpty()) { m_ui->annotatorWidget->clearScene(); } } -void marK::changeItem(int currentRow) +void marK::goToNextItem() +{ + m_currentIndex += 1; + if (m_currentIndex >= m_ui->listWidget->count()) { + m_currentIndex = 0; + } + + changeItem(); +} + +void marK::goToPreviousItem() +{ + m_currentIndex -= 1; + if (m_currentIndex < 0) { + m_currentIndex = m_ui->listWidget->count() - 1; + } + + changeItem(); +} + +void marK::changeItem() { - QListWidgetItem *currentItem = m_ui->listWidget->item(currentRow); + m_ui->listWidget->setCurrentRow(m_currentIndex); + QListWidgetItem *currentItem = m_ui->listWidget->item(m_currentIndex); changeItem(currentItem, nullptr); } @@ -205,6 +236,8 @@ void marK::changeDirectory() } m_currentDirectory = path; m_watcher->addPath(m_currentDirectory); + m_ui->listWidget->clear(); + m_currentIndex = -1; updateFiles(); QFontMetrics metrics(m_ui->listLabel->font()); diff --git a/src/ui/mark.h b/src/ui/mark.h index 960927b..fb78835 100644 --- a/src/ui/mark.h +++ b/src/ui/mark.h @@ -50,7 +50,7 @@ public: public: void changeDirectory(); - void changeItem(int currentRow); + void changeItem(); void changeShape(marK::Shape shape); void updateFiles(); void savePolygons(OutputType type); @@ -67,6 +67,8 @@ public slots: void saveToJson() { savePolygons(OutputType::JSON); }; void saveToXml() { savePolygons(OutputType::XML); }; void importData(); + void goToNextItem(); + void goToPreviousItem(); private: QScopedPointer m_ui; @@ -75,6 +77,7 @@ private: QString m_filepath; QVector m_polygonClasses; QVector m_tempFiles; + int m_currentIndex; bool m_autoSaveJsonIsEnabled; bool m_autoSaveXmlIsEnabled; }; -- GitLab From 170ea730a43439df5238725f64c929ac7490b8f1 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Sat, 8 Feb 2020 19:43:33 -0300 Subject: [PATCH 18/29] split toggleAutoSave function --- src/ui/mark.cpp | 25 ++++++++++++------------- src/ui/mark.h | 3 ++- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 3bc02d3..15830d4 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -74,11 +74,11 @@ marK::marK(QWidget *parent) : QAction *enableAutoSaveJson = autoSaveMenu->addAction("JSON"); enableAutoSaveJson->setCheckable(true); - connect(enableAutoSaveJson, &QAction::toggled, this, [=](){ toggleAutoSave(OutputType::JSON); }); + connect(enableAutoSaveJson, &QAction::toggled, this, &marK::toggleAutoSaveJson); QAction *enableAutoSaveXml = autoSaveMenu->addAction("XML"); enableAutoSaveXml->setCheckable(true); - connect(enableAutoSaveXml, &QAction::toggled, this, [=](){ toggleAutoSave(OutputType::XML); }); + connect(enableAutoSaveXml, &QAction::toggled, this, &marK::toggleAutoSaveXml); QShortcut *nextItemShortcut = new QShortcut(this); nextItemShortcut->setKey(Qt::Key_Down); @@ -361,19 +361,18 @@ void marK::retrieveTempFile() } } -void marK::toggleAutoSave(OutputType output_type) +void marK::toggleAutoSaveJson() { - if (output_type == marK::OutputType::JSON) { - m_ui->annotatorWidget->setAutoSaveFilePath(m_filepath); - m_ui->annotatorWidget->toggleAutoSaveJson(); - m_autoSaveJsonIsEnabled = !m_autoSaveJsonIsEnabled; - } + m_ui->annotatorWidget->setAutoSaveFilePath(m_filepath); + m_ui->annotatorWidget->toggleAutoSaveJson(); + m_autoSaveJsonIsEnabled = !m_autoSaveJsonIsEnabled; +} - else if (output_type == marK::OutputType::XML) { - m_ui->annotatorWidget->setAutoSaveFilePath(m_filepath); - m_ui->annotatorWidget->toggleAutoSaveXml(); - m_autoSaveXmlIsEnabled = !m_autoSaveXmlIsEnabled; - } +void marK::toggleAutoSaveXml() +{ + m_ui->annotatorWidget->setAutoSaveFilePath(m_filepath); + m_ui->annotatorWidget->toggleAutoSaveXml(); + m_autoSaveXmlIsEnabled = !m_autoSaveXmlIsEnabled; } marK::~marK() diff --git a/src/ui/mark.h b/src/ui/mark.h index fb78835..4e33a75 100644 --- a/src/ui/mark.h +++ b/src/ui/mark.h @@ -57,7 +57,6 @@ public: void addNewClass(MarkedClass* markedClass); void makeTempFile(); void retrieveTempFile(); - void toggleAutoSave(OutputType output_type); public slots: void changeItem(QListWidgetItem *current, QListWidgetItem *previous); @@ -69,6 +68,8 @@ public slots: void importData(); void goToNextItem(); void goToPreviousItem(); + void toggleAutoSaveJson(); + void toggleAutoSaveXml(); private: QScopedPointer m_ui; -- GitLab From 8e2a314f4b69eb22f6535236a75ab01d06302cf4 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Sun, 9 Feb 2020 15:48:36 -0300 Subject: [PATCH 19/29] apply suggestions made by clazy --- src/ui/annotatorwidget.cpp | 2 +- src/ui/mark.cpp | 16 ++++++++-------- src/ui/serializer.cpp | 9 +++++---- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/ui/annotatorwidget.cpp b/src/ui/annotatorwidget.cpp index dab69e6..88f2583 100644 --- a/src/ui/annotatorwidget.cpp +++ b/src/ui/annotatorwidget.cpp @@ -113,7 +113,7 @@ void AnnotatorWidget::mousePressEvent(QMouseEvent* event) void AnnotatorWidget::repaint() { - for (QGraphicsItem* item : m_items) { + for (QGraphicsItem *item : qAsConst(m_items)) { m_ui->graphicsView->scene()->removeItem(item); } diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 15830d4..697436c 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -104,14 +104,14 @@ marK::marK(QWidget *parent) : connect(m_ui->undoButton, &QPushButton::clicked, m_ui->annotatorWidget, &AnnotatorWidget::undo); connect(m_ui->resetButton, &QPushButton::clicked, m_ui->annotatorWidget, &AnnotatorWidget::reset); - connect(m_ui->comboBox, &QComboBox::editTextChanged, + connect(m_ui->comboBox, &QComboBox::editTextChanged, this, [&](const QString & text) { m_ui->comboBox->setItemText(m_ui->comboBox->currentIndex(), text); m_polygonClasses[m_ui->comboBox->currentIndex()]->setName(text); } ); - connect(m_ui->comboBox, QOverload::of(&QComboBox::activated), + connect(m_ui->comboBox, QOverload::of(&QComboBox::activated), this, [&](int index) { m_ui->annotatorWidget->setCurrentPolygonClass(m_polygonClasses[index]); } @@ -120,11 +120,11 @@ marK::marK(QWidget *parent) : connect(m_ui->selectClassColorButton, &QPushButton::clicked, this, &marK::selectClassColor); m_ui->polygonButton->setIcon(QIcon::fromTheme("tool_polyline")); - connect(m_ui->polygonButton, &QPushButton::clicked, + connect(m_ui->polygonButton, &QPushButton::clicked, this, [&](bool checked) { changeShape(marK::Shape::Polygon); }); m_ui->rectButton->setIcon(QIcon::fromTheme("tool_rectangle")); - connect(m_ui->rectButton, &QPushButton::clicked, + connect(m_ui->rectButton, &QPushButton::clicked, this, [&](bool checked) { changeShape(marK::Shape::Rectangle); }); } @@ -147,7 +147,7 @@ void marK::updateFiles(const QString &path) QStringList items = resDirectory.entryList(QStringList() << "*.jpg" << "*.jpeg" << "*.JPG" << "*.JPEG" << "*.png" << "*.PNG" << "*.txt" << "*.TXT", QDir::Files); - for (const QString &item : items) { + for (const QString &item : qAsConst(items)) { QPixmap item_pix; if (item.endsWith(".txt") || item.endsWith(".TXT")) { @@ -319,7 +319,7 @@ void marK::importData() // add new classes to comboBox // TODO: verify class name, if equal do not add - for (MarkedClass *markedClass : markedClasses) { + for (MarkedClass *markedClass : qAsConst(markedClasses)) { addNewClass(markedClass); } } @@ -356,7 +356,7 @@ void marK::retrieveTempFile() markedClasses = m_ui->annotatorWidget->importObjects(tempFilePath, OutputType::JSON); - for (MarkedClass *markedClass : markedClasses) { + for (MarkedClass *markedClass : qAsConst(markedClasses)) { addNewClass(markedClass); } } @@ -378,7 +378,7 @@ void marK::toggleAutoSaveXml() marK::~marK() { // cleaning temp files - for (const QString& filename : m_tempFiles) { + for (const QString &filename : qAsConst(m_tempFiles)) { QFile tempfile(filename); tempfile.remove(); } diff --git a/src/ui/serializer.cpp b/src/ui/serializer.cpp index 3112c54..69bfb6d 100644 --- a/src/ui/serializer.cpp +++ b/src/ui/serializer.cpp @@ -19,6 +19,7 @@ #include "markedclass.h" #include +#include #include #include #include @@ -80,7 +81,7 @@ QString Serializer::toXML() xmlWriter.writeStartElement("annotation"); - for (const Polygon &item : m_items) { + for (const Polygon &item : qAsConst(m_items)) { xmlWriter.writeStartElement("object"); xmlWriter.writeStartElement("class"); @@ -127,7 +128,7 @@ QString Serializer::toJSON() QJsonArray classesArray; - for (const Polygon &item : m_items) { + for (const Polygon &item : qAsConst(m_items)) { QJsonObject recordObject; recordObject.insert("Class", item.polygonClass()->name()); @@ -168,14 +169,14 @@ QVector Serializer::readJSON() QJsonArray polygonArray = doc.array(); QVector savedPolygons; - for (const QJsonValue &classObj : polygonArray) { + for (const QJsonValue &classObj : qAsConst(polygonArray)) { Polygon polygon; auto polygonClass = new MarkedClass(classObj["Class"].toString()); polygon.setPolygonClass(polygonClass); QJsonArray polygonArray = classObj["Polygon"].toArray(); - for (const QJsonValue &polygonObj : polygonArray) { + for (const QJsonValue &polygonObj : qAsConst(polygonArray)) { QJsonObject ptObj = polygonObj["pt"].toObject(); double x = ptObj.value("x").toString().toDouble(); -- GitLab From ed78b5e204d4008deb4f162b7ad1e1047a7d4ab2 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Mon, 10 Feb 2020 13:25:10 -0300 Subject: [PATCH 20/29] fix bug in adding new marked classes with the same name read in a file --- src/ui/mark.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 697436c..8b1c4fd 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -322,10 +322,17 @@ void marK::importData() for (MarkedClass *markedClass : qAsConst(markedClasses)) { addNewClass(markedClass); } + m_ui->annotatorWidget->repaint(); } -void marK::addNewClass(MarkedClass* markedClass) +void marK::addNewClass(MarkedClass *markedClass) { + for (MarkedClass *existingMarkedClass : m_polygonClasses) { + if (markedClass->name() == existingMarkedClass->name()) { + markedClass->setColor(existingMarkedClass->color()); + return; + } + } int classQt = m_polygonClasses.size(); m_polygonClasses << markedClass; @@ -359,6 +366,7 @@ void marK::retrieveTempFile() for (MarkedClass *markedClass : qAsConst(markedClasses)) { addNewClass(markedClass); } + m_ui->annotatorWidget->repaint(); } void marK::toggleAutoSaveJson() -- GitLab From 1bc93d012a736b1e10789233d7493f3d3d8969e7 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Mon, 10 Feb 2020 13:32:09 -0300 Subject: [PATCH 21/29] fix bug in navegation when a item is selected with the mouse --- src/ui/mark.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 8b1c4fd..fa602bc 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -208,6 +208,7 @@ void marK::changeItem(QListWidgetItem *current, QListWidgetItem *previous) QString itemPath = QDir(m_currentDirectory).filePath(current->text()); if (itemPath != m_filepath) { + m_currentIndex = m_ui->listWidget->currentRow(); makeTempFile(); m_filepath = itemPath; m_ui->annotatorWidget->changeItem(itemPath); @@ -327,7 +328,7 @@ void marK::importData() void marK::addNewClass(MarkedClass *markedClass) { - for (MarkedClass *existingMarkedClass : m_polygonClasses) { + for (MarkedClass *existingMarkedClass : qAsConst(m_polygonClasses)) { if (markedClass->name() == existingMarkedClass->name()) { markedClass->setColor(existingMarkedClass->color()); return; -- GitLab From 37087dd5b815c3f2eddcdf9a1812a445f089ae52 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Mon, 10 Feb 2020 14:17:23 -0300 Subject: [PATCH 22/29] refator, remove unneeded code --- src/ui/annotatorwidget.cpp | 4 ++-- src/ui/annotatorwidget.h | 2 +- src/ui/mark.cpp | 12 ++---------- src/ui/serializer.cpp | 7 +++---- src/ui/serializer.h | 3 +-- 5 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/ui/annotatorwidget.cpp b/src/ui/annotatorwidget.cpp index 88f2583..21d96a3 100644 --- a/src/ui/annotatorwidget.cpp +++ b/src/ui/annotatorwidget.cpp @@ -242,11 +242,11 @@ bool AnnotatorWidget::saveObjects(const QString &filepath, marK::OutputType type return serializer.write(filepath, type); } -QVector AnnotatorWidget::importObjects(const QString &filepath, marK::OutputType output_type) +QVector AnnotatorWidget::importObjects(const QString &filepath) { Serializer serializer(filepath); - QVector objects = serializer.read(output_type); + QVector objects = serializer.read(); QVector markedClasses; if (!objects.isEmpty()) { diff --git a/src/ui/annotatorwidget.h b/src/ui/annotatorwidget.h index 042cdc2..557e602 100644 --- a/src/ui/annotatorwidget.h +++ b/src/ui/annotatorwidget.h @@ -39,7 +39,7 @@ public: ~AnnotatorWidget() override; public: - QVector importObjects(const QString &filepath, marK::OutputType output_type); + QVector importObjects(const QString &filepath); bool saveObjects(const QString &filepath, marK::OutputType output_type); void setAutoSaveFilePath(const QString &str); diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index fa602bc..c93a434 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -301,14 +301,7 @@ void marK::importData() // TODO: fix crash when there is no image loaded QVector markedClasses; - // TODO: remove these if and else - if (filepath.endsWith(".json")) { - markedClasses = m_ui->annotatorWidget->importObjects(filepath, OutputType::JSON); - } - - else if (filepath.endsWith(".xml")) { - markedClasses = m_ui->annotatorWidget->importObjects(filepath, OutputType::XML); - } + markedClasses = m_ui->annotatorWidget->importObjects(filepath); if (markedClasses.isEmpty()) { QMessageBox msgBox; @@ -319,7 +312,6 @@ void marK::importData() } // add new classes to comboBox - // TODO: verify class name, if equal do not add for (MarkedClass *markedClass : qAsConst(markedClasses)) { addNewClass(markedClass); } @@ -362,7 +354,7 @@ void marK::retrieveTempFile() QString tempFilePath = Serializer::getTempFileName(m_filepath); QVector markedClasses; - markedClasses = m_ui->annotatorWidget->importObjects(tempFilePath, OutputType::JSON); + markedClasses = m_ui->annotatorWidget->importObjects(tempFilePath); for (MarkedClass *markedClass : qAsConst(markedClasses)) { addNewClass(markedClass); diff --git a/src/ui/serializer.cpp b/src/ui/serializer.cpp index 69bfb6d..eff626f 100644 --- a/src/ui/serializer.cpp +++ b/src/ui/serializer.cpp @@ -38,17 +38,16 @@ Serializer::Serializer(const QVector items) : { } -QVector Serializer::read(marK::OutputType output_type) +QVector Serializer::read() { QVector objects; - m_output_type = output_type; bool fileExists = QFile::exists(m_filepath); if (fileExists) { - if (output_type == marK::OutputType::XML) { + if (m_filepath.endsWith(".xml")) { objects = this->readXML(); } - else if (output_type == marK::OutputType::JSON) { + else if (m_filepath.endsWith(".json")) { objects = this->readJSON(); } } diff --git a/src/ui/serializer.h b/src/ui/serializer.h index dd9c9af..8a988dd 100644 --- a/src/ui/serializer.h +++ b/src/ui/serializer.h @@ -33,7 +33,7 @@ public: bool write(const QString &filepath, marK::OutputType output_type); - QVector read(marK::OutputType output_type); + QVector read(); static QString getTempFileName(const QString &filepath); static QString handleFileNameExtension(const QString &str, marK::OutputType output_type = marK::OutputType::JSON); @@ -52,6 +52,5 @@ private: // put it to work with MarkedObject QVector m_items; QString m_filepath; - marK::OutputType m_output_type; }; #endif // SERIALIZER_H -- GitLab From ea076783eae13a33fe6890d6f1cb42b4de0efd53 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Mon, 10 Feb 2020 14:37:48 -0300 Subject: [PATCH 23/29] dont execute importData function if no file is currently loaded --- src/ui/mark.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index c93a434..2b75e5e 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -239,6 +239,7 @@ void marK::changeDirectory() m_watcher->addPath(m_currentDirectory); m_ui->listWidget->clear(); m_currentIndex = -1; + m_filepath.clear(); updateFiles(); QFontMetrics metrics(m_ui->listLabel->font()); @@ -295,10 +296,11 @@ void marK::savePolygons(OutputType type) void marK::importData() { + if (m_filepath.isEmpty()) return; //exiting because this is no image loaded + QString filepath = QFileDialog::getOpenFileName(this, "Select File", QDir::homePath(), "JSON and XML files (*.json *.xml)"); - // TODO: fix crash when there is no image loaded QVector markedClasses; markedClasses = m_ui->annotatorWidget->importObjects(filepath); -- GitLab From 264a2a1a2cb3e8a65798eec5b7abd13fff096344 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Tue, 11 Feb 2020 14:11:19 -0300 Subject: [PATCH 24/29] simplifying implementation --- src/ui/mark.cpp | 51 +++++++++++++++---------------------------------- src/ui/mark.h | 2 -- 2 files changed, 15 insertions(+), 38 deletions(-) diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 2b75e5e..d8b9a04 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -40,7 +40,6 @@ marK::marK(QWidget *parent) : m_ui(new Ui::marK), m_watcher(new QFileSystemWatcher(this)), m_currentDirectory(""), - m_currentIndex(-1), m_autoSaveJsonIsEnabled(false), m_autoSaveXmlIsEnabled(false) { @@ -135,14 +134,6 @@ void marK::updateFiles() void marK::updateFiles(const QString &path) { - QListWidgetItem *previousSelectedItem = m_ui->listWidget->currentItem(); - QString previousText; - if (previousSelectedItem != nullptr) { - previousText = previousSelectedItem->text(); - } - - m_ui->listWidget->clear(); - QDir resDirectory(path); QStringList items = resDirectory.entryList(QStringList() << "*.jpg" << "*.jpeg" << "*.JPG" << "*.JPEG" << "*.png" << "*.PNG" << "*.txt" << "*.TXT", QDir::Files); @@ -161,43 +152,29 @@ void marK::updateFiles(const QString &path) QListWidgetItem *itemW = new QListWidgetItem(item_pix, item); m_ui->listWidget->addItem(itemW); - - if (!previousText.isEmpty() && previousText == item) { - int currentIndex = m_ui->listWidget->count() - 1; - m_currentIndex = currentIndex; - changeItem(); - } - } - - if (previousText.isEmpty()) { - m_ui->annotatorWidget->clearScene(); } } void marK::goToNextItem() { - m_currentIndex += 1; - if (m_currentIndex >= m_ui->listWidget->count()) { - m_currentIndex = 0; + int newIndex = m_ui->listWidget->currentRow() + 1; + if (newIndex >= m_ui->listWidget->count()) { + newIndex = 0; } - changeItem(); + m_ui->listWidget->setCurrentRow(newIndex); + QListWidgetItem *currentItem = m_ui->listWidget->item(newIndex); + changeItem(currentItem, nullptr); } void marK::goToPreviousItem() { - m_currentIndex -= 1; - if (m_currentIndex < 0) { - m_currentIndex = m_ui->listWidget->count() - 1; + int newIndex = m_ui->listWidget->currentRow() - 1; + if (newIndex < 0) { + newIndex = m_ui->listWidget->count() - 1; } - - changeItem(); -} - -void marK::changeItem() -{ - m_ui->listWidget->setCurrentRow(m_currentIndex); - QListWidgetItem *currentItem = m_ui->listWidget->item(m_currentIndex); + m_ui->listWidget->setCurrentRow(newIndex); + QListWidgetItem *currentItem = m_ui->listWidget->item(newIndex); changeItem(currentItem, nullptr); } @@ -208,7 +185,6 @@ void marK::changeItem(QListWidgetItem *current, QListWidgetItem *previous) QString itemPath = QDir(m_currentDirectory).filePath(current->text()); if (itemPath != m_filepath) { - m_currentIndex = m_ui->listWidget->currentRow(); makeTempFile(); m_filepath = itemPath; m_ui->annotatorWidget->changeItem(itemPath); @@ -231,14 +207,17 @@ void marK::changeDirectory() QString path = QFileDialog::getExistingDirectory(this, "Select Directory", QDir::homePath(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + if (m_currentDirectory == path) + return; + if (!path.isEmpty()) { if (m_currentDirectory != "") { m_watcher->removePath(m_currentDirectory); } m_currentDirectory = path; m_watcher->addPath(m_currentDirectory); + m_ui->annotatorWidget->clearScene(); m_ui->listWidget->clear(); - m_currentIndex = -1; m_filepath.clear(); updateFiles(); diff --git a/src/ui/mark.h b/src/ui/mark.h index 4e33a75..d2e0aee 100644 --- a/src/ui/mark.h +++ b/src/ui/mark.h @@ -50,7 +50,6 @@ public: public: void changeDirectory(); - void changeItem(); void changeShape(marK::Shape shape); void updateFiles(); void savePolygons(OutputType type); @@ -78,7 +77,6 @@ private: QString m_filepath; QVector m_polygonClasses; QVector m_tempFiles; - int m_currentIndex; bool m_autoSaveJsonIsEnabled; bool m_autoSaveXmlIsEnabled; }; -- GitLab From 11fcbbc85445cd78f30a3e46772850d3c5d22c0d Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Tue, 11 Feb 2020 14:53:57 -0300 Subject: [PATCH 25/29] handling temporary files better --- src/ui/mark.cpp | 18 ++++++++---------- src/ui/mark.h | 1 - src/ui/serializer.cpp | 3 ++- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index d8b9a04..89a090e 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -321,13 +321,13 @@ void marK::addNewClass(MarkedClass *markedClass) void marK::makeTempFile() { - QString tempFilePath = Serializer::getTempFileName(m_filepath); + QDir tempDir = QDir::tempPath(); + if (!tempDir.exists("mark")) + tempDir.mkdir("mark"); - bool success = m_ui->annotatorWidget->saveObjects(tempFilePath, OutputType::JSON); + QString tempFilePath = Serializer::getTempFileName(m_filepath); - if (success) { - m_tempFiles.append(tempFilePath); - } + m_ui->annotatorWidget->saveObjects(tempFilePath, OutputType::JSON); } void marK::retrieveTempFile() @@ -359,9 +359,7 @@ void marK::toggleAutoSaveXml() marK::~marK() { - // cleaning temp files - for (const QString &filename : qAsConst(m_tempFiles)) { - QFile tempfile(filename); - tempfile.remove(); - } + QDir tempDir = QDir::tempPath(); + if (tempDir.exists("mark")) + tempDir.removeRecursively(); } diff --git a/src/ui/mark.h b/src/ui/mark.h index d2e0aee..c8791cc 100644 --- a/src/ui/mark.h +++ b/src/ui/mark.h @@ -76,7 +76,6 @@ private: QString m_currentDirectory; QString m_filepath; QVector m_polygonClasses; - QVector m_tempFiles; bool m_autoSaveJsonIsEnabled; bool m_autoSaveXmlIsEnabled; }; diff --git a/src/ui/serializer.cpp b/src/ui/serializer.cpp index eff626f..48125d6 100644 --- a/src/ui/serializer.cpp +++ b/src/ui/serializer.cpp @@ -282,11 +282,12 @@ bool Serializer::write(const QString &filepath, marK::OutputType output_type) QString Serializer::getTempFileName(const QString &filepath) { QString tempFileName = filepath; + tempFileName.remove(0, 1); tempFileName = handleFileNameExtension(tempFileName); tempFileName.replace("/", "_"); - tempFileName.prepend(QDir::tempPath() + "/mark"); + tempFileName.prepend(QDir::tempPath() + "/mark/"); return tempFileName; } -- GitLab From 0654517b616f2c7fb5a1b53478a0b02cad194430 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Tue, 11 Feb 2020 15:10:17 -0300 Subject: [PATCH 26/29] replacing static_cast on function pointers to qOverload --- src/ui/mark.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 89a090e..9c95b19 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -93,10 +93,10 @@ marK::marK(QWidget *parent) : addNewClass(); connect(m_ui->listWidget, &QListWidget::currentItemChanged, this, - static_cast(&marK::changeItem)); + qOverload(&marK::changeItem)); connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, - static_cast(&marK::updateFiles)); + qOverload(&marK::updateFiles)); connect(m_ui->newClassButton, &QPushButton::clicked, this, qOverload<>(&marK::addNewClass)); -- GitLab From 8815d142dd7b79c3a1bea75aaef147178a7a6159 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Tue, 11 Feb 2020 16:25:14 -0300 Subject: [PATCH 27/29] turn static method to private and fix behavior update function --- src/ui/mark.cpp | 3 ++- src/ui/serializer.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 9c95b19..330a910 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -134,6 +134,8 @@ void marK::updateFiles() void marK::updateFiles(const QString &path) { + m_ui->listWidget->clear(); + QDir resDirectory(path); QStringList items = resDirectory.entryList(QStringList() << "*.jpg" << "*.jpeg" << "*.JPG" << "*.JPEG" << "*.png" << "*.PNG" << "*.txt" << "*.TXT", QDir::Files); @@ -217,7 +219,6 @@ void marK::changeDirectory() m_currentDirectory = path; m_watcher->addPath(m_currentDirectory); m_ui->annotatorWidget->clearScene(); - m_ui->listWidget->clear(); m_filepath.clear(); updateFiles(); diff --git a/src/ui/serializer.h b/src/ui/serializer.h index 8a988dd..30d39ea 100644 --- a/src/ui/serializer.h +++ b/src/ui/serializer.h @@ -36,7 +36,6 @@ public: QVector read(); static QString getTempFileName(const QString &filepath); - static QString handleFileNameExtension(const QString &str, marK::OutputType output_type = marK::OutputType::JSON); private: QByteArray getData(); @@ -47,6 +46,7 @@ private: QVector readXML(); QString serialize(marK::OutputType output_type); + static QString handleFileNameExtension(const QString &str, marK::OutputType output_type = marK::OutputType::JSON); private: // put it to work with MarkedObject -- GitLab From 0a8d3bca70759ada1a3eeb56157e87eafcada684 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Wed, 12 Feb 2020 22:50:20 -0300 Subject: [PATCH 28/29] refator, simplify auto save feature --- src/ui/annotatorwidget.cpp | 13 ++++----- src/ui/annotatorwidget.h | 7 ++--- src/ui/mark.cpp | 56 ++++++++++++++++++++++++-------------- src/ui/mark.h | 7 ++--- 4 files changed, 46 insertions(+), 37 deletions(-) diff --git a/src/ui/annotatorwidget.cpp b/src/ui/annotatorwidget.cpp index 21d96a3..c47bf42 100644 --- a/src/ui/annotatorwidget.cpp +++ b/src/ui/annotatorwidget.cpp @@ -30,8 +30,7 @@ AnnotatorWidget::AnnotatorWidget(QWidget* parent): m_scaleW(0.0), m_scaleH(0.0), m_autoSaveFilePath(""), - m_autoSaveJsonIsEnabled(false), - m_autoSaveXmlIsEnabled(false) + m_autoSaveType(marK::OutputType::None) { m_ui->setupUi(this); @@ -138,11 +137,8 @@ void AnnotatorWidget::paintPolygon(Polygon &polygon) m_items << pol; - if (m_autoSaveJsonIsEnabled) { - saveObjects(m_autoSaveFilePath, marK::OutputType::JSON); - } - if (m_autoSaveXmlIsEnabled) { - saveObjects(m_autoSaveFilePath, marK::OutputType::XML); + if (m_autoSaveType != marK::OutputType::None) { + saveObjects(m_autoSaveFilePath, m_autoSaveType); } } else { @@ -267,7 +263,8 @@ QVector AnnotatorWidget::importObjects(const QString &filepath) return markedClasses; } -void AnnotatorWidget::setAutoSaveFilePath(const QString &str) +void AnnotatorWidget::setAutoSaveFile(const QString &str, marK::OutputType outputType) { m_autoSaveFilePath = str; + m_autoSaveType = outputType; } diff --git a/src/ui/annotatorwidget.h b/src/ui/annotatorwidget.h index 557e602..f56ad07 100644 --- a/src/ui/annotatorwidget.h +++ b/src/ui/annotatorwidget.h @@ -42,9 +42,7 @@ public: QVector importObjects(const QString &filepath); bool saveObjects(const QString &filepath, marK::OutputType output_type); - void setAutoSaveFilePath(const QString &str); - void toggleAutoSaveJson() { m_autoSaveJsonIsEnabled = !m_autoSaveJsonIsEnabled; }; - void toggleAutoSaveXml() { m_autoSaveXmlIsEnabled = !m_autoSaveXmlIsEnabled; }; + void setAutoSaveFile(const QString &str, marK::OutputType outputType); void mousePressEvent(QMouseEvent* event) override; @@ -73,8 +71,7 @@ private: qreal m_scaleH; QString m_autoSaveFilePath; - bool m_autoSaveJsonIsEnabled; - bool m_autoSaveXmlIsEnabled; + marK::OutputType m_autoSaveType; }; #endif // ANNOTATORWIDGET_H diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 330a910..2f13d10 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -20,6 +20,7 @@ #include "serializer.h" #include +#include #include #include #include @@ -40,8 +41,7 @@ marK::marK(QWidget *parent) : m_ui(new Ui::marK), m_watcher(new QFileSystemWatcher(this)), m_currentDirectory(""), - m_autoSaveJsonIsEnabled(false), - m_autoSaveXmlIsEnabled(false) + m_autoSaveType(OutputType::None) { m_ui->setupUi(this); @@ -71,13 +71,23 @@ marK::marK(QWidget *parent) : QMenu *autoSaveMenu = editMenu->addMenu("Auto Save"); - QAction *enableAutoSaveJson = autoSaveMenu->addAction("JSON"); - enableAutoSaveJson->setCheckable(true); - connect(enableAutoSaveJson, &QAction::toggled, this, &marK::toggleAutoSaveJson); + QActionGroup *autoSaveActionGroup = new QActionGroup(this); - QAction *enableAutoSaveXml = autoSaveMenu->addAction("XML"); - enableAutoSaveXml->setCheckable(true); - connect(enableAutoSaveXml, &QAction::toggled, this, &marK::toggleAutoSaveXml); + QAction *autoSaveJsonButton = autoSaveMenu->addAction("JSON"); + autoSaveJsonButton->setCheckable(true); + connect(autoSaveJsonButton, &QAction::triggered, this, &marK::toggleAutoSave); + autoSaveJsonButton->setActionGroup(autoSaveActionGroup); + + QAction *autoSaveXmlButton = autoSaveMenu->addAction("XML"); + autoSaveXmlButton->setCheckable(true); + connect(autoSaveXmlButton, &QAction::triggered, this, &marK::toggleAutoSave); + autoSaveXmlButton->setActionGroup(autoSaveActionGroup); + + QAction *autoSaveDisableButton = autoSaveMenu->addAction("Disabled"); + autoSaveDisableButton->setCheckable(true); + autoSaveDisableButton->setChecked(true); + connect(autoSaveDisableButton, &QAction::triggered, this, &marK::toggleAutoSave); + autoSaveDisableButton->setActionGroup(autoSaveActionGroup); QShortcut *nextItemShortcut = new QShortcut(this); nextItemShortcut->setKey(Qt::Key_Down); @@ -192,8 +202,8 @@ void marK::changeItem(QListWidgetItem *current, QListWidgetItem *previous) m_ui->annotatorWidget->changeItem(itemPath); retrieveTempFile(); - if (m_autoSaveJsonIsEnabled || m_autoSaveXmlIsEnabled) { - m_ui->annotatorWidget->setAutoSaveFilePath(itemPath); + if (m_autoSaveType != OutputType::None) { + m_ui->annotatorWidget->setAutoSaveFile(itemPath, m_autoSaveType); } } } @@ -344,18 +354,24 @@ void marK::retrieveTempFile() m_ui->annotatorWidget->repaint(); } -void marK::toggleAutoSaveJson() +void marK::toggleAutoSave() { - m_ui->annotatorWidget->setAutoSaveFilePath(m_filepath); - m_ui->annotatorWidget->toggleAutoSaveJson(); - m_autoSaveJsonIsEnabled = !m_autoSaveJsonIsEnabled; -} + QAction *button = qobject_cast(sender()); + QString type = button->text(); + if (type == "Disabled") { + m_ui->annotatorWidget->setAutoSaveFile("", OutputType::None); + m_autoSaveType = OutputType::None; + } -void marK::toggleAutoSaveXml() -{ - m_ui->annotatorWidget->setAutoSaveFilePath(m_filepath); - m_ui->annotatorWidget->toggleAutoSaveXml(); - m_autoSaveXmlIsEnabled = !m_autoSaveXmlIsEnabled; + else if (type == "XML") { + m_ui->annotatorWidget->setAutoSaveFile(m_filepath, OutputType::XML); + m_autoSaveType = OutputType::XML; + } + + else if (type == "JSON") { + m_ui->annotatorWidget->setAutoSaveFile(m_filepath, OutputType::JSON); + m_autoSaveType = OutputType::JSON; + } } marK::~marK() diff --git a/src/ui/mark.h b/src/ui/mark.h index c8791cc..e586c31 100644 --- a/src/ui/mark.h +++ b/src/ui/mark.h @@ -35,6 +35,7 @@ class marK : public QMainWindow public: enum class OutputType { + None, XML, JSON }; @@ -67,8 +68,7 @@ public slots: void importData(); void goToNextItem(); void goToPreviousItem(); - void toggleAutoSaveJson(); - void toggleAutoSaveXml(); + void toggleAutoSave(); private: QScopedPointer m_ui; @@ -76,8 +76,7 @@ private: QString m_currentDirectory; QString m_filepath; QVector m_polygonClasses; - bool m_autoSaveJsonIsEnabled; - bool m_autoSaveXmlIsEnabled; + OutputType m_autoSaveType; }; #endif // MARK_H -- GitLab From 00442248875acd649ef80ae6984e1afec6a71459 Mon Sep 17 00:00:00 2001 From: Jean Lima Andrade Date: Thu, 13 Feb 2020 08:55:27 -0300 Subject: [PATCH 29/29] actual fix of updateFiles function related --- src/ui/mark.cpp | 12 ++++++++---- src/ui/mark.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ui/mark.cpp b/src/ui/mark.cpp index 2f13d10..1bb9ccf 100644 --- a/src/ui/mark.cpp +++ b/src/ui/mark.cpp @@ -106,7 +106,7 @@ marK::marK(QWidget *parent) : qOverload(&marK::changeItem)); connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, - qOverload(&marK::updateFiles)); + [=](){ marK::updateFiles(); }); connect(m_ui->newClassButton, &QPushButton::clicked, this, qOverload<>(&marK::addNewClass)); @@ -139,10 +139,11 @@ marK::marK(QWidget *parent) : void marK::updateFiles() { - updateFiles(m_currentDirectory); + int currentIndex = m_ui->listWidget->currentRow(); + updateFiles(m_currentDirectory, currentIndex); } -void marK::updateFiles(const QString &path) +void marK::updateFiles(const QString &path, const int index) { m_ui->listWidget->clear(); @@ -165,6 +166,9 @@ void marK::updateFiles(const QString &path) QListWidgetItem *itemW = new QListWidgetItem(item_pix, item); m_ui->listWidget->addItem(itemW); } + + if (index >= 0) + m_ui->listWidget->setCurrentRow(index); } void marK::goToNextItem() @@ -230,7 +234,7 @@ void marK::changeDirectory() m_watcher->addPath(m_currentDirectory); m_ui->annotatorWidget->clearScene(); m_filepath.clear(); - updateFiles(); + updateFiles(path); QFontMetrics metrics(m_ui->listLabel->font()); QString elidedText = metrics.elidedText(m_currentDirectory, Qt::ElideMiddle, diff --git a/src/ui/mark.h b/src/ui/mark.h index e586c31..d9ca1ef 100644 --- a/src/ui/mark.h +++ b/src/ui/mark.h @@ -60,7 +60,7 @@ public: public slots: void changeItem(QListWidgetItem *current, QListWidgetItem *previous); - void updateFiles(const QString &path); + void updateFiles(const QString &path, const int index = -1); void addNewClass(); void selectClassColor(); void saveToJson() { savePolygons(OutputType::JSON); }; -- GitLab