Commit b638145f authored by Davis King's avatar Davis King

Moved the responsibility for automatically filling out a test_box_overlap

object from the structural_object_detection_trainer to the
structural_svm_object_detection_problem.  This allows us to use image scanners
which require an image be loaded before get_best_matching_rect() can be called.
I also made it so that the scanner loading (and therefore feature extraction)
is threaded.  Previously, it only used a single core.
parent d81641cd
...@@ -275,29 +275,8 @@ namespace dlib ...@@ -275,29 +275,8 @@ namespace dlib
} }
#endif #endif
test_box_overlap local_overlap_tester;
if (auto_overlap_tester)
{
std::vector<std::vector<rectangle> > mapped_rects(truth_object_detections.size());
for (unsigned long i = 0; i < truth_object_detections.size(); ++i)
{
mapped_rects[i].resize(truth_object_detections[i].size());
for (unsigned long j = 0; j < truth_object_detections[i].size(); ++j)
{
mapped_rects[i][j] = scanner.get_best_matching_rect(truth_object_detections[i][j].get_rect());
}
}
local_overlap_tester = find_tight_overlap_tester(mapped_rects);
}
else
{
local_overlap_tester = overlap_tester;
}
structural_svm_object_detection_problem<image_scanner_type,image_array_type > structural_svm_object_detection_problem<image_scanner_type,image_array_type >
svm_prob(scanner, local_overlap_tester, images, truth_object_detections, num_threads); svm_prob(scanner, overlap_tester, auto_overlap_tester, images, truth_object_detections, num_threads);
if (verbose) if (verbose)
svm_prob.be_verbose(); svm_prob.be_verbose();
...@@ -314,7 +293,7 @@ namespace dlib ...@@ -314,7 +293,7 @@ namespace dlib
solver(svm_prob,w); solver(svm_prob,w);
// report the results of the training. // report the results of the training.
return object_detector<image_scanner_type>(scanner, local_overlap_tester, w); return object_detector<image_scanner_type>(scanner, svm_prob.get_overlap_tester(), w);
} }
template < template <
......
...@@ -37,6 +37,7 @@ namespace dlib ...@@ -37,6 +37,7 @@ namespace dlib
structural_svm_object_detection_problem( structural_svm_object_detection_problem(
const image_scanner_type& scanner, const image_scanner_type& scanner,
const test_box_overlap& overlap_tester, const test_box_overlap& overlap_tester,
const bool auto_overlap_tester,
const image_array_type& images_, const image_array_type& images_,
const std::vector<std::vector<full_object_detection> >& truth_object_detections_, const std::vector<std::vector<full_object_detection> >& truth_object_detections_,
unsigned long num_threads = 2 unsigned long num_threads = 2
...@@ -75,19 +76,34 @@ namespace dlib ...@@ -75,19 +76,34 @@ namespace dlib
} }
} }
#endif #endif
// The purpose of the max_num_dets member variable is to give us a reasonable
scanners.set_max_size(images.size()); // upper limit on the number of detections we can expect from a single image.
scanners.set_size(images.size()); // This is used in the separation_oracle to put a hard limit on the number of
// detections we will consider. We do this purely for computational reasons
// since otherwise we can end up wasting large amounts of time on certain
// pathological cases during optimization which ultimately do not influence the
// result. Therefore, we for the separation oracle to only consider the
// max_num_dets strongest detections.
max_num_dets = 0; max_num_dets = 0;
for (unsigned long i = 0; i < truth_object_detections.size(); ++i) for (unsigned long i = 0; i < truth_object_detections.size(); ++i)
{ {
if (truth_object_detections[i].size() > max_num_dets) if (truth_object_detections[i].size() > max_num_dets)
max_num_dets = truth_object_detections[i].size(); max_num_dets = truth_object_detections[i].size();
scanners[i].copy_configuration(scanner);
} }
max_num_dets = max_num_dets*3 + 10; max_num_dets = max_num_dets*3 + 10;
initialize_scanners(scanner, num_threads);
if (auto_overlap_tester)
{
auto_configure_overlap_tester();
}
}
test_box_overlap get_overlap_tester (
) const
{
return boxes_overlap;
} }
void set_match_eps ( void set_match_eps (
...@@ -154,6 +170,24 @@ namespace dlib ...@@ -154,6 +170,24 @@ namespace dlib
} }
private: private:
void auto_configure_overlap_tester(
)
{
std::vector<std::vector<rectangle> > mapped_rects(truth_object_detections.size());
for (unsigned long i = 0; i < truth_object_detections.size(); ++i)
{
mapped_rects[i].resize(truth_object_detections[i].size());
for (unsigned long j = 0; j < truth_object_detections[i].size(); ++j)
{
mapped_rects[i][j] = scanners[i].get_best_matching_rect(truth_object_detections[i][j].get_rect());
}
}
boxes_overlap = find_tight_overlap_tester(mapped_rects);
}
virtual long get_num_dimensions ( virtual long get_num_dimensions (
) const ) const
{ {
...@@ -172,7 +206,7 @@ namespace dlib ...@@ -172,7 +206,7 @@ namespace dlib
feature_vector_type& psi feature_vector_type& psi
) const ) const
{ {
const image_scanner_type& scanner = get_scanner(idx); const image_scanner_type& scanner = scanners[idx];
psi.set_size(get_num_dimensions()); psi.set_size(get_num_dimensions());
std::vector<rectangle> mapped_rects; std::vector<rectangle> mapped_rects;
...@@ -268,7 +302,7 @@ namespace dlib ...@@ -268,7 +302,7 @@ namespace dlib
feature_vector_type& psi feature_vector_type& psi
) const ) const
{ {
const image_scanner_type& scanner = get_scanner(idx); const image_scanner_type& scanner = scanners[idx];
std::vector<std::pair<double, rectangle> > dets; std::vector<std::pair<double, rectangle> > dets;
const double thresh = current_solution(scanner.get_num_dimensions()); const double thresh = current_solution(scanner.get_num_dimensions());
...@@ -437,13 +471,38 @@ namespace dlib ...@@ -437,13 +471,38 @@ namespace dlib
return std::make_pair(match,best_idx); return std::make_pair(match,best_idx);
} }
struct init_scanners_helper
{
init_scanners_helper (
array<image_scanner_type>& scanners_,
const image_array_type& images_
) :
scanners(scanners_),
images(images_)
{}
array<image_scanner_type>& scanners;
const image_array_type& images;
void operator() (long i ) const
{
scanners[i].load(images[i]);
}
};
const image_scanner_type& get_scanner (long idx) const void initialize_scanners (
const image_scanner_type& scanner,
unsigned long num_threads
)
{ {
if (scanners[idx].is_loaded_with_image() == false) scanners.set_max_size(images.size());
scanners[idx].load(images[idx]); scanners.set_size(images.size());
for (unsigned long i = 0; i < scanners.size(); ++i)
scanners[i].copy_configuration(scanner);
return scanners[idx]; // now load the images into all the scanners
parallel_for(num_threads, 0, scanners.size(), init_scanners_helper(scanners, images));
} }
......
...@@ -68,7 +68,7 @@ namespace dlib ...@@ -68,7 +68,7 @@ namespace dlib
A detection is considered a false alarm if it doesn't match with any A detection is considered a false alarm if it doesn't match with any
of the ground truth rectangles or if it is a duplicate detection of a of the ground truth rectangles or if it is a duplicate detection of a
truth rectangle. Finally, for the purposes of calculating loss, a match truth rectangle. Finally, for the purposes of calculating loss, a match
is determined using the following formula, rectangles A and B match is determined using the following formula where rectangles A and B match
if and only if: if and only if:
A.intersect(B).area()/(A+B).area() > get_match_eps() A.intersect(B).area()/(A+B).area() > get_match_eps()
!*/ !*/
...@@ -77,6 +77,7 @@ namespace dlib ...@@ -77,6 +77,7 @@ namespace dlib
structural_svm_object_detection_problem( structural_svm_object_detection_problem(
const image_scanner_type& scanner, const image_scanner_type& scanner,
const test_box_overlap& overlap_tester, const test_box_overlap& overlap_tester,
const bool auto_overlap_tester,
const image_array_type& images, const image_array_type& images,
const std::vector<std::vector<full_object_detection> >& truth_object_detections, const std::vector<std::vector<full_object_detection> >& truth_object_detections,
unsigned long num_threads = 2 unsigned long num_threads = 2
...@@ -95,12 +96,18 @@ namespace dlib ...@@ -95,12 +96,18 @@ namespace dlib
attempts to learn to predict truth_object_detections[i] based on attempts to learn to predict truth_object_detections[i] based on
images[i]. Or in other words, this object can be used to learn a images[i]. Or in other words, this object can be used to learn a
parameter vector, w, such that an object_detector declared as: parameter vector, w, such that an object_detector declared as:
object_detector<image_scanner_type> detector(scanner,overlap_tester,w) object_detector<image_scanner_type> detector(scanner,get_overlap_tester(),w)
results in a detector object which attempts to compute the locations of results in a detector object which attempts to compute the locations of
all the objects in truth_object_detections. So if you called all the objects in truth_object_detections. So if you called
detector(images[i]) you would hopefully get a list of rectangles back detector(images[i]) you would hopefully get a list of rectangles back
that had truth_object_detections[i].size() elements and contained exactly that had truth_object_detections[i].size() elements and contained exactly
the rectangles indicated by truth_object_detections[i]. the rectangles indicated by truth_object_detections[i].
- if (auto_overlap_tester == true) then
- #get_overlap_tester() == a test_box_overlap object that is configured
using the find_tight_overlap_tester() routine and the contents of
truth_object_detections.
- else
- #get_overlap_tester() == overlap_tester
- #get_match_eps() == 0.5 - #get_match_eps() == 0.5
- This object will use num_threads threads during the optimization - This object will use num_threads threads during the optimization
procedure. You should set this parameter equal to the number of procedure. You should set this parameter equal to the number of
...@@ -109,6 +116,13 @@ namespace dlib ...@@ -109,6 +116,13 @@ namespace dlib
- #get_loss_per_false_alarm() == 1 - #get_loss_per_false_alarm() == 1
!*/ !*/
test_box_overlap get_overlap_tester (
) const;
/*!
ensures
- returns the overlap tester used by this object.
!*/
void set_match_eps ( void set_match_eps (
double eps double eps
); );
......
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