1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
10 #include "VOCAnnotationParser.hpp"
12 #include "user_exception.hpp"
14 std::string VOCAnnotationParser::parseString(const pugi::xml_node& node, const std::string& def) {
15 if (node && node.child_value()) {
16 return node.child_value();
22 int VOCAnnotationParser::parseInt(const pugi::xml_node& node, const int def) {
23 if (!node) return def;
24 std::string val = parseString(node);
26 return std::stoi(val);
27 } catch (const std::invalid_argument&) {
28 THROW_USER_EXCEPTION(1) << "Can't convert node <" << node.name()
29 << "> value \"" << val << "\" to integer";
33 bool VOCAnnotationParser::parseBool(const pugi::xml_node& node, bool def) {
34 if (!node) return def;
35 std::string val = parseString(node);
36 if (val == "1") return true;
37 if (val == "0") return false;
39 THROW_USER_EXCEPTION(1) << "Can't convert node <" << node.name()
40 << "> value \"" << val << "\" to boolean";
44 VOCAnnotation VOCAnnotationParser::parse(const std::string& filename) {
48 xml_parse_result result = doc.load_file(filename.c_str());
50 if (result.status != pugi::status_ok) {
51 throw UserException(result.status)
52 << "parsing failed at offset " << result.offset << ": " << result.description();
55 xml_node annNode = doc.child("annotation");
57 THROW_USER_EXCEPTION(1) << "No root <annotation> tag";
62 ann.filename = parseString(annNode.child("filename"));
63 ann.folder = parseString(annNode.child("folder"));
64 ann.segmented = parseBool(annNode.child("segmented"));
66 xml_node sizeNode = annNode.child("size");
67 ann.size.depth = parseInt(sizeNode.child("depth"));
68 ann.size.height = parseInt(sizeNode.child("height"));
69 ann.size.width = parseInt(sizeNode.child("width"));
71 xml_node sourceNode = annNode.child("source");
72 ann.source.annotation = parseString(sourceNode.child("annotation"));
73 ann.source.database = parseString(sourceNode.child("database"));
74 ann.source.image = parseString(sourceNode.child("image"));
77 for (xml_node objNode = annNode.child("object"); objNode; objNode = objNode.next_sibling("object")) {
79 obj.name = parseString(objNode.child("name"));
80 obj.difficult = parseBool(objNode.child("difficult"));
81 obj.occluded = parseBool(objNode.child("occluded"));
82 obj.pose = parseString(objNode.child("pose"));
83 obj.truncated = parseBool(objNode.child("truncated"));
85 xml_node bndboxNode = objNode.child("bndbox");
86 obj.bndbox.xmin = parseInt(bndboxNode.child("xmin"));
87 obj.bndbox.xmax = parseInt(bndboxNode.child("xmax"));
88 obj.bndbox.ymin = parseInt(bndboxNode.child("ymin"));
89 obj.bndbox.ymax = parseInt(bndboxNode.child("ymax"));
91 ann.objects.push_back(obj);
94 catch (const std::invalid_argument& e) {
95 THROW_USER_EXCEPTION(1) << "conversion error: " << e.what();
101 VOCAnnotationParser::~VOCAnnotationParser() {
104 inline bool ends_with(std::string const & value, std::string const & ending) {
105 if (ending.size() > value.size()) return false;
106 return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
109 VOCAnnotationCollector::VOCAnnotationCollector(const std::string& path) {
110 VOCAnnotationParser parser;
111 if (ends_with(path, ".xml")) {
113 _annotations.push_back(parser.parse(path));
115 std::list<std::string> baseDirContents = getDirContents(path, true);
116 for (const auto& sub : baseDirContents) {
117 std::list<std::string> annotationDirContents = getDirContents(sub, true);
118 if (annotationDirContents.size() == 0 && ends_with(sub, ".xml")) {
119 _annotations.push_back(parser.parse(sub));
121 for (const auto& file : annotationDirContents) {
122 if (ends_with(file, ".xml")) {
123 _annotations.push_back(parser.parse(file));