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 the current directory to be the one that contains the // metadata file. We do this because the file might contain // file paths which are relative to this folder. 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); const 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); save_png(temp, filename); for (unsigned long j = 0; j < metadata.images[i].boxes.size(); ++j) { const rectangle rect = metadata.images[i].boxes[j].rect; rectangle newrect; newrect += tran(rect.tl_corner()); newrect += tran(rect.tr_corner()); newrect += tran(rect.bl_corner()); newrect += tran(rect.br_corner()); // now make newrect have the same area as the starting rect. double ratio = std::sqrt(rect.area()/(double)newrect.area()); newrect = centered_rect(newrect, newrect.width()*ratio, newrect.height()*ratio); metadata.images[i].boxes[j].rect = newrect; // rotate all the object parts std::map<std::string,point>::iterator k; for (k = metadata.images[i].boxes[j].parts.begin(); k != metadata.images[i].boxes[j].parts.end(); ++k) { k->second = tran(k->second); } } metadata.images[i].filename = filename; } save_image_dataset_metadata(metadata, metadata_filename); }
unsigned long area(const rectangle& r) { return r.area(); }
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,"resample",100*100); const double margin_scale = 2.5; // cropped image will be this times wider than the object. const size_t image_size = obj_size*margin_scale*margin_scale; dlib::image_dataset_metadata::dataset data, resampled_data; resampled_data.comment = data.comment; resampled_data.name = data.name + " RESAMPLED"; load_image_dataset_metadata(data, parser[0]); locally_change_current_dir chdir(get_parent_directory(file(parser[0]))); console_progress_indicator pbar(data.images.size()); for (unsigned long i = 0; i < data.images.size(); ++i) { // don't even bother loading images that don't have objects. if (data.images[i].boxes.size() == 0) continue; pbar.print_status(i); array2d<rgb_pixel> img, chip; load_image(img, data.images[i].filename); // figure out what chips we want to take from this image 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 || !get_rect(img).contains(rect)) continue; const rectangle crop_rect = centered_rect(rect, rect.width()*margin_scale, rect.height()*margin_scale); // skip crops that have a lot of border pixels if (get_rect(img).intersect(crop_rect).area() < crop_rect.area()*0.8) continue; const rectangle_transform tform = get_mapping_to_chip(chip_details(crop_rect, image_size)); extract_image_chip(img, chip_details(crop_rect, image_size), chip); image_dataset_metadata::image dimg; // Now transform the boxes to the crop and also mark them as ignored if they // have already been cropped out or are outside the crop. for (size_t k = 0; k < data.images[i].boxes.size(); ++k) { image_dataset_metadata::box box = data.images[i].boxes[k]; // ignore boxes outside the cropped image if (crop_rect.intersect(box.rect).area() == 0) continue; // mark boxes we include in the crop as ignored. Also mark boxes that // aren't totally within the crop as ignored. if (crop_rect.contains(grow_rect(box.rect,10))) data.images[i].boxes[k].ignore = true; else 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); } dimg.filename = data.images[i].filename + "RESAMPLED"+cast_to_string(j)+".jpg"; save_jpeg(chip,dimg.filename, 98); resampled_data.images.push_back(dimg); } } save_image_dataset_metadata(resampled_data, parser[0] + ".RESAMPLED.xml"); return EXIT_SUCCESS; }
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); // cropped image will be this times wider than the object. 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) { // don't even bother loading images that don't have objects. if (data.images[i].boxes.size() == 0) continue; pbar.print_status(i); array2d<rgb_pixel> img, chip; load_image(img, data.images[i].filename); // figure out what chips we want to take from this image 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; // Now transform the boxes to the crop and also mark them as ignored if they // have already been cropped out or are outside the crop. for (size_t k = 0; k < data.images[i].boxes.size(); ++k) { image_dataset_metadata::box box = data.images[i].boxes[k]; // ignore boxes outside the cropped image if (crop_rect.intersect(box.rect).area() == 0) continue; // mark boxes we include in the crop as ignored. Also mark boxes that // aren't totally within the crop as ignored. 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); } // Put a 64bit hash of the image data into the name to make sure there are no // file name conflicts. 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"; if (parser.option("jpg")) { dimg.filename = to_jpg_name(dimg.filename); save_jpeg(chip,dimg.filename, JPEG_QUALITY); } 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; }