File indexing completed on 2024-04-21 03:50:55
0001 /************************************************************************* 0002 * Copyright (C) 2020 by Jean Lima Andrade <jeno.andrade@gmail.com> * 0003 * * 0004 * This program is free software; you can redistribute it and/or * 0005 * modify it under the terms of the GNU General Public License as * 0006 * published by the Free Software Foundation; either version 3 of * 0007 * the License, or (at your option) any later version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, * 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0012 * GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License * 0015 * along with this program. If not, see <http://www.gnu.org/licenses/>.* 0016 *************************************************************************/ 0017 0018 #include "core/markedclass.h" 0019 #include "core/serializer.h" 0020 #include "image/polygon.h" 0021 #include "text/sentence.h" 0022 #include "util/fileutils.h" 0023 0024 #include <memory> 0025 0026 #include <QDir> 0027 #include <QFile> 0028 #include <QHash> 0029 #include <QJsonArray> 0030 #include <QJsonDocument> 0031 #include <QJsonObject> 0032 #include <QRegularExpression> 0033 #include <QtGlobal> 0034 #include <QXmlStreamWriter> 0035 0036 QVector<MarkedObject*> Serializer::read(const QString& filepath) 0037 { 0038 QVector<MarkedObject*> objects; 0039 0040 if (QFile::exists(filepath)) { 0041 if (filepath.endsWith(".xml")) 0042 objects = readXML(filepath); 0043 else if (filepath.endsWith(".json")) 0044 objects = readJSON(filepath); 0045 } 0046 0047 return objects; 0048 } 0049 0050 QString Serializer::serialize(const QVector<MarkedObject*>& objects, OutputType outputType) 0051 { 0052 if (outputType == OutputType::XML) 0053 return toXML(objects); 0054 0055 else if (outputType == OutputType::JSON) 0056 return toJSON(objects); 0057 0058 return QString(); 0059 } 0060 0061 QString Serializer::toXML(const QVector<MarkedObject*>& objects) 0062 { 0063 if (objects.isEmpty()) 0064 return QString(); 0065 0066 QString xmldoc; 0067 0068 QXmlStreamWriter xmlWriter(&xmldoc); 0069 xmlWriter.setAutoFormatting(true); 0070 xmlWriter.writeStartDocument(); 0071 xmlWriter.writeStartElement("annotation"); 0072 0073 auto writeXMLObject = [&](const QString& unitName, int x, int y) { 0074 xmlWriter.writeStartElement(unitName); 0075 0076 xmlWriter.writeStartElement("x"); 0077 xmlWriter.writeCharacters(QString::number(x)); 0078 xmlWriter.writeEndElement(); 0079 0080 xmlWriter.writeStartElement("y"); 0081 xmlWriter.writeCharacters(QString::number(y)); 0082 xmlWriter.writeEndElement(); 0083 0084 xmlWriter.writeEndElement(); 0085 }; 0086 0087 for (MarkedObject* object : objects) { 0088 xmlWriter.writeStartElement("object"); 0089 0090 xmlWriter.writeStartElement("class"); 0091 xmlWriter.writeCharacters(object->objClass()->name()); 0092 xmlWriter.writeEndElement(); 0093 0094 if (object->type() == MarkedObject::Type::Sentence) { 0095 const Sentence *sentence = static_cast<const Sentence*>(object); 0096 writeXMLObject(sentence->unitName(), sentence->begin(), sentence->end()); 0097 } 0098 else if (object->type() == MarkedObject::Type::Polygon) { 0099 const Polygon *polygon = static_cast<const Polygon*>(object); 0100 xmlWriter.writeStartElement("Polygon"); 0101 for (const QPointF& point : *polygon) 0102 writeXMLObject(polygon->unitName(), point.x(), point.y()); 0103 xmlWriter.writeEndElement(); 0104 } 0105 0106 xmlWriter.writeEndElement(); 0107 } 0108 0109 xmlWriter.writeEndElement(); 0110 0111 xmlWriter.writeEndElement(); 0112 xmlWriter.writeEndDocument(); 0113 0114 return xmldoc; 0115 } 0116 0117 QString Serializer::toJSON(const QVector<MarkedObject*>& objects) 0118 { 0119 if (objects.isEmpty()) 0120 return QString(); 0121 0122 QJsonArray classesArray; 0123 0124 auto createUnitObject = [](int x, int y) { 0125 QJsonObject unitObject; 0126 unitObject.insert("x", QString::number(x)); 0127 unitObject.insert("y", QString::number(y)); 0128 return unitObject; 0129 }; 0130 0131 for (MarkedObject* object : objects) { 0132 QJsonObject recordObject; 0133 recordObject.insert("Class", object->objClass()->name()); 0134 0135 if (object->type() == MarkedObject::Type::Sentence) { 0136 const Sentence *sentence = static_cast<const Sentence*>(object); 0137 QJsonObject unitObject = createUnitObject(sentence->begin(), sentence->end()); 0138 recordObject.insert(object->unitName(), unitObject); 0139 } 0140 else if (object->type() == MarkedObject::Type::Polygon) { 0141 QJsonArray objectsArray; 0142 0143 const Polygon *polygon = static_cast<const Polygon*>(object); 0144 for (const QPointF& point : *polygon) { 0145 QJsonObject unitObject = createUnitObject(point.x(), point.y()); 0146 QJsonObject markedObject; 0147 markedObject.insert(object->unitName(), unitObject); 0148 objectsArray.push_back(markedObject); 0149 } 0150 0151 recordObject.insert("Polygon", objectsArray); 0152 } 0153 0154 classesArray.push_back(recordObject); 0155 } 0156 0157 return QJsonDocument(classesArray).toJson(); 0158 } 0159 0160 QVector<MarkedObject*> Serializer::readJSON(const QString& filepath) 0161 { 0162 QVector<MarkedObject*> savedObjects; 0163 QHash<QString, MarkedClass*> markedClasses; 0164 0165 QByteArray data = getData(filepath); 0166 QJsonDocument doc = QJsonDocument::fromJson(data); 0167 0168 QJsonArray objectArray = doc.array(); 0169 0170 for (const QJsonValue& jsonObj : qAsConst(objectArray)) { 0171 QString className = jsonObj["Class"].toString(); 0172 0173 MarkedObject::Type objectType; 0174 if (jsonObj["st"] != QJsonValue::Undefined) 0175 objectType = MarkedObject::Type::Sentence; 0176 else if (jsonObj["Polygon"] != QJsonValue::Undefined) 0177 objectType = MarkedObject::Type::Polygon; 0178 0179 if (!markedClasses.contains(className)) 0180 markedClasses[className] = new MarkedClass(className); 0181 0182 MarkedObject* object = nullptr; 0183 if (objectType == MarkedObject::Type::Sentence) { 0184 QJsonObject sentenceObj = jsonObj["st"].toObject(); 0185 object = new Sentence(markedClasses[className], sentenceObj["x"].toString().toDouble(), sentenceObj["y"].toString().toDouble()); 0186 } 0187 else if (objectType == MarkedObject::Type::Polygon) { 0188 QVector<QPointF> polygonPoints; 0189 for (const QJsonValue& unitObj : jsonObj["Polygon"].toArray()) { 0190 QJsonObject pointJson = unitObj["pt"].toObject(); 0191 QPointF pointObj(pointJson["x"].toString().toDouble(), pointJson["y"].toString().toDouble()); 0192 polygonPoints << pointObj; 0193 } 0194 object = new Polygon(markedClasses[className], polygonPoints); 0195 } 0196 0197 if (object != nullptr) 0198 savedObjects << object; 0199 } 0200 0201 return savedObjects; 0202 } 0203 0204 QVector<MarkedObject*> Serializer::readXML(const QString& filepath) 0205 { 0206 QVector<MarkedObject*> savedObjects; 0207 QHash<QString, MarkedClass*> markedClasses; 0208 0209 QByteArray data = getData(filepath); 0210 0211 QXmlStreamReader xmlReader(data); 0212 xmlReader.readNextStartElement(); 0213 0214 auto readNextXY = [&]() { 0215 xmlReader.readNextStartElement(); 0216 double x = xmlReader.readElementText().toDouble(); 0217 xmlReader.readNextStartElement(); 0218 double y = xmlReader.readElementText().toDouble(); 0219 xmlReader.skipCurrentElement(); 0220 0221 return QPair<int, int>(x, y); 0222 }; 0223 0224 while (!xmlReader.atEnd()) { 0225 QXmlStreamReader::TokenType token = xmlReader.readNext(); 0226 if (token == QXmlStreamReader::StartElement) { 0227 xmlReader.readNextStartElement(); 0228 0229 QString className = xmlReader.readElementText(); 0230 0231 if (!markedClasses.contains(className)) 0232 markedClasses[className] = new MarkedClass(className); 0233 0234 xmlReader.readNextStartElement(); 0235 0236 MarkedObject* object; 0237 if (xmlReader.name() == "Polygon") { 0238 QVector<QPointF> polygonPoints; 0239 0240 while (xmlReader.name() != "object") { 0241 if (xmlReader.name() == "pt") { 0242 QPair<int, int> pointXY = readNextXY(); 0243 polygonPoints << QPointF(pointXY.first, pointXY.second); 0244 } 0245 xmlReader.readNextStartElement(); 0246 } 0247 0248 object = new Polygon(markedClasses[className], polygonPoints); 0249 } 0250 else if (xmlReader.name() == "st") { 0251 QPair<int, int> sentenceBeginEnd = readNextXY(); 0252 object = new Sentence(markedClasses[className], sentenceBeginEnd.first, sentenceBeginEnd.second); 0253 } 0254 0255 savedObjects << object; 0256 } 0257 } 0258 0259 return savedObjects; 0260 } 0261 0262 QByteArray Serializer::getData(const QString& filepath) 0263 { 0264 QFile file(filepath); 0265 file.open(QIODevice::ReadOnly|QIODevice::Text); 0266 QByteArray data = file.readAll(); 0267 file.close(); 0268 0269 return data; 0270 } 0271 0272 bool Serializer::write(const QString &filepath, const QVector<MarkedObject*>& objects, OutputType outputType) 0273 { 0274 if (!objects.isEmpty()) { 0275 QString document = serialize(objects, outputType); 0276 0277 if (!document.isEmpty()) { 0278 QString outputFilename = FileUtils::placeSuffix(filepath, outputType); 0279 QFile file(outputFilename); 0280 if (file.open(QIODevice::WriteOnly|QIODevice::Text)) 0281 return file.write(document.toUtf8()) != -1; 0282 } 0283 } 0284 0285 return false; 0286 }