318 lines
12 KiB
C++
318 lines
12 KiB
C++
// Copyright (C) 2013 Davis E. King (davis@dlib.net)
|
|
// License: Boost Software License See LICENSE.txt for the full license.
|
|
#ifndef DLIB_REMOVE_UnOBTAINABLE_RECTANGLES_Hh_
|
|
#define DLIB_REMOVE_UnOBTAINABLE_RECTANGLES_Hh_
|
|
|
|
#include "remove_unobtainable_rectangles_abstract.h"
|
|
#include "scan_image_pyramid.h"
|
|
#include "scan_image_boxes.h"
|
|
#include "scan_image_custom.h"
|
|
#include "scan_fhog_pyramid.h"
|
|
#include "../svm/structural_object_detection_trainer.h"
|
|
#include "../geometry.h"
|
|
|
|
|
|
namespace dlib
|
|
{
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
namespace impl
|
|
{
|
|
inline bool matches_rect (
|
|
const std::vector<rectangle>& rects,
|
|
const rectangle& rect,
|
|
const double eps
|
|
)
|
|
{
|
|
for (unsigned long i = 0; i < rects.size(); ++i)
|
|
{
|
|
const double score = (rect.intersect(rects[i])).area()/(double)(rect+rects[i]).area();
|
|
if (score > eps)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
inline rectangle get_best_matching_rect (
|
|
const std::vector<rectangle>& rects,
|
|
const rectangle& rect
|
|
)
|
|
{
|
|
double best_score = -1;
|
|
rectangle best_rect;
|
|
for (unsigned long i = 0; i < rects.size(); ++i)
|
|
{
|
|
const double score = (rect.intersect(rects[i])).area()/(double)(rect+rects[i]).area();
|
|
if (score > best_score)
|
|
{
|
|
best_score = score;
|
|
best_rect = rects[i];
|
|
}
|
|
}
|
|
return best_rect;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename image_array_type,
|
|
typename image_scanner_type
|
|
>
|
|
std::vector<std::vector<rectangle> > pyramid_remove_unobtainable_rectangles (
|
|
const structural_object_detection_trainer<image_scanner_type>& trainer,
|
|
const image_array_type& images,
|
|
std::vector<std::vector<rectangle> >& object_locations
|
|
)
|
|
{
|
|
using namespace dlib::impl;
|
|
// make sure requires clause is not broken
|
|
DLIB_ASSERT(images.size() == object_locations.size(),
|
|
"\t std::vector<std::vector<rectangle>> remove_unobtainable_rectangles()"
|
|
<< "\n\t Invalid inputs were given to this function."
|
|
);
|
|
|
|
|
|
std::vector<std::vector<rectangle> > rejects(images.size());
|
|
|
|
// If the trainer is setup to automatically fit the overlap tester to the data then
|
|
// we should use the loosest possible overlap tester here. Otherwise we should use
|
|
// the tester the trainer will use.
|
|
test_box_overlap boxes_overlap(0.9999999,1);
|
|
if (!trainer.auto_set_overlap_tester())
|
|
boxes_overlap = trainer.get_overlap_tester();
|
|
|
|
for (unsigned long k = 0; k < images.size(); ++k)
|
|
{
|
|
std::vector<rectangle> objs = object_locations[k];
|
|
|
|
// First remove things that don't have any matches with the candidate object
|
|
// locations.
|
|
std::vector<rectangle> good_rects;
|
|
for (unsigned long j = 0; j < objs.size(); ++j)
|
|
{
|
|
const rectangle rect = trainer.get_scanner().get_best_matching_rect(objs[j]);
|
|
const double score = (objs[j].intersect(rect)).area()/(double)(objs[j] + rect).area();
|
|
if (score > trainer.get_match_eps())
|
|
good_rects.push_back(objs[j]);
|
|
else
|
|
rejects[k].push_back(objs[j]);
|
|
}
|
|
object_locations[k] = good_rects;
|
|
|
|
|
|
// Remap these rectangles to the ones that can come out of the scanner. That
|
|
// way when we compare them to each other in the following loop we will know if
|
|
// any distinct truth rectangles get mapped to overlapping boxes.
|
|
objs.resize(good_rects.size());
|
|
for (unsigned long i = 0; i < good_rects.size(); ++i)
|
|
objs[i] = trainer.get_scanner().get_best_matching_rect(good_rects[i]);
|
|
|
|
good_rects.clear();
|
|
// now check for truth rects that are too close together.
|
|
for (unsigned long i = 0; i < objs.size(); ++i)
|
|
{
|
|
// check if objs[i] hits another box
|
|
bool hit_box = false;
|
|
for (unsigned long j = i+1; j < objs.size(); ++j)
|
|
{
|
|
if (boxes_overlap(objs[i], objs[j]))
|
|
{
|
|
hit_box = true;
|
|
break;
|
|
}
|
|
}
|
|
if (hit_box)
|
|
rejects[k].push_back(object_locations[k][i]);
|
|
else
|
|
good_rects.push_back(object_locations[k][i]);
|
|
}
|
|
object_locations[k] = good_rects;
|
|
}
|
|
|
|
return rejects;
|
|
}
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename image_array_type,
|
|
typename Pyramid_type,
|
|
typename Feature_extractor_type
|
|
>
|
|
std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (
|
|
const structural_object_detection_trainer<scan_image_pyramid<Pyramid_type, Feature_extractor_type> >& trainer,
|
|
const image_array_type& images,
|
|
std::vector<std::vector<rectangle> >& object_locations
|
|
)
|
|
{
|
|
return impl::pyramid_remove_unobtainable_rectangles(trainer, images, object_locations);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename image_array_type,
|
|
typename Pyramid_type,
|
|
typename Feature_extractor_type
|
|
>
|
|
std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (
|
|
const structural_object_detection_trainer<scan_fhog_pyramid<Pyramid_type,Feature_extractor_type> >& trainer,
|
|
const image_array_type& images,
|
|
std::vector<std::vector<rectangle> >& object_locations
|
|
)
|
|
{
|
|
return impl::pyramid_remove_unobtainable_rectangles(trainer, images, object_locations);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
namespace impl
|
|
{
|
|
template <
|
|
typename image_array_type,
|
|
typename scanner_type,
|
|
typename get_boxes_functor
|
|
>
|
|
std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (
|
|
get_boxes_functor& bg,
|
|
const structural_object_detection_trainer<scanner_type>& trainer,
|
|
const image_array_type& images,
|
|
std::vector<std::vector<rectangle> >& object_locations
|
|
)
|
|
{
|
|
using namespace dlib::impl;
|
|
// make sure requires clause is not broken
|
|
DLIB_ASSERT(images.size() == object_locations.size(),
|
|
"\t std::vector<std::vector<rectangle>> remove_unobtainable_rectangles()"
|
|
<< "\n\t Invalid inputs were given to this function."
|
|
);
|
|
|
|
std::vector<rectangle> rects;
|
|
|
|
std::vector<std::vector<rectangle> > rejects(images.size());
|
|
|
|
// If the trainer is setup to automatically fit the overlap tester to the data then
|
|
// we should use the loosest possible overlap tester here. Otherwise we should use
|
|
// the tester the trainer will use.
|
|
test_box_overlap boxes_overlap(0.9999999,1);
|
|
if (!trainer.auto_set_overlap_tester())
|
|
boxes_overlap = trainer.get_overlap_tester();
|
|
|
|
for (unsigned long k = 0; k < images.size(); ++k)
|
|
{
|
|
std::vector<rectangle> objs = object_locations[k];
|
|
// Don't even bother computing the candidate rectangles if there aren't any
|
|
// object locations for this image since there isn't anything to do anyway.
|
|
if (objs.size() == 0)
|
|
continue;
|
|
|
|
bg(images[k], rects);
|
|
|
|
|
|
// First remove things that don't have any matches with the candidate object
|
|
// locations.
|
|
std::vector<rectangle> good_rects;
|
|
for (unsigned long j = 0; j < objs.size(); ++j)
|
|
{
|
|
if (matches_rect(rects, objs[j], trainer.get_match_eps()))
|
|
good_rects.push_back(objs[j]);
|
|
else
|
|
rejects[k].push_back(objs[j]);
|
|
}
|
|
object_locations[k] = good_rects;
|
|
|
|
|
|
// Remap these rectangles to the ones that can come out of the scanner. That
|
|
// way when we compare them to each other in the following loop we will know if
|
|
// any distinct truth rectangles get mapped to overlapping boxes.
|
|
objs.resize(good_rects.size());
|
|
for (unsigned long i = 0; i < good_rects.size(); ++i)
|
|
objs[i] = get_best_matching_rect(rects, good_rects[i]);
|
|
|
|
good_rects.clear();
|
|
// now check for truth rects that are too close together.
|
|
for (unsigned long i = 0; i < objs.size(); ++i)
|
|
{
|
|
// check if objs[i] hits another box
|
|
bool hit_box = false;
|
|
for (unsigned long j = i+1; j < objs.size(); ++j)
|
|
{
|
|
if (boxes_overlap(objs[i], objs[j]))
|
|
{
|
|
hit_box = true;
|
|
break;
|
|
}
|
|
}
|
|
if (hit_box)
|
|
rejects[k].push_back(object_locations[k][i]);
|
|
else
|
|
good_rects.push_back(object_locations[k][i]);
|
|
}
|
|
object_locations[k] = good_rects;
|
|
}
|
|
|
|
return rejects;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <typename T>
|
|
struct load_to_functor
|
|
{
|
|
load_to_functor(T& obj_) : obj(obj_) {}
|
|
T& obj;
|
|
|
|
template <typename U, typename V>
|
|
void operator()(const U& u, V& v)
|
|
{
|
|
obj.load(u,v);
|
|
}
|
|
};
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename image_array_type,
|
|
typename feature_extractor,
|
|
typename box_generator
|
|
>
|
|
std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (
|
|
const structural_object_detection_trainer<scan_image_boxes<feature_extractor, box_generator> >& trainer,
|
|
const image_array_type& images,
|
|
std::vector<std::vector<rectangle> >& object_locations
|
|
)
|
|
{
|
|
box_generator bg = trainer.get_scanner().get_box_generator();
|
|
return impl::remove_unobtainable_rectangles(bg, trainer, images, object_locations);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename image_array_type,
|
|
typename feature_extractor
|
|
>
|
|
std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (
|
|
const structural_object_detection_trainer<scan_image_custom<feature_extractor> >& trainer,
|
|
const image_array_type& images,
|
|
std::vector<std::vector<rectangle> >& object_locations
|
|
)
|
|
{
|
|
feature_extractor fe;
|
|
fe.copy_configuration(trainer.get_scanner().get_feature_extractor());
|
|
impl::load_to_functor<feature_extractor> bg(fe);
|
|
return impl::remove_unobtainable_rectangles(bg, trainer, images, object_locations);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
}
|
|
|
|
#endif // DLIB_REMOVE_UnOBTAINABLE_RECTANGLES_Hh_
|
|
|