Commit 30e073d6 authored by Davis King's avatar Davis King

Reworked the scan_image() routine to make it run faster. Also added

a new function called sum_filter().
parent 6c0f5980
......@@ -9,6 +9,7 @@
#include "../matrix.h"
#include "../algs.h"
#include "../rand.h"
#include "../array2d.h"
namespace dlib
{
......@@ -106,6 +107,100 @@ namespace dlib
return static_cast<double>(temp);
}
// ----------------------------------------------------------------------------------------
template <
typename image_type1,
typename image_type2
>
void sum_filter (
const image_type1& img,
image_type2& out,
const rectangle& rect
)
{
DLIB_ASSERT(img.nr() == out.nr() &&
img.nc() == out.nc(),
"\t void sum_filter()"
<< "\n\t Invalid arguments given to this function."
<< "\n\t img.nr(): " << img.nr()
<< "\n\t img.nc(): " << img.nc()
<< "\n\t out.nr(): " << out.nr()
<< "\n\t out.nc(): " << out.nc()
);
typedef typename image_type1::type pixel_type;
typedef typename promote<pixel_type>::type ptype;
std::vector<ptype> column_sum;
column_sum.resize(img.nc() + rect.width(),0);
const long top = -1 + rect.top();
const long bottom = -1 + rect.bottom();
long left = rect.left()-1;
// initialize column_sum at row -1
for (unsigned long j = 0; j < column_sum.size(); ++j)
{
rectangle strip(left,top,left,bottom);
strip = strip.intersect(get_rect(img));
if (!strip.is_empty())
{
column_sum[j] = sum(matrix_cast<ptype>(subm(array_to_matrix(img),strip)));
}
++left;
}
const rectangle area = get_rect(img);
// save width to avoid computing them over and over
const long width = rect.width();
// Now do the bulk of the scanning work.
for (long r = 0; r < img.nr(); ++r)
{
// set to sum at point(-1,r). i.e. should be equal to sum_of_rects_in_images(images, rects, point(-1,r))
// We compute it's value in the next loop.
ptype cur_sum = 0;
// Update the first part of column_sum since we only work on the c+width part of column_sum
// in the main loop.
const long top = r + rect.top() - 1;
const long bottom = r + rect.bottom();
for (long k = 0; k < width; ++k)
{
const long right = k-width + rect.right();
const ptype br_corner = area.contains(right,bottom) ? img[bottom][right] : 0;
const ptype tr_corner = area.contains(right,top) ? img[top][right] : 0;
// update the sum in this column now that we are on the next row
column_sum[k] = column_sum[k] + br_corner - tr_corner;
cur_sum += column_sum[k];
}
for (long c = 0; c < img.nc(); ++c)
{
const long top = r + rect.top() - 1;
const long bottom = r + rect.bottom();
const long right = c + rect.right();
const ptype br_corner = area.contains(right,bottom) ? img[bottom][right] : 0;
const ptype tr_corner = area.contains(right,top) ? img[top][right] : 0;
// update the sum in this column now that we are on the next row
column_sum[c+width] = column_sum[c+width] + br_corner - tr_corner;
// add in the new right side of the rect and subtract the old right side.
cur_sum = cur_sum + column_sum[c+width] - column_sum[c];
out[r][c] += cur_sum;
}
}
}
// ----------------------------------------------------------------------------------------
template <
......@@ -143,127 +238,23 @@ namespace dlib
if (max_dets == 0)
return;
dlib::rand rnd;
typedef typename image_array_type::type::type pixel_type;
typedef typename promote<pixel_type>::type ptype;
std::vector<std::vector<ptype> > column_sums(rects.size());
for (unsigned long i = 0; i < column_sums.size(); ++i)
{
const typename image_array_type::type& img = images[rects[i].first];
column_sums[i].resize(img.nc() + rects[i].second.width(),0);
const long top = -1 + rects[i].second.top();
const long bottom = -1 + rects[i].second.bottom();
long left = rects[i].second.left()-1;
// initialize column_sums[i] at row -1
for (unsigned long j = 0; j < column_sums[i].size(); ++j)
{
rectangle strip(left,top,left,bottom);
strip = strip.intersect(get_rect(img));
if (!strip.is_empty())
{
column_sums[i][j] = sum(matrix_cast<ptype>(subm(array_to_matrix(img),strip)));
}
++left;
}
}
const rectangle area = get_rect(images[0]);
array2d<ptype> accum(images[0].nr(), images[0].nc());
assign_all_pixels(accum, 0);
// Figure out the area of the image where we won't need to do boundary checking
// when sliding the boxes around.
rectangle bound = dlib::impl::bounding_box_of_rects(rects, point(0,0));
rectangle free_area = get_rect(images[0]);
free_area.left() -= bound.left();
free_area.top() -= bound.top()-1;
free_area.right() -= bound.right();
free_area.bottom() -= bound.bottom();
// save widths to avoid computing them over and over
std::vector<long> widths(rects.size());
for (unsigned long i = 0; i < rects.size(); ++i)
widths[i] = rects[i].second.width();
sum_filter(images[rects[i].first], accum, rects[i].second);
unsigned long count = 0;
// Now do the bulk of the scanning work.
for (long r = 0; r < images[0].nr(); ++r)
dlib::rand rnd;
for (long r = 0; r < accum.nr(); ++r)
{
// set to sum at point(-1,r). i.e. should be equal to sum_of_rects_in_images(images, rects, point(-1,r))
// We compute it's value in the next loop.
ptype cur_sum = 0;
// Update the first part of column_sums since we only work on the c+width part of column_sums
// in the main loop.
for (unsigned long i = 0; i < rects.size(); ++i)
{
const typename image_array_type::type& img = images[rects[i].first];
const long top = r + rects[i].second.top() - 1;
const long bottom = r + rects[i].second.bottom();
const long width = rects[i].second.width();
for (long k = 0; k < width; ++k)
{
const long right = k-width + rects[i].second.right();
const ptype br_corner = area.contains(right,bottom) ? img[bottom][right] : 0;
const ptype tr_corner = area.contains(right,top) ? img[top][right] : 0;
// update the sum in this column now that we are on the next row
column_sums[i][k] = column_sums[i][k] + br_corner - tr_corner;
cur_sum += column_sums[i][k];
}
}
for (long c = 0; c < images[0].nc(); ++c)
for (long c = 0; c < accum.nc(); ++c)
{
// if we don't need to do the bounds checking on the image
if (free_area.contains(c,r))
{
for (unsigned long i = 0; i < rects.size(); ++i)
{
const typename image_array_type::type& img = images[rects[i].first];
const long top = r + rects[i].second.top() - 1;
const long bottom = r + rects[i].second.bottom();
const long right = c + rects[i].second.right();
const long width = widths[i];
const ptype br_corner = img[bottom][right];
const ptype tr_corner = img[top][right];
// update the sum in this column now that we are on the next row
column_sums[i][c+width] = column_sums[i][c+width] + br_corner - tr_corner;
// add in the new right side of the rect and subtract the old right side.
cur_sum = cur_sum + column_sums[i][c+width] - column_sums[i][c];
}
}
else
{
for (unsigned long i = 0; i < rects.size(); ++i)
{
const typename image_array_type::type& img = images[rects[i].first];
const long top = r + rects[i].second.top() - 1;
const long bottom = r + rects[i].second.bottom();
const long right = c + rects[i].second.right();
const long width = widths[i];
const ptype br_corner = area.contains(right,bottom) ? img[bottom][right] : 0;
const ptype tr_corner = area.contains(right,top) ? img[top][right] : 0;
// update the sum in this column now that we are on the next row
column_sums[i][c+width] = column_sums[i][c+width] + br_corner - tr_corner;
// add in the new right side of the rect and subtract the old right side.
cur_sum = cur_sum + column_sums[i][c+width] - column_sums[i][c];
}
}
const ptype cur_sum = accum[r][c];
if (cur_sum >= thresh)
{
++count;
......
......@@ -10,6 +10,31 @@
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename image_type1,
typename image_type2
>
void sum_filter (
const image_type1& img,
image_type2& out,
const rectangle& rect
)
/*!
requires
- out.nr() == img.nr()
- out.nc() == img.nc()
- image_type1 == an implementation of array2d/array2d_kernel_abstract.h
and it must contain a scalar type
- image_type2 == an implementation of array2d/array2d_kernel_abstract.h
and it must contain a scalar type
ensures
- for all valid r and c:
- let SUM(r,c) == sum of pixels inside the rectangle translate_rect(rect, point(c,r))
- #out[r][c] == out[r][c] + SUM(r,c)
!*/
// ----------------------------------------------------------------------------------------
template <
......
......@@ -28,6 +28,30 @@ namespace
// should start with "test."
logger dlog("test.scan_image");
// ----------------------------------------------------------------------------------------
template <typename image_type1, typename image_type2>
void sum_filter_i (
const image_type1& img,
image_type2& out,
const rectangle& rect
)
{
typedef typename image_type1::type pixel_type;
typedef typename promote<pixel_type>::type ptype;
integral_image_generic<ptype> iimg;
iimg.load(img);
for (long r = 0; r < img.nr(); ++r)
{
for (long c = 0; c < img.nc(); ++c)
{
const rectangle temp = translate_rect(rect, point(c,r)).intersect(get_rect(iimg));
if (temp.is_empty() == false)
out[r][c] += iimg.get_sum_of_area(temp);
}
}
}
// ----------------------------------------------------------------------------------------
......@@ -364,6 +388,58 @@ namespace
}
}
// ----------------------------------------------------------------------------------------
template <typename pixel_type>
void test_sum_filter (
)
{
dlib::rand rnd;
for (int k = 0; k < 20; ++k)
{
print_spinner();
array2d<pixel_type> img(1 + rnd.get_random_32bit_number()%100,
1 + rnd.get_random_32bit_number()%100);
for (long r = 0; r < img.nr(); ++r)
{
for (long c = 0; c < img.nc(); ++c)
{
img[r][c] = 100*(rnd.get_random_double()-0.5);
}
}
array2d<long> test1(img.nr(), img.nc());
array2d<double> test2(img.nr(), img.nc());
array2d<long> test1_i(img.nr(), img.nc());
array2d<double> test2_i(img.nr(), img.nc());
assign_all_pixels(test1, 0);
assign_all_pixels(test2, 0);
assign_all_pixels(test1_i, 0);
assign_all_pixels(test2_i, 0);
for (int i = 0; i < 10; ++i)
{
const long width = rnd.get_random_32bit_number()%10 + 1;
const long height = rnd.get_random_32bit_number()%10 + 1;
const point p(rnd.get_random_32bit_number()%img.nc(),
rnd.get_random_32bit_number()%img.nr());
const rectangle rect = centered_rect(p, width, height);
sum_filter(img, test1, rect);
sum_filter(img, test2, rect);
sum_filter(img, test1_i, rect);
sum_filter(img, test2_i, rect);
DLIB_TEST(array_to_matrix(test1) == array_to_matrix(test1_i));
DLIB_TEST(array_to_matrix(test2) == array_to_matrix(test2_i));
}
}
}
// ----------------------------------------------------------------------------------------
class scan_image_tester : public tester
......@@ -384,6 +460,9 @@ namespace
run_test3<unsigned char>(-1);
run_test3<double>(1);
run_test3<double>(-1);
test_sum_filter<unsigned char>();
test_sum_filter<double>();
}
} a;
......
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