Commit 9e54a208 authored by Davis King's avatar Davis King

Refactored create_tiled_pyramid() code to remove unnecessary copying. It's now

about 2x faster.  The code is cleaner too.
parent 8c2d87db
...@@ -1023,99 +1023,134 @@ namespace dlib ...@@ -1023,99 +1023,134 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < namespace impl
typename pyramid_type, {
typename image_type1, template <typename pyramid_type>
typename image_type2 void compute_tiled_image_pyramid_details (
> const pyramid_type& pyr,
void create_tiled_pyramid ( long nr,
const image_type1& img, long nc,
image_type2& out_img, const unsigned long padding,
const unsigned long outer_padding,
std::vector<rectangle>& rects, std::vector<rectangle>& rects,
const unsigned long padding = 10, long& pyramid_image_nr,
const unsigned long outer_padding = 0 long& pyramid_image_nc
) )
{ {
DLIB_ASSERT(!is_same_object(img, out_img));
rects.clear(); rects.clear();
if (num_rows(img)*num_columns(img) == 0) if (nr*nc == 0)
{ {
set_image_size(out_img,0,0); pyramid_image_nr = 0;
pyramid_image_nc = 0;
return; return;
} }
const long min_height = 5; const long min_height = 5;
pyramid_type pyr; rects.reserve(100);
std::vector<matrix<rgb_pixel>> pyramid; rects.push_back(rectangle(nc,nr));
matrix<rgb_pixel> temp;
assign_image(temp, img);
pyramid.push_back(std::move(temp));
// build the whole pyramid // build the whole pyramid
while(true) while(true)
{ {
matrix<rgb_pixel> temp; find_pyramid_down_output_image_size(pyr, nr, nc);
pyr(pyramid.back(), temp); if (nr*nc == 0 || nr < min_height)
if (temp.size() == 0 || temp.nr() < min_height)
break; break;
pyramid.push_back(std::move(temp)); rects.push_back(rectangle(nc,nr));
} }
// figure out output image size // figure out output image size
long total_height = 0; long total_height = 0;
for (auto&& i : pyramid) for (auto&& i : rects)
total_height += i.nr()+padding; total_height += i.height()+padding;
total_height -= padding*2; // don't add unnecessary padding to the very right side. total_height -= padding*2; // don't add unnecessary padding to the very right side.
long height = 0; long height = 0;
long prev_width = 0; long prev_width = 0;
for (auto&& i : pyramid) for (auto&& i : rects)
{ {
// Figure out how far we go on the first column. We go until the next image can // 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 // fit next to the previous one, which means we can double back for the second
// column of images. // column of images.
if (i.nc() <= img.nc()-prev_width-(long)padding && if (i.width() <= rects[0].width()-prev_width-(long)padding &&
(height-img.nr())*2 >= (total_height-img.nr())) (height-rects[0].height())*2 >= (total_height-rects[0].height()))
{ {
break; break;
} }
height += i.nr() + padding; height += i.height() + padding;
prev_width = i.nc(); prev_width = i.width();
} }
height -= padding; // don't add unnecessary padding to the very right side. height -= padding; // don't add unnecessary padding to the very right side.
const long width = img.nc(); const long width = rects[0].width();
set_image_size(out_img,height+outer_padding*2,width+outer_padding*2); pyramid_image_nr = height+outer_padding*2;
assign_all_pixels(out_img, 0); pyramid_image_nc = width+outer_padding*2;
long y = outer_padding; long y = outer_padding;
size_t i = 0; size_t i = 0;
while(y < height+(long)outer_padding) while(y < height+(long)outer_padding && i < rects.size())
{ {
rectangle rect = translate_rect(get_rect(pyramid[i]),point(outer_padding,y)); rects[i] = translate_rect(rects[i],point(outer_padding,y));
DLIB_ASSERT(get_rect(out_img).contains(rect)); DLIB_ASSERT(rectangle(pyramid_image_nc,pyramid_image_nr).contains(rects[i]));
rects.push_back(rect); y += rects[i].height()+padding;
auto si = sub_image(out_img, rect);
assign_image(si, pyramid[i]);
y += pyramid[i].nr()+padding;
++i; ++i;
} }
y -= padding; y -= padding;
while (i < pyramid.size()) while (i < rects.size())
{ {
point p1(outer_padding+width-1,y-1); point p1(outer_padding+width-1,y-1);
point p2 = p1 - get_rect(pyramid[i]).br_corner(); point p2 = p1 - rects[i].br_corner();
rectangle rect(p1,p2); rectangle rect(p1,p2);
DLIB_ASSERT(get_rect(out_img).contains(rect)); DLIB_ASSERT(rectangle(pyramid_image_nc,pyramid_image_nr).contains(rect));
// don't keep going on the last row if it would intersect the original image. // don't keep going on the last row if it would intersect the original image.
if (!get_rect(img).intersect(rect).is_empty()) if (!rects[0].intersect(rect).is_empty())
break; break;
rects.push_back(rect);
auto si = sub_image(out_img, rect); rects[i] = rect;
assign_image(si, pyramid[i]); y -= rects[i].height()+padding;
y -= pyramid[i].nr()+padding;
++i; ++i;
} }
// Delete any extraneous rectangles if we broke out of the above loop early due to
// intersection with the original image.
rects.resize(i);
}
}
// ----------------------------------------------------------------------------------------
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));
long out_nr, out_nc;
pyramid_type pyr;
impl::compute_tiled_image_pyramid_details(pyr, img.nr(), img.nc(), padding, outer_padding, rects, out_nr, out_nc);
set_image_size(out_img, out_nr, out_nc);
assign_all_pixels(out_img, 0);
if (rects.size() == 0)
return;
// now build the image pyramid into out_img
auto si = sub_image(out_img, rects[0]);
assign_image(si, img);
for (size_t i = 1; i < rects.size(); ++i)
{
auto s1 = sub_image(out_img, rects[i-1]);
auto s2 = sub_image(out_img, rects[i]);
pyr(s1,s2);
}
} }
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
......
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