diff options
Diffstat (limited to 'ml/dlib/tools/imglab/src/convert_pascal_xml.cpp')
-rw-r--r-- | ml/dlib/tools/imglab/src/convert_pascal_xml.cpp | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/ml/dlib/tools/imglab/src/convert_pascal_xml.cpp b/ml/dlib/tools/imglab/src/convert_pascal_xml.cpp new file mode 100644 index 000000000..c699d7777 --- /dev/null +++ b/ml/dlib/tools/imglab/src/convert_pascal_xml.cpp @@ -0,0 +1,239 @@ + +#include "convert_pascal_xml.h" +#include "dlib/data_io.h" +#include <iostream> +#include <dlib/xml_parser.h> +#include <string> +#include <dlib/dir_nav.h> +#include <dlib/cmd_line_parser.h> + +using namespace std; +using namespace dlib; + +namespace +{ + using namespace dlib::image_dataset_metadata; + +// ---------------------------------------------------------------------------------------- + + class doc_handler : public document_handler + { + image& temp_image; + std::string& dataset_name; + + std::vector<std::string> ts; + box temp_box; + + public: + + doc_handler( + image& temp_image_, + std::string& dataset_name_ + ): + temp_image(temp_image_), + dataset_name(dataset_name_) + {} + + + virtual void start_document ( + ) + { + ts.clear(); + temp_image = image(); + temp_box = box(); + dataset_name.clear(); + } + + virtual void end_document ( + ) + { + } + + virtual void start_element ( + const unsigned long , + const std::string& name, + const dlib::attribute_list& + ) + { + if (ts.size() == 0 && name != "annotation") + { + std::ostringstream sout; + sout << "Invalid XML document. Root tag must be <annotation>. Found <" << name << "> instead."; + throw dlib::error(sout.str()); + } + + + ts.push_back(name); + } + + virtual void end_element ( + const unsigned long , + const std::string& name + ) + { + ts.pop_back(); + if (ts.size() == 0) + return; + + if (name == "object" && ts.back() == "annotation") + { + temp_image.boxes.push_back(temp_box); + temp_box = box(); + } + } + + virtual void characters ( + const std::string& data + ) + { + if (ts.size() == 2 && ts[1] == "filename") + { + temp_image.filename = trim(data); + } + else if (ts.size() == 3 && ts[2] == "database" && ts[1] == "source") + { + dataset_name = trim(data); + } + else if (ts.size() >= 3) + { + if (ts[ts.size()-2] == "bndbox" && ts[ts.size()-3] == "object") + { + if (ts.back() == "xmin") temp_box.rect.left() = string_cast<double>(data); + else if (ts.back() == "ymin") temp_box.rect.top() = string_cast<double>(data); + else if (ts.back() == "xmax") temp_box.rect.right() = string_cast<double>(data); + else if (ts.back() == "ymax") temp_box.rect.bottom() = string_cast<double>(data); + } + else if (ts.back() == "name" && ts[ts.size()-2] == "object") + { + temp_box.label = trim(data); + } + else if (ts.back() == "difficult" && ts[ts.size()-2] == "object") + { + if (trim(data) == "0" || trim(data) == "false") + { + temp_box.difficult = false; + } + else + { + temp_box.difficult = true; + } + } + else if (ts.back() == "truncated" && ts[ts.size()-2] == "object") + { + if (trim(data) == "0" || trim(data) == "false") + { + temp_box.truncated = false; + } + else + { + temp_box.truncated = true; + } + } + else if (ts.back() == "occluded" && ts[ts.size()-2] == "object") + { + if (trim(data) == "0" || trim(data) == "false") + { + temp_box.occluded = false; + } + else + { + temp_box.occluded = true; + } + } + + } + } + + virtual void processing_instruction ( + const unsigned long , + const std::string& , + const std::string& + ) + { + } + }; + +// ---------------------------------------------------------------------------------------- + + class xml_error_handler : public error_handler + { + public: + virtual void error ( + const unsigned long + ) { } + + virtual void fatal_error ( + const unsigned long line_number + ) + { + std::ostringstream sout; + sout << "There is a fatal error on line " << line_number << " so parsing will now halt."; + throw dlib::error(sout.str()); + } + }; + +// ---------------------------------------------------------------------------------------- + + void parse_annotation_file( + const std::string& file, + dlib::image_dataset_metadata::image& img, + std::string& dataset_name + ) + { + doc_handler dh(img, dataset_name); + xml_error_handler eh; + + xml_parser::kernel_1a parser; + parser.add_document_handler(dh); + parser.add_error_handler(eh); + + ifstream fin(file.c_str()); + if (!fin) + throw dlib::error("Unable to open file " + file); + parser.parse(fin); + } + +// ---------------------------------------------------------------------------------------- + +} + +void convert_pascal_xml( + const command_line_parser& parser +) +{ + cout << "Convert from PASCAL XML annotation format..." << endl; + + dlib::image_dataset_metadata::dataset dataset; + + std::string name; + dlib::image_dataset_metadata::image img; + + const std::string filename = parser.option("c").argument(); + // make sure the file exists so we can use the get_parent_directory() command to + // figure out it's parent directory. + make_empty_file(filename); + const std::string parent_dir = get_parent_directory(file(filename)).full_name(); + + for (unsigned long i = 0; i < parser.number_of_arguments(); ++i) + { + try + { + parse_annotation_file(parser[i], img, name); + const string root = get_parent_directory(get_parent_directory(file(parser[i]))).full_name(); + const string img_path = root + directory::get_separator() + "JPEGImages" + directory::get_separator(); + + dataset.name = name; + img.filename = strip_path(img_path + img.filename, parent_dir); + dataset.images.push_back(img); + + } + catch (exception& ) + { + cout << "Error while processing file " << parser[i] << endl << endl; + throw; + } + } + + save_image_dataset_metadata(dataset, filename); +} + |