1.frontal_face_detector detector = get_frontal_face_detector();
2.typedef object_detector<scan_fhog_pyramid<pyramid_down<6> > > frontal_face_detector;
3.
class pyramid_down : noncopyable
{
public:
COMPILE_TIME_ASSERT(N > 0);
template <typename T>
vector<double,2> point_down (
const vector<T,2>& p
) const
{
const double ratio = (N-1.0)/N;
return (p - 0.3)*ratio;
}
template <typename T>
vector<double,2> point_up (
const vector<T,2>& p
) const
{
const double ratio = N/(N-1.0);
return p*ratio + 0.3;
}
// -----------------------------
template <typename T>
vector<double,2> point_down (
const vector<T,2>& p,
unsigned int levels
) const
{
vector<double,2> temp = p;
for (unsigned int i = 0; i < levels; ++i)
temp = point_down(temp);
return temp;
}
template <typename T>
vector<double,2> point_up (
const vector<T,2>& p,
unsigned int levels
) const
{
vector<double,2> temp = p;
for (unsigned int i = 0; i < levels; ++i)
temp = point_up(temp);
return temp;
}
// -----------------------------
drectangle rect_up (
const drectangle& rect
) const
{
return drectangle(point_up(rect.tl_corner()), point_up(rect.br_corner()));
}
drectangle rect_up (
const drectangle& rect,
unsigned int levels
) const
{
return drectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels));
}
// -----------------------------
drectangle rect_down (
const drectangle& rect
) const
{
return drectangle(point_down(rect.tl_corner()), point_down(rect.br_corner()));
}
drectangle rect_down (
const drectangle& rect,
unsigned int levels
) const
{
return drectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels));
}
template <
typename in_image_type,
typename out_image_type
>
void operator() (
const in_image_type& original,
out_image_type& down
) const
{
// make sure requires clause is not broken
DLIB_ASSERT(is_same_object(original, down) == false,
"\t void pyramid_down::operator()"
<< "\n\t is_same_object(original, down): " << is_same_object(original, down)
<< "\n\t this: " << this
);
typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;
typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;
COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );
COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );
set_image_size(down, ((N-1)*num_rows(original))/N+0.5, ((N-1)*num_columns(original))/N+0.5);
resize_image(original, down);
}
template <
typename image_type
>
void operator() (
image_type& img
) const
{
image_type temp;
(*this)(img, temp);
swap(temp, img);
}
};
template <>
class pyramid_down<1> : public pyramid_disable {};
template <>
class pyramid_down<2> : public dlib::impl::pyramid_down_2_1 {};
template <>
class pyramid_down<3> : public dlib::impl::pyramid_down_3_2 {};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <unsigned int N>
double pyramid_rate(const pyramid_down<N>&)
{
return (N-1.0)/N;
}
// ----------------------------------------------------------------------------------------
template <
typename pyramid_type,
typename image_type1,
typename image_type2
>
void create_tiled_pyramid (
const image_type1& img,
image_type2& out_img,
std::vector<rectangle>& rects,
const unsigned long padding = 10,
const unsigned long outer_padding = 0
)
{
DLIB_ASSERT(!is_same_object(img, out_img));
rects.clear();
if (num_rows(img)*num_columns(img) == 0)
{
set_image_size(out_img,0,0);
return;
}
const long min_height = 5;
pyramid_type pyr;
std::vector<matrix<rgb_pixel>> pyramid;
matrix<rgb_pixel> temp;
assign_image(temp, img);
pyramid.push_back(std::move(temp));
// build the whole pyramid
while(true)
{
matrix<rgb_pixel> temp;
pyr(pyramid.back(), temp);
if (temp.size() == 0 || temp.nr() < min_height)
break;
pyramid.push_back(std::move(temp));
}
// figure out output image size
long total_height = 0;
for (auto&& i : pyramid)
total_height += i.nr()+padding;
total_height -= padding*2; // don't add unnecessary padding to the very right side.
long height = 0;
long prev_width = 0;
for (auto&& i : pyramid)
{
// Figure out how far we go on the first column. We go until the next image can
// fit next to the previous one, which means we can double back for the second
// column of images.
if (i.nc() <= img.nc()-prev_width-(long)padding &&
(height-img.nr())*2 >= (total_height-img.nr()))
{
break;
}
height += i.nr() + padding;
prev_width = i.nc();
}
height -= padding; // don't add unnecessary padding to the very right side.
const long width = img.nc();
set_image_size(out_img,height+outer_padding*2,width+outer_padding*2);
assign_all_pixels(out_img, 0);
long y = outer_padding;
size_t i = 0;
while(y < height+(long)outer_padding)
{
rectangle rect = translate_rect(get_rect(pyramid[i]),point(outer_padding,y));
DLIB_ASSERT(get_rect(out_img).contains(rect));
rects.push_back(rect);
auto si = sub_image(out_img, rect);
assign_image(si, pyramid[i]);
y += pyramid[i].nr()+padding;
++i;
}
y -= padding;
while (i < pyramid.size())
{
point p1(outer_padding+width-1,y-1);
point p2 = p1 - get_rect(pyramid[i]).br_corner();
rectangle rect(p1,p2);
DLIB_ASSERT(get_rect(out_img).contains(rect));
// don't keep going on the last row if it would intersect the original image.
if (!get_rect(img).intersect(rect).is_empty())
break;
rects.push_back(rect);
auto si = sub_image(out_img, rect);
assign_image(si, pyramid[i]);
y -= pyramid[i].nr()+padding;
++i;
}
}