Commit d8a23c87 authored by Davis King's avatar Davis King

Added pyramid_rate(), create_tiled_pyramid(), image_to_tiled_pyramid(), and

tiled_pyramid_to_image().
parent 1a739219
......@@ -969,6 +969,180 @@ namespace dlib
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <unsigned int N>
double pyramid_rate(const pyramid_down<N>&)
{
return N/(N+1.0);
}
// ----------------------------------------------------------------------------------------
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
)
{
DLIB_ASSERT(!is_same_object(img, out_img));
rects.clear();
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-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.
out_img.set_size(height,img.nc());
assign_all_pixels(out_img, 0);
long y = 0;
size_t i = 0;
while(y < height)
{
rectangle rect = translate_rect(get_rect(pyramid[i]),point(0,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(img.nc()-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;
}
}
// ----------------------------------------------------------------------------------------
template <
typename pyramid_type
>
dpoint image_to_tiled_pyramid (
const std::vector<rectangle>& rects,
double scale,
dpoint p
)
{
DLIB_CASSERT(rects.size() > 0);
DLIB_CASSERT(0 < scale && scale <= 1);
pyramid_type pyr;
// This scale factor maps this many levels down the pyramid
long pyramid_down_iter = static_cast<long>(std::log(scale)/std::log(pyramid_rate(pyr))+0.5);
pyramid_down_iter = put_in_range(0, (long)rects.size()-1, pyramid_down_iter);
return rects[pyramid_down_iter].tl_corner() + pyr.point_down(p, pyramid_down_iter);
}
// ----------------------------------------------------------------------------------------
template <
typename pyramid_type
>
drectangle image_to_tiled_pyramid (
const std::vector<rectangle>& rects,
double scale,
drectangle r
)
{
DLIB_ASSERT(rects.size() > 0);
DLIB_ASSERT(0 < scale && scale <= 1);
return drectangle(image_to_tiled_pyramid<pyramid_type>(rects, scale, r.tl_corner()),
image_to_tiled_pyramid<pyramid_type>(rects, scale, r.br_corner()));
}
// ----------------------------------------------------------------------------------------
template <
typename pyramid_type
>
dpoint tiled_pyramid_to_image (
const std::vector<rectangle>& rects,
dpoint p
)
{
DLIB_CASSERT(rects.size() > 0);
size_t pyramid_down_iter = nearest_rect(rects, p);
p -= rects[pyramid_down_iter].tl_corner();
pyramid_type pyr;
return pyr.point_up(p, pyramid_down_iter);
}
// ----------------------------------------------------------------------------------------
template <
typename pyramid_type
>
drectangle tiled_pyramid_to_image (
const std::vector<rectangle>& rects,
drectangle r
)
{
DLIB_CASSERT(rects.size() > 0);
size_t pyramid_down_iter = nearest_rect(rects, dcenter(r));
dpoint origin = rects[pyramid_down_iter].tl_corner();
r = drectangle(r.tl_corner()-origin, r.br_corner()-origin);
pyramid_type pyr;
return pyr.rect_up(r, pyramid_down_iter);
}
// ----------------------------------------------------------------------------------------
}
......
......@@ -195,6 +195,164 @@ namespace dlib
!*/
};
// ----------------------------------------------------------------------------------------
template <
unsigned int N
>
double pyramid_rate(
const pyramid_down<N>& pyr
);
/*!
ensures
- returns N/(N+1.0)
!*/
// ----------------------------------------------------------------------------------------
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
);
/*!
requires
- pyramid_type == one of the dlib::pyramid_down template instances defined above.
- is_same_object(img, out_img) == false
- image_type1 == an image object that implements the interface defined in
dlib/image_processing/generic_image.h
- image_type2 == an image object that implements the interface defined in
dlib/image_processing/generic_image.h
- for both pixel types P in the input and output images, we require:
- pixel_traits<P>::has_alpha == false
ensures
- Creates an image pyramid from the input image img. The pyramid is made using
pyramid_type. The highest resolution image is img and then all further
pyramid levels are generated from pyramid_type's downsampling. The entire
resulting pyramid is packed into a single image and stored in out_img.
- When packing pyramid levels into out_img, there will be padding pixels of
space between each sub-image.
- The resulting pyramid will be composed of #rects.size() images packed into
out_img. Moreover, #rects[i] is the location inside out_img of the i-th
pyramid level.
- #rects.size() > 0
- #rects[0] == get_rect(img). I.e. the first rectangle is the highest
resolution pyramid layer. Subsequent elements of #rects correspond to
smaller and smaller pyramid layers inside out_img.
!*/
// ----------------------------------------------------------------------------------------
template <
typename pyramid_type
>
dpoint image_to_tiled_pyramid (
const std::vector<rectangle>& rects,
double scale,
dpoint p
);
/*!
requires
- pyramid_type == one of the dlib::pyramid_down template instances defined above.
- 0 < scale <= 1
- rects.size() > 0
ensures
- The function create_tiled_pyramid() converts an image, img, to a "tiled
pyramid" called out_img. It also outputs a vector of rectangles, rect, that
show where each pyramid layer appears in out_img. Therefore,
image_to_tiled_pyramid() allows you to map from coordinates in img (i.e. p)
to coordinates in the tiled pyramid out_img, when given the rects metadata.
So given a point p in img, you can ask, what coordinate in out_img
corresponds to img[p.y()][p.x()] when things are scale times smaller? This
new coordinate is a location in out_img and is what is returned by this
function.
- A scale of 1 means we don't move anywhere in the pyramid scale space relative
to the input image while smaller values of scale mean we move down the
pyramid.
- Assumes pyramid_type is the pyramid class used to produce the tiled image.
!*/
// ----------------------------------------------------------------------------------------
template <
typename pyramid_type
>
drectangle image_to_tiled_pyramid (
const std::vector<rectangle>& rects,
double scale,
drectangle r
);
/*!
requires
- pyramid_type == one of the dlib::pyramid_down template instances defined above.
- 0 < scale <= 1
- rects.size() > 0
ensures
- This function maps from input image space to tiled pyramid coordinate space
just as the above image_to_tiled_pyramid() does, except it operates on
rectangle objects instead of points.
- Assumes pyramid_type is the pyramid class used to produce the tiled image.
!*/
// ----------------------------------------------------------------------------------------
template <
typename pyramid_type
>
dpoint tiled_pyramid_to_image (
const std::vector<rectangle>& rects,
dpoint p
);
/*!
requires
- pyramid_type == one of the dlib::pyramid_down template instances defined above.
- rects.size() > 0
ensures
- This function maps from a coordinate in a tiled pyramid to the corresponding
input image coordinate. Therefore, it is essentially the inverse of
image_to_tiled_pyramid().
- It should be noted that this function isn't an exact inverse of
image_to_tiled_pyramid(). This is because you can ask
image_to_tiled_pyramid() for the coordinates of points outside the input
image and they will be mapped to somewhere that doesn't have an inverse. But
for points actually inside the image this function performs an inverse
mapping.
- Assumes pyramid_type is the pyramid class used to produce the tiled image.
!*/
// ----------------------------------------------------------------------------------------
template <
typename pyramid_type
>
drectangle tiled_pyramid_to_image (
const std::vector<rectangle>& rects,
drectangle r
);
/*!
requires
- pyramid_type == one of the dlib::pyramid_down template instances defined above.
- rects.size() > 0
ensures
- This function maps from a coordinate in a tiled pyramid to the corresponding
input image coordinate. Therefore, it is essentially the inverse of
image_to_tiled_pyramid().
- It should be noted that this function isn't an exact inverse of
image_to_tiled_pyramid(). This is because you can ask
image_to_tiled_pyramid() for the coordinates of points outside the input
image and they will be mapped to somewhere that doesn't have an inverse. But
for points actually inside the image this function performs an inverse
mapping.
- Assumes pyramid_type is the pyramid class used to produce the tiled image.
!*/
// ----------------------------------------------------------------------------------------
}
......
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