181 lines
6.4 KiB
C++
181 lines
6.4 KiB
C++
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
|
|
// License: Boost Software License See LICENSE.txt for the full license.
|
|
#ifndef DLIB_SCAN_IMaGE_PYRAMID_TOOLS_Hh_
|
|
#define DLIB_SCAN_IMaGE_PYRAMID_TOOLS_Hh_
|
|
|
|
#include "scan_image_pyramid_tools_abstract.h"
|
|
#include "../statistics.h"
|
|
#include <list>
|
|
#include "../geometry.h"
|
|
#include <iostream>
|
|
|
|
namespace dlib
|
|
{
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
namespace impl
|
|
{
|
|
inline bool compare_first (
|
|
const std::pair<unsigned long,rectangle>& a,
|
|
const std::pair<unsigned long,rectangle>& b
|
|
)
|
|
{
|
|
return a.first < b.first;
|
|
}
|
|
}
|
|
|
|
|
|
template <typename image_scanner_type>
|
|
std::vector<rectangle> determine_object_boxes (
|
|
const image_scanner_type& scanner,
|
|
const std::vector<rectangle>& rects,
|
|
double min_match_score
|
|
)
|
|
{
|
|
// make sure requires clause is not broken
|
|
DLIB_ASSERT(0 < min_match_score && min_match_score <= 1,
|
|
"\t std::vector<rectangle> determine_object_boxes()"
|
|
<< "\n\t Invalid inputs were given to this function. "
|
|
<< "\n\t min_match_score: " << min_match_score
|
|
);
|
|
|
|
typename image_scanner_type::pyramid_type pyr;
|
|
|
|
typedef std::list<std::pair<unsigned long, rectangle> > list_type;
|
|
|
|
unsigned long max_area = 0;
|
|
|
|
// Copy rects into sorted_rects and sort them in order of increasing area. But
|
|
// only include the rectangles that aren't already obtainable by the scanner.
|
|
list_type sorted_rects;
|
|
for (unsigned long i = 0; i < rects.size(); ++i)
|
|
{
|
|
if (scanner.get_num_detection_templates() > 0)
|
|
{
|
|
rectangle temp = scanner.get_best_matching_rect(rects[i]);
|
|
const double match_score = (rects[i].intersect(temp).area())/(double)(rects[i] + temp).area();
|
|
// skip this rectangle if it's already matched well enough.
|
|
if (match_score > min_match_score)
|
|
continue;
|
|
}
|
|
max_area = std::max(rects[i].area(), max_area);
|
|
sorted_rects.push_back(std::make_pair(rects[i].area(), rects[i]));
|
|
}
|
|
sorted_rects.sort(dlib::impl::compare_first);
|
|
|
|
// Make sure this area value is comfortably larger than all the
|
|
// rectangles' areas.
|
|
max_area = 3*max_area + 100;
|
|
|
|
std::vector<rectangle> object_boxes;
|
|
|
|
while (sorted_rects.size() != 0)
|
|
{
|
|
rectangle cur = sorted_rects.front().second;
|
|
sorted_rects.pop_front();
|
|
object_boxes.push_back(centered_rect(point(0,0), cur.width(), cur.height()));
|
|
|
|
// Scale cur up the image pyramid and remove any rectangles which match.
|
|
// But also stop when cur gets large enough to not match anything.
|
|
for (unsigned long itr = 0;
|
|
itr < scanner.get_max_pyramid_levels() && cur.area() < max_area;
|
|
++itr)
|
|
{
|
|
list_type::iterator i = sorted_rects.begin();
|
|
while (i != sorted_rects.end())
|
|
{
|
|
const rectangle temp = move_rect(i->second, cur.tl_corner());
|
|
const double match_score = (cur.intersect(temp).area())/(double)(cur + temp).area();
|
|
if (match_score > min_match_score)
|
|
{
|
|
i = sorted_rects.erase(i);
|
|
}
|
|
else
|
|
{
|
|
++i;
|
|
}
|
|
}
|
|
|
|
cur = pyr.rect_up(cur);
|
|
}
|
|
|
|
}
|
|
|
|
return object_boxes;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <typename image_scanner_type>
|
|
std::vector<rectangle> determine_object_boxes (
|
|
const image_scanner_type& scanner,
|
|
const std::vector<std::vector<rectangle> >& rects,
|
|
double min_match_score
|
|
)
|
|
{
|
|
// make sure requires clause is not broken
|
|
DLIB_ASSERT(0 < min_match_score && min_match_score <= 1,
|
|
"\t std::vector<rectangle> determine_object_boxes()"
|
|
<< "\n\t Invalid inputs were given to this function. "
|
|
<< "\n\t min_match_score: " << min_match_score
|
|
);
|
|
|
|
std::vector<rectangle> temp;
|
|
for (unsigned long i = 0; i < rects.size(); ++i)
|
|
{
|
|
for (unsigned long j = 0; j < rects[i].size(); ++j)
|
|
{
|
|
temp.push_back(rects[i][j]);
|
|
}
|
|
}
|
|
|
|
return determine_object_boxes(scanner, temp, min_match_score);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <typename image_scanner_type>
|
|
void setup_grid_detection_templates (
|
|
image_scanner_type& scanner,
|
|
const std::vector<std::vector<rectangle> >& rects,
|
|
unsigned int cells_x,
|
|
unsigned int cells_y,
|
|
double min_match_score = 0.75
|
|
)
|
|
{
|
|
const std::vector<rectangle>& object_boxes = determine_object_boxes(scanner, rects, min_match_score);
|
|
for (unsigned long i = 0; i < object_boxes.size(); ++i)
|
|
{
|
|
scanner.add_detection_template(object_boxes[i], create_grid_detection_template(object_boxes[i], cells_x, cells_y));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <typename image_scanner_type>
|
|
void setup_grid_detection_templates_verbose (
|
|
image_scanner_type& scanner,
|
|
const std::vector<std::vector<rectangle> >& rects,
|
|
unsigned int cells_x,
|
|
unsigned int cells_y,
|
|
double min_match_score = 0.75
|
|
)
|
|
{
|
|
const std::vector<rectangle>& object_boxes = determine_object_boxes(scanner, rects, min_match_score);
|
|
std::cout << "number of detection templates: "<< object_boxes.size() << std::endl;
|
|
for (unsigned long i = 0; i < object_boxes.size(); ++i)
|
|
{
|
|
std::cout << " object box " << i << ": width: " << object_boxes[i].width()
|
|
<< " height: "<< object_boxes[i].height() << std::endl;
|
|
scanner.add_detection_template(object_boxes[i], create_grid_detection_template(object_boxes[i], cells_x, cells_y));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
}
|
|
|
|
#endif // DLIB_SCAN_IMaGE_PYRAMID_TOOLS_Hh_
|
|
|