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

about 2x faster.  The code is cleaner too.
This commit is contained in:
Davis King 2017-09-04 21:56:24 -04:00
parent 8c2d87db09
commit 9e54a2088a
1 changed files with 108 additions and 73 deletions

View File

@ -1021,6 +1021,100 @@ namespace dlib
nc = 0;
}
// ----------------------------------------------------------------------------------------
namespace impl
{
template <typename pyramid_type>
void compute_tiled_image_pyramid_details (
const pyramid_type& pyr,
long nr,
long nc,
const unsigned long padding,
const unsigned long outer_padding,
std::vector<rectangle>& rects,
long& pyramid_image_nr,
long& pyramid_image_nc
)
{
rects.clear();
if (nr*nc == 0)
{
pyramid_image_nr = 0;
pyramid_image_nc = 0;
return;
}
const long min_height = 5;
rects.reserve(100);
rects.push_back(rectangle(nc,nr));
// build the whole pyramid
while(true)
{
find_pyramid_down_output_image_size(pyr, nr, nc);
if (nr*nc == 0 || nr < min_height)
break;
rects.push_back(rectangle(nc,nr));
}
// figure out output image size
long total_height = 0;
for (auto&& i : rects)
total_height += i.height()+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 : rects)
{
// 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.width() <= rects[0].width()-prev_width-(long)padding &&
(height-rects[0].height())*2 >= (total_height-rects[0].height()))
{
break;
}
height += i.height() + padding;
prev_width = i.width();
}
height -= padding; // don't add unnecessary padding to the very right side.
const long width = rects[0].width();
pyramid_image_nr = height+outer_padding*2;
pyramid_image_nc = width+outer_padding*2;
long y = outer_padding;
size_t i = 0;
while(y < height+(long)outer_padding && i < rects.size())
{
rects[i] = translate_rect(rects[i],point(outer_padding,y));
DLIB_ASSERT(rectangle(pyramid_image_nc,pyramid_image_nr).contains(rects[i]));
y += rects[i].height()+padding;
++i;
}
y -= padding;
while (i < rects.size())
{
point p1(outer_padding+width-1,y-1);
point p2 = p1 - rects[i].br_corner();
rectangle rect(p1,p2);
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.
if (!rects[0].intersect(rect).is_empty())
break;
rects[i] = rect;
y -= rects[i].height()+padding;
++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 <
@ -1038,84 +1132,25 @@ namespace dlib
{
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;
long out_nr, out_nc;
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));
}
impl::compute_tiled_image_pyramid_details(pyr, img.nr(), img.nc(), padding, outer_padding, rects, out_nr, out_nc);
// 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);
set_image_size(out_img, out_nr, out_nc);
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;
}
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);
}
}
// ----------------------------------------------------------------------------------------