Commit 0beabe84 authored by Davis King's avatar Davis King

Added image_dataset_file::shrink_big_images(). So now load_image_dataset() can

load a dataset of high resolution files into a user requested lower resolution.
parent 2ed907aa
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include <set> #include <set>
#include "../image_processing/full_object_detection.h" #include "../image_processing/full_object_detection.h"
#include <utility> #include <utility>
#include <limits>
#include "../image_transforms/image_pyramid.h"
namespace dlib namespace dlib
...@@ -30,6 +32,7 @@ namespace dlib ...@@ -30,6 +32,7 @@ namespace dlib
_skip_empty_images = false; _skip_empty_images = false;
_have_parts = false; _have_parts = false;
_filename = filename; _filename = filename;
_box_area_thresh = std::numeric_limits<double>::infinity();
} }
image_dataset_file boxes_match_label( image_dataset_file boxes_match_label(
...@@ -57,6 +60,15 @@ namespace dlib ...@@ -57,6 +60,15 @@ namespace dlib
return temp; return temp;
} }
image_dataset_file shrink_big_images(
double new_box_area_thresh = 150*150
) const
{
image_dataset_file temp(*this);
temp._box_area_thresh = new_box_area_thresh;
return temp;
}
bool should_load_box ( bool should_load_box (
const image_dataset_metadata::box& box const image_dataset_metadata::box& box
) const ) const
...@@ -73,6 +85,7 @@ namespace dlib ...@@ -73,6 +85,7 @@ namespace dlib
const std::string& get_filename() const { return _filename; } const std::string& get_filename() const { return _filename; }
bool should_skip_empty_images() const { return _skip_empty_images; } bool should_skip_empty_images() const { return _skip_empty_images; }
bool should_boxes_have_parts() const { return _have_parts; } bool should_boxes_have_parts() const { return _have_parts; }
double box_area_thresh() const { return _box_area_thresh; }
const std::set<std::string>& get_selected_box_labels() const { return _labels; } const std::set<std::string>& get_selected_box_labels() const { return _labels; }
private: private:
...@@ -80,6 +93,8 @@ namespace dlib ...@@ -80,6 +93,8 @@ namespace dlib
std::set<std::string> _labels; std::set<std::string> _labels;
bool _skip_empty_images; bool _skip_empty_images;
bool _have_parts; bool _have_parts;
double _box_area_thresh;
}; };
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
...@@ -95,7 +110,6 @@ namespace dlib ...@@ -95,7 +110,6 @@ namespace dlib
{ {
images.clear(); images.clear();
object_locations.clear(); object_locations.clear();
const std::string old_working_dir = get_current_dir();
std::vector<std::vector<rectangle> > ignored_rects; std::vector<std::vector<rectangle> > ignored_rects;
...@@ -106,7 +120,7 @@ namespace dlib ...@@ -106,7 +120,7 @@ namespace dlib
// Set the current directory to be the one that contains the // Set the current directory to be the one that contains the
// metadata file. We do this because the file might contain // metadata file. We do this because the file might contain
// file paths which are relative to this folder. // file paths which are relative to this folder.
set_current_dir(get_parent_directory(file(source.get_filename()))); locally_change_current_dir chdir(get_parent_directory(file(source.get_filename())));
typedef typename array_type::value_type image_type; typedef typename array_type::value_type image_type;
...@@ -116,6 +130,7 @@ namespace dlib ...@@ -116,6 +130,7 @@ namespace dlib
std::vector<rectangle> rects, ignored; std::vector<rectangle> rects, ignored;
for (unsigned long i = 0; i < data.images.size(); ++i) for (unsigned long i = 0; i < data.images.size(); ++i)
{ {
double min_rect_size = std::numeric_limits<double>::infinity();
rects.clear(); rects.clear();
ignored.clear(); ignored.clear();
for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j) for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j)
...@@ -123,22 +138,51 @@ namespace dlib ...@@ -123,22 +138,51 @@ namespace dlib
if (source.should_load_box(data.images[i].boxes[j])) if (source.should_load_box(data.images[i].boxes[j]))
{ {
if (data.images[i].boxes[j].ignore) if (data.images[i].boxes[j].ignore)
{
ignored.push_back(data.images[i].boxes[j].rect); ignored.push_back(data.images[i].boxes[j].rect);
}
else else
{
rects.push_back(data.images[i].boxes[j].rect); rects.push_back(data.images[i].boxes[j].rect);
min_rect_size = std::min<double>(min_rect_size, rects.back().area());
}
} }
} }
if (!source.should_skip_empty_images() || rects.size() != 0) if (!source.should_skip_empty_images() || rects.size() != 0)
{ {
object_locations.push_back(rects);
ignored_rects.push_back(ignored);
load_image(img, data.images[i].filename); load_image(img, data.images[i].filename);
if (rects.size() != 0)
{
// if shrinking the image would still result in the smallest box being
// bigger than the box area threshold then shrink the image.
while(min_rect_size/2/2 > source.box_area_thresh())
{
pyramid_down<2> pyr;
pyr(img);
min_rect_size *= (1.0/2.0)*(1.0/2.0);
for (auto&& r : rects)
r = pyr.rect_down(r);
for (auto&& r : ignored)
r = pyr.rect_down(r);
}
while(min_rect_size*(2.0/3.0)*(2.0/3.0) > source.box_area_thresh())
{
pyramid_down<3> pyr;
pyr(img);
min_rect_size *= (2.0/3.0)*(2.0/3.0);
for (auto&& r : rects)
r = pyr.rect_down(r);
for (auto&& r : ignored)
r = pyr.rect_down(r);
}
}
images.push_back(img); images.push_back(img);
object_locations.push_back(rects);
ignored_rects.push_back(ignored);
} }
} }
set_current_dir(old_working_dir);
return ignored_rects; return ignored_rects;
} }
...@@ -171,23 +215,51 @@ namespace dlib ...@@ -171,23 +215,51 @@ namespace dlib
std::vector<mmod_rect> rects; std::vector<mmod_rect> rects;
for (unsigned long i = 0; i < data.images.size(); ++i) for (unsigned long i = 0; i < data.images.size(); ++i)
{ {
double min_rect_size = std::numeric_limits<double>::infinity();
rects.clear(); rects.clear();
for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j) for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j)
{ {
if (source.should_load_box(data.images[i].boxes[j])) if (source.should_load_box(data.images[i].boxes[j]))
{ {
if (data.images[i].boxes[j].ignore) if (data.images[i].boxes[j].ignore)
{
rects.push_back(ignored_mmod_rect(data.images[i].boxes[j].rect)); rects.push_back(ignored_mmod_rect(data.images[i].boxes[j].rect));
}
else else
{
rects.push_back(mmod_rect(data.images[i].boxes[j].rect)); rects.push_back(mmod_rect(data.images[i].boxes[j].rect));
min_rect_size = std::min<double>(min_rect_size, rects.back().rect.area());
}
} }
} }
if (!source.should_skip_empty_images() || rects.size() != 0) if (!source.should_skip_empty_images() || rects.size() != 0)
{ {
object_locations.push_back(std::move(rects));
load_image(img, data.images[i].filename); load_image(img, data.images[i].filename);
if (rects.size() != 0)
{
// if shrinking the image would still result in the smallest box being
// bigger than the box area threshold then shrink the image.
while(min_rect_size/2/2 > source.box_area_thresh())
{
pyramid_down<2> pyr;
pyr(img);
min_rect_size *= (1.0/2.0)*(1.0/2.0);
for (auto&& r : rects)
r.rect = pyr.rect_down(r.rect);
}
while(min_rect_size*(2.0/3.0)*(2.0/3.0) > source.box_area_thresh())
{
pyramid_down<3> pyr;
pyr(img);
min_rect_size *= (2.0/3.0)*(2.0/3.0);
for (auto&& r : rects)
r.rect = pyr.rect_down(r.rect);
}
}
images.push_back(std::move(img)); images.push_back(std::move(img));
object_locations.push_back(std::move(rects));
} }
} }
} }
...@@ -261,7 +333,6 @@ namespace dlib ...@@ -261,7 +333,6 @@ namespace dlib
parts_list.clear(); parts_list.clear();
images.clear(); images.clear();
object_locations.clear(); object_locations.clear();
const std::string old_working_dir = get_current_dir();
using namespace dlib::image_dataset_metadata; using namespace dlib::image_dataset_metadata;
dataset data; dataset data;
...@@ -270,7 +341,7 @@ namespace dlib ...@@ -270,7 +341,7 @@ namespace dlib
// Set the current directory to be the one that contains the // Set the current directory to be the one that contains the
// metadata file. We do this because the file might contain // metadata file. We do this because the file might contain
// file paths which are relative to this folder. // file paths which are relative to this folder.
set_current_dir(get_parent_directory(file(source.get_filename()))); locally_change_current_dir chdir(get_parent_directory(file(source.get_filename())));
std::set<std::string> all_parts; std::set<std::string> all_parts;
...@@ -307,6 +378,7 @@ namespace dlib ...@@ -307,6 +378,7 @@ namespace dlib
std::vector<full_object_detection> object_dets; std::vector<full_object_detection> object_dets;
for (unsigned long i = 0; i < data.images.size(); ++i) for (unsigned long i = 0; i < data.images.size(); ++i)
{ {
double min_rect_size = std::numeric_limits<double>::infinity();
object_dets.clear(); object_dets.clear();
ignored.clear(); ignored.clear();
for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j) for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j)
...@@ -330,20 +402,57 @@ namespace dlib ...@@ -330,20 +402,57 @@ namespace dlib
} }
object_dets.push_back(full_object_detection(data.images[i].boxes[j].rect, partlist)); object_dets.push_back(full_object_detection(data.images[i].boxes[j].rect, partlist));
min_rect_size = std::min<double>(min_rect_size, object_dets.back().get_rect().area());
} }
} }
} }
if (!source.should_skip_empty_images() || object_dets.size() != 0) if (!source.should_skip_empty_images() || object_dets.size() != 0)
{ {
object_locations.push_back(object_dets);
ignored_rects.push_back(ignored);
load_image(img, data.images[i].filename); load_image(img, data.images[i].filename);
if (object_dets.size() != 0)
{
// if shrinking the image would still result in the smallest box being
// bigger than the box area threshold then shrink the image.
while(min_rect_size/2/2 > source.box_area_thresh())
{
pyramid_down<2> pyr;
pyr(img);
min_rect_size *= (1.0/2.0)*(1.0/2.0);
for (auto&& r : object_dets)
{
r.get_rect() = pyr.rect_down(r.get_rect());
for (unsigned long k = 0; k < r.num_parts(); ++k)
r.part(k) = pyr.point_down(r.part(k));
}
for (auto&& r : ignored)
{
r = pyr.rect_down(r);
}
}
while(min_rect_size*(2.0/3.0)*(2.0/3.0) > source.box_area_thresh())
{
pyramid_down<3> pyr;
pyr(img);
min_rect_size *= (2.0/3.0)*(2.0/3.0);
for (auto&& r : object_dets)
{
r.get_rect() = pyr.rect_down(r.get_rect());
for (unsigned long k = 0; k < r.num_parts(); ++k)
r.part(k) = pyr.point_down(r.part(k));
}
for (auto&& r : ignored)
{
r = pyr.rect_down(r);
}
}
}
images.push_back(img); images.push_back(img);
object_locations.push_back(object_dets);
ignored_rects.push_back(ignored);
} }
} }
set_current_dir(old_working_dir);
return ignored_rects; return ignored_rects;
} }
......
...@@ -36,6 +36,7 @@ namespace dlib ...@@ -36,6 +36,7 @@ namespace dlib
This means that, initially, all boxes will be loaded. Therefore, for all This means that, initially, all boxes will be loaded. Therefore, for all
possible boxes B we have: possible boxes B we have:
- #should_load_box(B) == true - #should_load_box(B) == true
- #box_area_thresh() == infinity
!*/ !*/
const std::string& get_filename( const std::string& get_filename(
...@@ -115,6 +116,26 @@ namespace dlib ...@@ -115,6 +116,26 @@ namespace dlib
- returns false - returns false
!*/ !*/
image_dataset_file shrink_big_images(
double new_box_area_thresh = 150*150
) const;
/*!
ensures
- returns a copy of *this that is identical in all respects to *this except
that #box_area_thresh() == new_box_area_thresh
!*/
double box_area_thresh(
) const;
/*!
ensures
- If the smallest non-ignored rectangle in an image has an area greater
than box_area_thresh() then we will shrink the image until the area of
the box is about equal to box_area_thresh(). This is useful if you have
a dataset containing very high resolution images and you don't want to
load it in its native high resolution. Setting the box_area_thresh()
allows you to control the resolution of the loaded images.
!*/
}; };
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment