| |
|
| | #include "dlib/data_io.h" |
| | #include "dlib/string.h" |
| | #include "metadata_editor.h" |
| | #include "convert_pascal_xml.h" |
| | #include "convert_pascal_v1.h" |
| | #include "convert_idl.h" |
| | #include "cluster.h" |
| | #include "flip_dataset.h" |
| | #include <dlib/cmd_line_parser.h> |
| | #include <dlib/image_transforms.h> |
| | #include <dlib/svm.h> |
| | #include <dlib/console_progress_indicator.h> |
| | #include <dlib/md5.h> |
| |
|
| | #include <iostream> |
| | #include <fstream> |
| | #include <string> |
| | #include <set> |
| |
|
| | #include <dlib/dir_nav.h> |
| |
|
| |
|
| | const char* VERSION = "1.21"; |
| |
|
| |
|
| |
|
| | using namespace std; |
| | using namespace dlib; |
| |
|
| | |
| |
|
| | void create_new_dataset ( |
| | const command_line_parser& parser |
| | ) |
| | { |
| | using namespace dlib::image_dataset_metadata; |
| |
|
| | const std::string filename = parser.option("c").argument(); |
| | |
| | |
| | make_empty_file(filename); |
| | const std::string parent_dir = get_parent_directory(file(filename)); |
| |
|
| | unsigned long depth = 0; |
| | if (parser.option("r")) |
| | depth = 30; |
| |
|
| | dataset meta; |
| | meta.name = "imglab dataset"; |
| | meta.comment = "Created by imglab tool."; |
| | for (unsigned long i = 0; i < parser.number_of_arguments(); ++i) |
| | { |
| | try |
| | { |
| | const string temp = strip_path(file(parser[i]), parent_dir); |
| | meta.images.push_back(image(temp)); |
| | } |
| | catch (dlib::file::file_not_found&) |
| | { |
| | |
| |
|
| | std::vector<file> files = get_files_in_directory_tree(parser[i], |
| | match_endings(".png .PNG .jpeg .JPEG .jpg .JPG .bmp .BMP .dng .DNG .gif .GIF .jxl .JXL .webp .WEBP"), |
| | depth); |
| | sort(files.begin(), files.end()); |
| |
|
| | for (unsigned long j = 0; j < files.size(); ++j) |
| | { |
| | meta.images.push_back(image(strip_path(files[j], parent_dir))); |
| | } |
| | } |
| | } |
| |
|
| | save_image_dataset_metadata(meta, filename); |
| | } |
| |
|
| | |
| |
|
| | int split_dataset ( |
| | const command_line_parser& parser |
| | ) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --split option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | const std::string label = parser.option("split").argument(); |
| |
|
| | dlib::image_dataset_metadata::dataset data, data_with, data_without; |
| | load_image_dataset_metadata(data, parser[0]); |
| |
|
| | data_with.name = data.name; |
| | data_with.comment = data.comment; |
| | data_without.name = data.name; |
| | data_without.comment = data.comment; |
| |
|
| | for (unsigned long i = 0; i < data.images.size(); ++i) |
| | { |
| | auto&& temp = data.images[i]; |
| |
|
| | bool has_the_label = false; |
| | |
| | for (unsigned long j = 0; j < temp.boxes.size(); ++j) |
| | { |
| | if (temp.boxes[j].label == label) |
| | { |
| | has_the_label = true; |
| | break; |
| | } |
| | } |
| |
|
| | if (has_the_label) |
| | data_with.images.push_back(temp); |
| | else |
| | data_without.images.push_back(temp); |
| | } |
| |
|
| |
|
| | save_image_dataset_metadata(data_with, left_substr(parser[0],".") + "_with_"+label + ".xml"); |
| | save_image_dataset_metadata(data_without, left_substr(parser[0],".") + "_without_"+label + ".xml"); |
| |
|
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | |
| |
|
| | int make_train_test_splits ( |
| | const command_line_parser& parser |
| | ) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --split-train-test option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | const double train_frac = get_option(parser, "split-train-test", 0.5); |
| |
|
| | dlib::image_dataset_metadata::dataset data, data_train, data_test; |
| | load_image_dataset_metadata(data, parser[0]); |
| |
|
| | data_train.name = data.name; |
| | data_train.comment = data.comment; |
| | data_test.name = data.name; |
| | data_test.comment = data.comment; |
| |
|
| | const unsigned long num_train_images = static_cast<unsigned long>(std::round(train_frac*data.images.size())); |
| |
|
| | for (unsigned long i = 0; i < data.images.size(); ++i) |
| | { |
| | if (i < num_train_images) |
| | data_train.images.push_back(data.images[i]); |
| | else |
| | data_test.images.push_back(data.images[i]); |
| | } |
| |
|
| | save_image_dataset_metadata(data_train, left_substr(parser[0],".") + "_train.xml"); |
| | save_image_dataset_metadata(data_test, left_substr(parser[0],".") + "_test.xml"); |
| |
|
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | |
| |
|
| | void print_all_labels ( |
| | const dlib::image_dataset_metadata::dataset& data |
| | ) |
| | { |
| | std::set<std::string> labels; |
| | for (unsigned long i = 0; i < data.images.size(); ++i) |
| | { |
| | for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j) |
| | { |
| | labels.insert(data.images[i].boxes[j].label); |
| | } |
| | } |
| |
|
| | for (std::set<std::string>::iterator i = labels.begin(); i != labels.end(); ++i) |
| | { |
| | if (i->size() != 0) |
| | { |
| | cout << *i << endl; |
| | } |
| | } |
| | } |
| |
|
| | |
| |
|
| | void print_all_label_stats ( |
| | const dlib::image_dataset_metadata::dataset& data |
| | ) |
| | { |
| | std::map<std::string, running_stats<double> > area_stats, aspect_ratio; |
| | std::map<std::string, int> image_hits; |
| | std::set<std::string> labels; |
| | unsigned long num_unignored_boxes = 0; |
| | for (unsigned long i = 0; i < data.images.size(); ++i) |
| | { |
| | std::set<std::string> temp; |
| | for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j) |
| | { |
| | labels.insert(data.images[i].boxes[j].label); |
| | temp.insert(data.images[i].boxes[j].label); |
| |
|
| | area_stats[data.images[i].boxes[j].label].add(data.images[i].boxes[j].rect.area()); |
| | aspect_ratio[data.images[i].boxes[j].label].add(data.images[i].boxes[j].rect.width()/ |
| | (double)data.images[i].boxes[j].rect.height()); |
| |
|
| | if (!data.images[i].boxes[j].ignore) |
| | ++num_unignored_boxes; |
| | } |
| |
|
| | |
| | for (std::set<std::string>::iterator i = temp.begin(); i != temp.end(); ++i) |
| | image_hits[*i] += 1; |
| | } |
| |
|
| | cout << "Number of images: "<< data.images.size() << endl; |
| | cout << "Number of different labels: "<< labels.size() << endl; |
| | cout << "Number of non-ignored boxes: " << num_unignored_boxes << endl << endl; |
| |
|
| | for (std::set<std::string>::iterator i = labels.begin(); i != labels.end(); ++i) |
| | { |
| | if (i->size() == 0) |
| | cout << "Unlabeled Boxes:" << endl; |
| | else |
| | cout << "Label: "<< *i << endl; |
| | cout << " number of images: " << image_hits[*i] << endl; |
| | cout << " number of occurrences: " << area_stats[*i].current_n() << endl; |
| | cout << " min box area: " << area_stats[*i].min() << endl; |
| | cout << " max box area: " << area_stats[*i].max() << endl; |
| | cout << " mean box area: " << area_stats[*i].mean() << endl; |
| | cout << " stddev box area: " << area_stats[*i].stddev() << endl; |
| | cout << " mean width/height ratio: " << aspect_ratio[*i].mean() << endl; |
| | cout << " stddev width/height ratio: " << aspect_ratio[*i].stddev() << endl; |
| | cout << endl; |
| | } |
| | } |
| |
|
| | |
| |
|
| | void rename_labels ( |
| | dlib::image_dataset_metadata::dataset& data, |
| | const std::string& from, |
| | const std::string& to |
| | ) |
| | { |
| | for (unsigned long i = 0; i < data.images.size(); ++i) |
| | { |
| | for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j) |
| | { |
| | if (data.images[i].boxes[j].label == from) |
| | data.images[i].boxes[j].label = to; |
| | } |
| | } |
| |
|
| | } |
| |
|
| | |
| |
|
| | void ignore_labels ( |
| | dlib::image_dataset_metadata::dataset& data, |
| | const std::string& label |
| | ) |
| | { |
| | for (unsigned long i = 0; i < data.images.size(); ++i) |
| | { |
| | for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j) |
| | { |
| | if (data.images[i].boxes[j].label == label) |
| | data.images[i].boxes[j].ignore = true; |
| | } |
| | } |
| | } |
| |
|
| | |
| |
|
| | void merge_metadata_files ( |
| | const command_line_parser& parser |
| | ) |
| | { |
| | image_dataset_metadata::dataset src, dest; |
| | load_image_dataset_metadata(src, parser.option("add").argument(0)); |
| | load_image_dataset_metadata(dest, parser.option("add").argument(1)); |
| |
|
| | std::map<string,image_dataset_metadata::image> merged_data; |
| | for (unsigned long i = 0; i < dest.images.size(); ++i) |
| | merged_data[dest.images[i].filename] = dest.images[i]; |
| | |
| | for (unsigned long i = 0; i < src.images.size(); ++i) |
| | merged_data[src.images[i].filename] = src.images[i]; |
| |
|
| | |
| | dest.images.clear(); |
| | for (std::map<string,image_dataset_metadata::image>::const_iterator i = merged_data.begin(); |
| | i != merged_data.end(); ++i) |
| | { |
| | dest.images.push_back(i->second); |
| | } |
| |
|
| | save_image_dataset_metadata(dest, "merged.xml"); |
| | } |
| |
|
| | |
| |
|
| | void rotate_dataset(const command_line_parser& parser) |
| | { |
| | image_dataset_metadata::dataset metadata; |
| | const string datasource = parser[0]; |
| | load_image_dataset_metadata(metadata,datasource); |
| |
|
| | double angle = get_option(parser, "rotate", 0); |
| |
|
| | |
| | |
| | |
| | set_current_dir(get_parent_directory(file(datasource))); |
| |
|
| | const string file_prefix = "rotated_"+ cast_to_string(angle) + "_"; |
| | const string metadata_filename = get_parent_directory(file(datasource)).full_name() + |
| | directory::get_separator() + file_prefix + file(datasource).name(); |
| |
|
| |
|
| | array2d<rgb_pixel> img, temp; |
| | for (unsigned long i = 0; i < metadata.images.size(); ++i) |
| | { |
| | file f(metadata.images[i].filename); |
| | string filename = get_parent_directory(f).full_name() + directory::get_separator() + file_prefix + to_png_name(f.name()); |
| |
|
| | load_image(img, metadata.images[i].filename); |
| | const point_transform_affine tran = rotate_image(img, temp, angle*pi/180); |
| | metadata.images[i].width = temp.nc(); |
| | metadata.images[i].height = temp.nr(); |
| | if (parser.option("jpg")) |
| | { |
| | filename = to_jpg_name(filename); |
| | save_jpeg(temp, filename,JPEG_QUALITY); |
| | } |
| | #ifdef DLIB_JXL_SUPPORT |
| | else if (parser.option("jxl")) |
| | { |
| | filename = to_jxl_name(filename); |
| | const float jxl_quality = std::stof(parser.option("jxl").argument()); |
| | save_jxl(temp, filename, jxl_quality); |
| | } |
| | #endif |
| | #ifdef DLIB_WEBP_SUPPORT |
| | else if (parser.option("webp")) |
| | { |
| | filename = to_webp_name(filename); |
| | const float webp_quality = std::stof(parser.option("webp").argument()); |
| | save_webp(temp, filename, webp_quality); |
| | } |
| | #endif |
| | else |
| | { |
| | save_png(temp, filename); |
| | } |
| |
|
| | rectangle_transform rtran = tran; |
| | for (unsigned long j = 0; j < metadata.images[i].boxes.size(); ++j) |
| | { |
| | metadata.images[i].boxes[j].rect = rtran(metadata.images[i].boxes[j].rect); |
| |
|
| | for (auto& p : metadata.images[i].boxes[j].parts) |
| | p.second = tran(p.second); |
| | } |
| |
|
| | metadata.images[i].filename = filename; |
| | } |
| |
|
| | save_image_dataset_metadata(metadata, metadata_filename); |
| | } |
| |
|
| | |
| |
|
| | void add_width_and_height_metadata(const command_line_parser& parser) |
| | { |
| | for (unsigned long i = 0; i < parser.number_of_arguments(); ++i) { |
| | image_dataset_metadata::dataset metadata; |
| | const string datasource = parser[i]; |
| | load_image_dataset_metadata(metadata,datasource); |
| |
|
| | |
| | |
| | |
| | set_current_dir(get_parent_directory(file(datasource))); |
| |
|
| | parallel_for(0, metadata.images.size(), [&](long i) |
| | { |
| | array2d<rgb_pixel> img; |
| | load_image(img, metadata.images[i].filename); |
| | metadata.images[i].width = img.nc(); |
| | metadata.images[i].height = img.nr(); |
| | }); |
| |
|
| | save_image_dataset_metadata(metadata, datasource); |
| | } |
| | } |
| |
|
| | |
| |
|
| | int resample_dataset(const command_line_parser& parser) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --resample option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | const size_t obj_size = get_option(parser,"cropped-object-size",100*100); |
| | const double margin_scale = get_option(parser,"crop-size",2.5); |
| | const unsigned long min_object_size = get_option(parser,"min-object-size",1); |
| | const bool one_object_per_image = parser.option("one-object-per-image"); |
| |
|
| | dlib::image_dataset_metadata::dataset data, resampled_data; |
| | std::ostringstream sout; |
| | sout << "\nThe --resample parameters which generated this dataset were:" << endl; |
| | sout << " cropped-object-size: "<< obj_size << endl; |
| | sout << " crop-size: "<< margin_scale << endl; |
| | sout << " min-object-size: "<< min_object_size << endl; |
| | if (one_object_per_image) |
| | sout << " one_object_per_image: true" << endl; |
| | resampled_data.comment = data.comment + sout.str(); |
| | resampled_data.name = data.name + " RESAMPLED"; |
| |
|
| | load_image_dataset_metadata(data, parser[0]); |
| | locally_change_current_dir chdir(get_parent_directory(file(parser[0]))); |
| | dlib::rand rnd; |
| |
|
| | const size_t image_size = std::round(std::sqrt(obj_size*margin_scale*margin_scale)); |
| | const chip_dims cdims(image_size, image_size); |
| |
|
| | console_progress_indicator pbar(data.images.size()); |
| | for (unsigned long i = 0; i < data.images.size(); ++i) |
| | { |
| | |
| | if (data.images[i].boxes.size() == 0) |
| | continue; |
| |
|
| | pbar.print_status(i); |
| | array2d<rgb_pixel> img, chip; |
| | load_image(img, data.images[i].filename); |
| |
|
| |
|
| | |
| | for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j) |
| | { |
| | const rectangle rect = data.images[i].boxes[j].rect; |
| | if (data.images[i].boxes[j].ignore || rect.area() < min_object_size) |
| | continue; |
| |
|
| | const auto max_dim = std::max(rect.width(), rect.height()); |
| |
|
| | const double rand_scale_perturb = 1 - 0.3*(rnd.get_random_double()-0.5); |
| | const rectangle crop_rect = centered_rect(rect, max_dim*margin_scale*rand_scale_perturb, max_dim*margin_scale*rand_scale_perturb); |
| |
|
| | const rectangle_transform tform = get_mapping_to_chip(chip_details(crop_rect, cdims)); |
| | extract_image_chip(img, chip_details(crop_rect, cdims), chip); |
| |
|
| | image_dataset_metadata::image dimg; |
| | |
| | |
| | for (size_t k = 0; k < data.images[i].boxes.size(); ++k) |
| | { |
| | image_dataset_metadata::box box = data.images[i].boxes[k]; |
| | |
| | if (crop_rect.intersect(box.rect).area() == 0) |
| | continue; |
| |
|
| | |
| | |
| | if (crop_rect.contains(grow_rect(box.rect,10)) && (!one_object_per_image || k==j)) |
| | data.images[i].boxes[k].ignore = true; |
| | else |
| | box.ignore = true; |
| |
|
| | if (box.rect.area() < min_object_size) |
| | box.ignore = true; |
| |
|
| | box.rect = tform(box.rect); |
| | for (auto&& p : box.parts) |
| | p.second = tform.get_tform()(p.second); |
| | dimg.boxes.push_back(box); |
| | } |
| | |
| | |
| | std::ostringstream sout; |
| | sout << hex << murmur_hash3_128bit(&chip[0][0], chip.size()*sizeof(chip[0][0])).second; |
| | dimg.filename = data.images[i].filename + "_RESAMPLED_"+sout.str()+".png"; |
| | dimg.width = chip.nc(); |
| | dimg.height = chip.nr(); |
| |
|
| | if (parser.option("jpg")) |
| | { |
| | dimg.filename = to_jpg_name(dimg.filename); |
| | save_jpeg(chip,dimg.filename, JPEG_QUALITY); |
| | } |
| | #ifdef DLIB_JXL_SUPPORT |
| | else if (parser.option("jxl")) |
| | { |
| | dimg.filename = to_jxl_name(dimg.filename); |
| | const float jxl_quality = std::stof(parser.option("jxl").argument()); |
| | save_jxl(chip, dimg.filename, jxl_quality); |
| | } |
| | #endif |
| | #ifdef DLIB_WEBP_SUPPORT |
| | else if (parser.option("webp")) |
| | { |
| | dimg.filename = to_webp_name(dimg.filename); |
| | const float webp_quality = std::stof(parser.option("webp").argument()); |
| | save_webp(chip, dimg.filename, webp_quality); |
| | } |
| | #endif |
| | else |
| | { |
| | save_png(chip,dimg.filename); |
| | } |
| | resampled_data.images.push_back(dimg); |
| | } |
| | } |
| |
|
| | save_image_dataset_metadata(resampled_data, parser[0] + ".RESAMPLED.xml"); |
| |
|
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | |
| |
|
| | int tile_dataset(const command_line_parser& parser) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --tile option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | string out_image = parser.option("tile").argument(); |
| | string ext = right_substr(out_image,"."); |
| | if (ext != "png" && ext != "jpg" |
| | #if DLIB_JXL_SUPPORT |
| | && ext != "jxl" |
| | #endif |
| | #if DLIB_WEBP_SUPPORT |
| | && ext != "webp" |
| | #endif |
| | ) |
| | { |
| | cerr << "The output image file must have one of these extensions: .png, .jpg" << endl; |
| | #if DLIB_JXL_SUPPORT |
| | cerr << ", .jxl"; |
| | #endif |
| | #if DLIB_WEBP_SUPPORT |
| | cerr << ", .webp"; |
| | #endif |
| | cerr << "."; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | const unsigned long chip_size = get_option(parser, "size", 8000); |
| |
|
| | dlib::image_dataset_metadata::dataset data; |
| | load_image_dataset_metadata(data, parser[0]); |
| | locally_change_current_dir chdir(get_parent_directory(file(parser[0]))); |
| | dlib::array<array2d<rgb_pixel> > images; |
| | console_progress_indicator pbar(data.images.size()); |
| | for (unsigned long i = 0; i < data.images.size(); ++i) |
| | { |
| | |
| | if (data.images[i].boxes.size() == 0) |
| | continue; |
| |
|
| | pbar.print_status(i); |
| | array2d<rgb_pixel> img; |
| | load_image(img, data.images[i].filename); |
| |
|
| | |
| | std::vector<chip_details> dets; |
| | for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j) |
| | { |
| | if (data.images[i].boxes[j].ignore) |
| | continue; |
| |
|
| | rectangle rect = data.images[i].boxes[j].rect; |
| | dets.push_back(chip_details(rect, chip_size)); |
| | } |
| | |
| | dlib::array<array2d<rgb_pixel> > chips; |
| | extract_image_chips(img, dets, chips); |
| | |
| | for (unsigned long j = 0; j < chips.size(); ++j) |
| | images.push_back(chips[j]); |
| | } |
| |
|
| | chdir.revert(); |
| |
|
| | if (ext == "png") |
| | { |
| | save_png(tile_images(images), out_image); |
| | } |
| | #ifdef DLIB_JXL_SUPPORT |
| | else if (ext == "jxl") |
| | { |
| | |
| | const float jxl_quality = get_option(parser, "jxl", 100.f); |
| | save_jxl(tile_images(images), out_image, jxl_quality); |
| | } |
| | #endif |
| | #ifdef DLIB_WEBP_SUPPORT |
| | else if (ext == "webp") |
| | { |
| | |
| | const float webp_quality = get_option(parser, "webp", 101.f); |
| | save_webp(tile_images(images), out_image, webp_quality); |
| | } |
| | #endif |
| | else |
| | { |
| | save_jpeg(tile_images(images), out_image, JPEG_QUALITY); |
| | } |
| |
|
| | return EXIT_SUCCESS; |
| | } |
| |
|
| |
|
| | |
| |
|
| | int main(int argc, char** argv) |
| | { |
| | try |
| | { |
| |
|
| | command_line_parser parser; |
| |
|
| | parser.add_option("h","Displays this information."); |
| | parser.add_option("v","Display version."); |
| | parser.add_option("font", "Set the label font in the GUI.", 1); |
| |
|
| | parser.set_group_name("Creating XML files"); |
| | parser.add_option("c","Create an XML file named <arg> listing a set of images.",1); |
| | parser.add_option("r","Search directories recursively for images."); |
| | parser.add_option("convert","Convert foreign image Annotations from <arg> format to the imglab format. " |
| | "Supported formats: pascal-xml, pascal-v1, idl.",1); |
| |
|
| | parser.set_group_name("Viewing XML files"); |
| | parser.add_option("tile","Chip out all the objects and save them as one big image called <arg>.",1); |
| | parser.add_option("size","When using --tile or --cluster, make each extracted object contain " |
| | "about <arg> pixels (default 8000).",1); |
| | parser.add_option("l","List all the labels in the given XML file."); |
| | parser.add_option("stats","List detailed statistics on the object labels in the given XML file."); |
| | parser.add_option("files","List all the files in the given XML file."); |
| |
|
| | parser.set_group_name("Editing/Transforming XML datasets"); |
| | parser.add_option("rename", "Rename all labels of <arg1> to <arg2>.",2); |
| | parser.add_option("parts","The display will allow image parts to be labeled. The set of allowable parts " |
| | "is defined by <arg> which should be a space separated list of parts.",1); |
| | parser.add_option("rmempty","Remove all images that don't contain non-ignored annotations and save the results to a new XML file."); |
| | parser.add_option("rmdupes","Remove duplicate images from the dataset. This is done by comparing " |
| | "the md5 hash of each image file and removing duplicate images. " ); |
| | parser.add_option("rmdiff","Set the ignored flag to true for boxes marked as difficult."); |
| | parser.add_option("rmtrunc","Set the ignored flag to true for boxes that are partially outside the image."); |
| | parser.add_option("box-images","Add a box to each image that contains the entire image."); |
| | parser.add_option("sort-num-objects","Sort the images listed an XML file so images with many objects are listed first."); |
| | parser.add_option("sort","Alphabetically sort the images in an XML file."); |
| | parser.add_option("shuffle","Randomly shuffle the order of the images listed in an XML file."); |
| | parser.add_option("seed", "When using --shuffle, set the random seed to the string <arg>.",1); |
| | parser.add_option("split", "Split the contents of an XML file into two separate files. One containing the " |
| | "images with objects labeled <arg> and another file with all the other images. ",1); |
| | parser.add_option("split-train-test", "Split the contents of an XML file into two separate files. A training " |
| | "file containing <arg> fraction of the images and a testing file containing the remaining (1-<arg>) images. " |
| | "The partitioning is done deterministically by putting the first images in the input xml file into the training split " |
| | "and the later images into the test split.",1); |
| | parser.add_option("add", "Add the image metadata from <arg1> into <arg2>. If any of the image " |
| | "tags are in both files then the ones in <arg2> are deleted and replaced with the " |
| | "image tags from <arg1>. The results are saved into merged.xml and neither <arg1> or " |
| | "<arg2> files are modified.",2); |
| | parser.add_option("flip", "Read an XML image dataset from the <arg> XML file and output a left-right flipped " |
| | "version of the dataset and an accompanying flipped XML file named flipped_<arg>. " |
| | "We also adjust object part labels after flipping so that the new flipped dataset " |
| | "has the same average part layout as the source dataset." ,1); |
| | parser.add_option("flip-basic", "This option is just like --flip, except we don't adjust any object part labels after flipping. " |
| | "The parts are instead simply mirrored to the flipped dataset.", 1); |
| | parser.add_option("rotate", "Read an XML image dataset and output a copy that is rotated counter clockwise by <arg> degrees. " |
| | "The output is saved to an XML file prefixed with rotated_<arg>.",1); |
| | parser.add_option("add-width-height-metadata", "Open the given xml files and set the width and height image metadata fields " |
| | "for every image. This involves loading each image to find these values."); |
| | parser.add_option("cluster", "Cluster all the objects in an XML file into <arg> different clusters (pass 0 to find automatically) and save " |
| | "the results as cluster_###.xml and cluster_###.jpg files.",1); |
| | parser.add_option("ignore", "Mark boxes labeled as <arg> as ignored. The resulting XML file is output as a separate file and the original is not modified.",1); |
| | parser.add_option("rmlabel","Remove all boxes labeled <arg> and save the results to a new XML file.",1); |
| | parser.add_option("rm-other-labels","Remove all boxes not labeled <arg> and save the results to a new XML file.",1); |
| | parser.add_option("rmignore","Remove all boxes marked ignore and save the results to a new XML file."); |
| | parser.add_option("rm-if-overlaps","Remove all boxes labeled <arg> if they overlap any box not labeled <arg> and save the results to a new XML file.",1); |
| | parser.add_option("jpg", "When saving images to disk, write them as jpg files instead of png."); |
| | #ifdef DLIB_JXL_SUPPORT |
| | parser.add_option("jxl", "When saving images to disk, write them as jxl files instead of png, using <arg> as the quality factor.", 1); |
| | #endif |
| | #ifdef DLIB_WEBP_SUPPORT |
| | parser.add_option("webp", "When saving images to disk, write them as webp files instead of png, using <arg> as the quality factor.", 1); |
| | #endif |
| |
|
| | parser.set_group_name("Cropping sub images"); |
| | parser.add_option("resample", "Crop out images that are centered on each object in the dataset. " |
| | "The output is a new XML dataset."); |
| | parser.add_option("cropped-object-size", "When doing --resample, make the cropped objects contain about <arg> pixels (default 10000).",1); |
| | parser.add_option("min-object-size", "When doing --resample, skip objects that have fewer than <arg> pixels in them (default 1).",1); |
| | parser.add_option("crop-size", "When doing --resample, the entire cropped image will be <arg> times wider than the object (default 2.5).",1); |
| | parser.add_option("one-object-per-image", "When doing --resample, only include one non-ignored object per image (i.e. the central object)."); |
| |
|
| |
|
| |
|
| | parser.parse(argc, argv); |
| |
|
| | const std::string font_path = get_option(parser, "font", ""); |
| |
|
| | const char* singles[] = {"h","c","r","l","files","convert","parts","rmdiff", "rmtrunc", "rmdupes", "seed", "shuffle", "split", "add", |
| | "flip-basic", "flip", "rotate", "tile", "size", "cluster", "resample", "min-object-size", "rmempty", |
| | "crop-size", "cropped-object-size", "rmlabel", "rm-other-labels", "rm-if-overlaps", "sort-num-objects", |
| | "one-object-per-image", "jpg", "rmignore", "sort", "split-train-test", "box-images", "add-width-height-metadata"}; |
| | parser.check_one_time_options(singles); |
| | const char* c_sub_ops[] = {"r", "convert"}; |
| | parser.check_sub_options("c", c_sub_ops); |
| | parser.check_sub_option("shuffle", "seed"); |
| | const char* resample_sub_ops[] = {"min-object-size", "crop-size", "cropped-object-size", "one-object-per-image"}; |
| | parser.check_sub_options("resample", resample_sub_ops); |
| | const char* size_parent_ops[] = {"tile", "cluster"}; |
| | parser.check_sub_options(size_parent_ops, "size"); |
| | parser.check_incompatible_options("c", "l"); |
| | parser.check_incompatible_options("c", "files"); |
| | parser.check_incompatible_options("c", "rmdiff"); |
| | parser.check_incompatible_options("c", "rmempty"); |
| | parser.check_incompatible_options("c", "rmlabel"); |
| | parser.check_incompatible_options("c", "rm-other-labels"); |
| | parser.check_incompatible_options("c", "rmignore"); |
| | parser.check_incompatible_options("c", "rm-if-overlaps"); |
| | parser.check_incompatible_options("c", "rmdupes"); |
| | parser.check_incompatible_options("c", "rmtrunc"); |
| | parser.check_incompatible_options("c", "box-images"); |
| | parser.check_incompatible_options("c", "add"); |
| | parser.check_incompatible_options("c", "flip"); |
| | parser.check_incompatible_options("c", "flip-basic"); |
| | parser.check_incompatible_options("flip", "flip-basic"); |
| | parser.check_incompatible_options("c", "rotate"); |
| | parser.check_incompatible_options("c", "add-width-height-metadata"); |
| | parser.check_incompatible_options("c", "rename"); |
| | parser.check_incompatible_options("c", "ignore"); |
| | parser.check_incompatible_options("c", "parts"); |
| | parser.check_incompatible_options("c", "tile"); |
| | parser.check_incompatible_options("c", "cluster"); |
| | parser.check_incompatible_options("c", "resample"); |
| | parser.check_incompatible_options("l", "rename"); |
| | parser.check_incompatible_options("l", "ignore"); |
| | parser.check_incompatible_options("l", "add"); |
| | parser.check_incompatible_options("l", "parts"); |
| | parser.check_incompatible_options("l", "flip"); |
| | parser.check_incompatible_options("l", "flip-basic"); |
| | parser.check_incompatible_options("l", "rotate"); |
| | parser.check_incompatible_options("l", "add-width-height-metadata"); |
| | parser.check_incompatible_options("files", "rename"); |
| | parser.check_incompatible_options("files", "ignore"); |
| | parser.check_incompatible_options("files", "add"); |
| | parser.check_incompatible_options("files", "parts"); |
| | parser.check_incompatible_options("files", "flip"); |
| | parser.check_incompatible_options("files", "flip-basic"); |
| | parser.check_incompatible_options("files", "rotate"); |
| | parser.check_incompatible_options("files", "add-width-height-metadata"); |
| | parser.check_incompatible_options("add", "flip"); |
| | parser.check_incompatible_options("add", "flip-basic"); |
| | parser.check_incompatible_options("add", "rotate"); |
| | parser.check_incompatible_options("add", "add-width-height-metadata"); |
| | parser.check_incompatible_options("add", "tile"); |
| | parser.check_incompatible_options("flip", "tile"); |
| | parser.check_incompatible_options("flip-basic", "tile"); |
| | parser.check_incompatible_options("rotate", "tile"); |
| | parser.check_incompatible_options("add-width-height-metadata", "tile"); |
| | parser.check_incompatible_options("cluster", "tile"); |
| | parser.check_incompatible_options("resample", "tile"); |
| | parser.check_incompatible_options("flip", "cluster"); |
| | parser.check_incompatible_options("flip-basic", "cluster"); |
| | parser.check_incompatible_options("rotate", "cluster"); |
| | parser.check_incompatible_options("add-width-height-metadata", "cluster"); |
| | parser.check_incompatible_options("add", "cluster"); |
| | parser.check_incompatible_options("flip", "resample"); |
| | parser.check_incompatible_options("flip-basic", "resample"); |
| | parser.check_incompatible_options("rotate", "resample"); |
| | parser.check_incompatible_options("add-width-height-metadata", "resample"); |
| | parser.check_incompatible_options("add", "resample"); |
| | parser.check_incompatible_options("shuffle", "tile"); |
| | parser.check_incompatible_options("sort-num-objects", "tile"); |
| | parser.check_incompatible_options("sort", "tile"); |
| | parser.check_incompatible_options("convert", "l"); |
| | parser.check_incompatible_options("convert", "files"); |
| | parser.check_incompatible_options("convert", "rename"); |
| | parser.check_incompatible_options("convert", "ignore"); |
| | parser.check_incompatible_options("convert", "parts"); |
| | parser.check_incompatible_options("convert", "cluster"); |
| | parser.check_incompatible_options("convert", "resample"); |
| | parser.check_incompatible_options("rmdiff", "rename"); |
| | parser.check_incompatible_options("rmdiff", "ignore"); |
| | parser.check_incompatible_options("rmempty", "ignore"); |
| | parser.check_incompatible_options("rmempty", "rename"); |
| | parser.check_incompatible_options("rmlabel", "ignore"); |
| | parser.check_incompatible_options("rmlabel", "rename"); |
| | parser.check_incompatible_options("rm-other-labels", "ignore"); |
| | parser.check_incompatible_options("rm-other-labels", "rename"); |
| | parser.check_incompatible_options("rmignore", "ignore"); |
| | parser.check_incompatible_options("rmignore", "rename"); |
| | parser.check_incompatible_options("rm-if-overlaps", "ignore"); |
| | parser.check_incompatible_options("rm-if-overlaps", "rename"); |
| | parser.check_incompatible_options("rmdupes", "rename"); |
| | parser.check_incompatible_options("rmdupes", "ignore"); |
| | parser.check_incompatible_options("rmtrunc", "rename"); |
| | parser.check_incompatible_options("rmtrunc", "ignore"); |
| | parser.check_incompatible_options("box-images", "rename"); |
| | parser.check_incompatible_options("box-images", "ignore"); |
| | #ifdef DLIB_JXL_SUPPORT |
| | parser.check_incompatible_options("jpg", "jxl"); |
| | #endif |
| | #ifdef DLIB_WEBP_SUPPORT |
| | parser.check_incompatible_options("jpg", "webp"); |
| | #endif |
| | #if DLIB_JXL_SUPPORT && DLIB_WEBP_SUPPORT |
| | parser.check_incompatible_options("jxl", "webp"); |
| | #endif |
| | const char* convert_args[] = {"pascal-xml","pascal-v1","idl"}; |
| | parser.check_option_arg_range("convert", convert_args); |
| | parser.check_option_arg_range("cluster", 0, 999); |
| | parser.check_option_arg_range("rotate", -360, 360); |
| | parser.check_option_arg_range("size", 10*10, 1000*1000); |
| | parser.check_option_arg_range("min-object-size", 1, 10000*10000); |
| | parser.check_option_arg_range("cropped-object-size", 4, 10000*10000); |
| | parser.check_option_arg_range("crop-size", 1.0, 100.0); |
| | parser.check_option_arg_range("split-train-test", 0.0, 1.0); |
| | #ifdef DLIB_JXL_SUPPORT |
| | parser.check_option_arg_range("jxl", 0.f, 100.f); |
| | #endif |
| | #ifdef DLIB_WEBP_SUPPORT |
| | parser.check_option_arg_range("webp", 0.f, std::numeric_limits<float>::max()); |
| | #endif |
| |
|
| | if (parser.option("h")) |
| | { |
| | cout << "Usage: imglab [options] <image files/directories or XML file>\n"; |
| | parser.print_options(cout); |
| | cout << endl << endl; |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("add")) |
| | { |
| | merge_metadata_files(parser); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("flip") || parser.option("flip-basic")) |
| | { |
| | flip_dataset(parser); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("rotate")) |
| | { |
| | rotate_dataset(parser); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("add-width-height-metadata")) |
| | { |
| | add_width_and_height_metadata(parser); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("v")) |
| | { |
| | cout << "imglab v" << VERSION |
| | << "\nCompiled: " << __TIME__ << " " << __DATE__ |
| | << "\nWritten by Davis King\n"; |
| | cout << "Check for updates at http://dlib.net\n\n"; |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("tile")) |
| | { |
| | return tile_dataset(parser); |
| | } |
| |
|
| | if (parser.option("cluster")) |
| | { |
| | return cluster_dataset(parser); |
| | } |
| |
|
| | if (parser.option("resample")) |
| | { |
| | return resample_dataset(parser); |
| | } |
| |
|
| | if (parser.option("c")) |
| | { |
| | if (parser.option("convert")) |
| | { |
| | if (parser.option("convert").argument() == "pascal-xml") |
| | convert_pascal_xml(parser); |
| | else if (parser.option("convert").argument() == "pascal-v1") |
| | convert_pascal_v1(parser); |
| | else if (parser.option("convert").argument() == "idl") |
| | convert_idl(parser); |
| | } |
| | else |
| | { |
| | create_new_dataset(parser); |
| | } |
| | return EXIT_SUCCESS; |
| | } |
| | |
| | if (parser.option("rmdiff")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --rmdiff option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data; |
| | load_image_dataset_metadata(data, parser[0]); |
| | for (unsigned long i = 0; i < data.images.size(); ++i) |
| | { |
| | for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j) |
| | { |
| | if (data.images[i].boxes[j].difficult) |
| | data.images[i].boxes[j].ignore = true; |
| | } |
| | } |
| | save_image_dataset_metadata(data, parser[0]); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("rmempty")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --rmempty option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data, data2; |
| | load_image_dataset_metadata(data, parser[0]); |
| |
|
| | data2 = data; |
| | data2.images.clear(); |
| | for (unsigned long i = 0; i < data.images.size(); ++i) |
| | { |
| | bool has_label = false; |
| | for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j) |
| | { |
| | if (!data.images[i].boxes[j].ignore) |
| | has_label = true; |
| | } |
| | if (has_label) |
| | data2.images.push_back(data.images[i]); |
| | } |
| | save_image_dataset_metadata(data2, parser[0] + ".rmempty.xml"); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("rmlabel")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --rmlabel option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data; |
| | load_image_dataset_metadata(data, parser[0]); |
| |
|
| | const auto label = parser.option("rmlabel").argument(); |
| |
|
| | for (auto&& img : data.images) |
| | { |
| | std::vector<dlib::image_dataset_metadata::box> boxes; |
| | for (auto&& b : img.boxes) |
| | { |
| | if (b.label != label) |
| | boxes.push_back(b); |
| | } |
| | img.boxes = boxes; |
| | } |
| |
|
| | save_image_dataset_metadata(data, parser[0] + ".rmlabel-"+label+".xml"); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("rm-other-labels")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --rm-other-labels option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data; |
| | load_image_dataset_metadata(data, parser[0]); |
| |
|
| | const auto labels = parser.option("rm-other-labels").argument(); |
| | |
| | std::string strlabels = labels; |
| | std::replace(strlabels.begin(), strlabels.end(), ',', '-'); |
| | std::vector<string> all_labels = split(labels, ","); |
| | for (auto&& img : data.images) |
| | { |
| | std::vector<dlib::image_dataset_metadata::box> boxes; |
| | for (auto&& b : img.boxes) |
| | { |
| | if (std::find(all_labels.begin(), all_labels.end(), b.label) != all_labels.end()) |
| | boxes.push_back(b); |
| | } |
| | img.boxes = boxes; |
| | } |
| |
|
| | save_image_dataset_metadata(data, parser[0] + ".rm-other-labels-"+ strlabels +".xml"); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("rmignore")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --rmignore option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data; |
| | load_image_dataset_metadata(data, parser[0]); |
| |
|
| | for (auto&& img : data.images) |
| | { |
| | std::vector<dlib::image_dataset_metadata::box> boxes; |
| | for (auto&& b : img.boxes) |
| | { |
| | if (!b.ignore) |
| | boxes.push_back(b); |
| | } |
| | img.boxes = boxes; |
| | } |
| |
|
| | save_image_dataset_metadata(data, parser[0] + ".rmignore.xml"); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("rm-if-overlaps")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --rm-if-overlaps option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data; |
| | load_image_dataset_metadata(data, parser[0]); |
| |
|
| | const auto label = parser.option("rm-if-overlaps").argument(); |
| |
|
| | test_box_overlap overlaps(0.5); |
| |
|
| | for (auto&& img : data.images) |
| | { |
| | std::vector<dlib::image_dataset_metadata::box> boxes; |
| | for (auto&& b : img.boxes) |
| | { |
| | if (b.label != label) |
| | { |
| | boxes.push_back(b); |
| | } |
| | else |
| | { |
| | bool has_overlap = false; |
| | for (auto&& b2 : img.boxes) |
| | { |
| | if (b2.label != label && overlaps(b2.rect, b.rect)) |
| | { |
| | has_overlap = true; |
| | break; |
| | } |
| | } |
| | if (!has_overlap) |
| | boxes.push_back(b); |
| | } |
| | } |
| | img.boxes = boxes; |
| | } |
| |
|
| | save_image_dataset_metadata(data, parser[0] + ".rm-if-overlaps-"+label+".xml"); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("rmdupes")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --rmdupes option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data, data_out; |
| | std::set<std::string> hashes; |
| | load_image_dataset_metadata(data, parser[0]); |
| | data_out = data; |
| | data_out.images.clear(); |
| |
|
| | for (unsigned long i = 0; i < data.images.size(); ++i) |
| | { |
| | ifstream fin(data.images[i].filename.c_str(), ios::binary); |
| | string hash = md5(fin); |
| | if (hashes.count(hash) == 0) |
| | { |
| | hashes.insert(hash); |
| | data_out.images.push_back(data.images[i]); |
| | } |
| | } |
| | save_image_dataset_metadata(data_out, parser[0]); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("box-images")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --box-images option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data; |
| | load_image_dataset_metadata(data, parser[0]); |
| | { |
| | locally_change_current_dir chdir(get_parent_directory(file(parser[0]))); |
| | parallel_for(0, data.images.size(), [&](long i) |
| | { |
| | array2d<unsigned char> img; |
| | load_image(img, data.images[i].filename); |
| | data.images[i].boxes.emplace_back(get_rect(img)); |
| | }); |
| | } |
| | save_image_dataset_metadata(data, parser[0]+".boxed.xml"); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("rmtrunc")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --rmtrunc option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data; |
| | load_image_dataset_metadata(data, parser[0]); |
| | { |
| | locally_change_current_dir chdir(get_parent_directory(file(parser[0]))); |
| | for (unsigned long i = 0; i < data.images.size(); ++i) |
| | { |
| | array2d<unsigned char> img; |
| | load_image(img, data.images[i].filename); |
| | const rectangle area = get_rect(img); |
| | for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j) |
| | { |
| | if (!area.contains(data.images[i].boxes[j].rect)) |
| | data.images[i].boxes[j].ignore = true; |
| | } |
| | } |
| | } |
| | save_image_dataset_metadata(data, parser[0]); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("l")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The -l option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data; |
| | load_image_dataset_metadata(data, parser[0]); |
| | print_all_labels(data); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("files")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --files option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data; |
| | load_image_dataset_metadata(data, parser[0]); |
| | for (size_t i = 0; i < data.images.size(); ++i) |
| | cout << data.images[i].filename << "\n"; |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("split")) |
| | { |
| | return split_dataset(parser); |
| | } |
| |
|
| | if (parser.option("split-train-test")) |
| | { |
| | return make_train_test_splits(parser); |
| | } |
| |
|
| | if (parser.option("shuffle")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --shuffle option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data; |
| | load_image_dataset_metadata(data, parser[0]); |
| | const string default_seed = cast_to_string(time(0)); |
| | const string seed = get_option(parser, "seed", default_seed); |
| | dlib::rand rnd(seed); |
| | randomize_samples(data.images, rnd); |
| | save_image_dataset_metadata(data, parser[0]); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("sort-num-objects")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --sort-num-objects option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data; |
| | load_image_dataset_metadata(data, parser[0]); |
| | std::sort(data.images.rbegin(), data.images.rend(), |
| | [](const image_dataset_metadata::image& a, const image_dataset_metadata::image& b) { return a.boxes.size() < b.boxes.size(); }); |
| | save_image_dataset_metadata(data, parser[0]); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("sort")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --sort option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data; |
| | load_image_dataset_metadata(data, parser[0]); |
| | std::sort(data.images.begin(), data.images.end(), |
| | [](const image_dataset_metadata::image& a, const image_dataset_metadata::image& b) { return a.filename < b.filename; }); |
| | save_image_dataset_metadata(data, parser[0]); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("stats")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --stats option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data; |
| | load_image_dataset_metadata(data, parser[0]); |
| | print_all_label_stats(data); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("rename")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --rename option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data; |
| | load_image_dataset_metadata(data, parser[0]); |
| | for (unsigned long i = 0; i < parser.option("rename").count(); ++i) |
| | { |
| | rename_labels(data, parser.option("rename").argument(0,i), parser.option("rename").argument(1,i)); |
| | } |
| | save_image_dataset_metadata(data, parser[0]); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.option("ignore")) |
| | { |
| | if (parser.number_of_arguments() != 1) |
| | { |
| | cerr << "The --ignore option requires you to give one XML file on the command line." << endl; |
| | return EXIT_FAILURE; |
| | } |
| |
|
| | dlib::image_dataset_metadata::dataset data; |
| | load_image_dataset_metadata(data, parser[0]); |
| | for (unsigned long i = 0; i < parser.option("ignore").count(); ++i) |
| | { |
| | ignore_labels(data, parser.option("ignore").argument()); |
| | } |
| | save_image_dataset_metadata(data, parser[0]+".ignored.xml"); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | if (parser.number_of_arguments() == 1) |
| | { |
| | metadata_editor editor(parser[0], font_path); |
| | if (parser.option("parts")) |
| | { |
| | std::vector<string> parts = split(parser.option("parts").argument()); |
| | for (unsigned long i = 0; i < parts.size(); ++i) |
| | { |
| | editor.add_labelable_part_name(parts[i]); |
| | } |
| | } |
| | editor.wait_until_closed(); |
| | return EXIT_SUCCESS; |
| | } |
| |
|
| | cout << "Invalid command, give -h to see options." << endl; |
| | return EXIT_FAILURE; |
| | } |
| | catch (exception& e) |
| | { |
| | cerr << e.what() << endl; |
| | return EXIT_FAILURE; |
| | } |
| | } |
| |
|
| | |
| |
|
| |
|