mirror of https://github.com/davisking/dlib.git
Added the max_filter() routine.
This commit is contained in:
parent
c1c8267ba5
commit
fce8eaabe4
|
@ -715,6 +715,189 @@ namespace dlib
|
|||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
namespace impl
|
||||
{
|
||||
template <typename T>
|
||||
class fast_deque
|
||||
{
|
||||
/*
|
||||
This is a fast and minimal implementation of std::deque for
|
||||
use with the max_filter.
|
||||
|
||||
This object assumes that no more than max_size elements
|
||||
will ever be pushed into it at a time.
|
||||
*/
|
||||
public:
|
||||
|
||||
explicit fast_deque(unsigned long max_size)
|
||||
{
|
||||
// find a power of two that upper bounds max_size
|
||||
mask = 2;
|
||||
while (mask < max_size)
|
||||
mask *= 2;
|
||||
|
||||
clear();
|
||||
|
||||
data.resize(mask);
|
||||
--mask; // make into bit mask
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
first = 1;
|
||||
last = 0;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
void pop_back()
|
||||
{
|
||||
last = (last-1)&mask;
|
||||
--size;
|
||||
}
|
||||
|
||||
void push_back(const T& item)
|
||||
{
|
||||
last = (last+1)&mask;
|
||||
++size;
|
||||
data[last] = item;
|
||||
}
|
||||
|
||||
void pop_front()
|
||||
{
|
||||
first = (first+1)&mask;
|
||||
--size;
|
||||
}
|
||||
|
||||
const T& front() const
|
||||
{
|
||||
return data[first];
|
||||
}
|
||||
|
||||
const T& back() const
|
||||
{
|
||||
return data[last];
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<T> data;
|
||||
unsigned long mask;
|
||||
unsigned long first;
|
||||
unsigned long last;
|
||||
unsigned long size;
|
||||
};
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
typename image_type1,
|
||||
typename image_type2
|
||||
>
|
||||
void max_filter (
|
||||
image_type1& img,
|
||||
image_type2& out,
|
||||
const long width,
|
||||
const long height,
|
||||
const typename image_type1::type& thresh
|
||||
)
|
||||
{
|
||||
DLIB_ASSERT((width%2)==1 &&
|
||||
(height%2)==1 &&
|
||||
width > 0 &&
|
||||
height > 0 &&
|
||||
out.nr() == img.nr() &&
|
||||
out.nc() == img.nc() &&
|
||||
is_same_object(img,out) == false,
|
||||
"\t void max_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()
|
||||
<< "\n\t width: " << width
|
||||
<< "\n\t height: " << height
|
||||
<< "\n\t is_same_object(img,out): " << is_same_object(img,out)
|
||||
);
|
||||
|
||||
typedef typename image_type1::type pixel_type;
|
||||
|
||||
|
||||
dlib::impl::fast_deque<std::pair<long,pixel_type> > Q(std::max(width,height));
|
||||
|
||||
const long last_col = std::max(img.nc(), (width/2));
|
||||
const long last_row = std::max(img.nr(), (height/2));
|
||||
|
||||
// run max filter along rows of img
|
||||
for (long r = 0; r < img.nr(); ++r)
|
||||
{
|
||||
Q.clear();
|
||||
for (long c = 0; c < width/2 && c < img.nc(); ++c)
|
||||
{
|
||||
while (!Q.empty() && img[r][c] >= Q.back().second)
|
||||
Q.pop_back();
|
||||
Q.push_back(make_pair(c,img[r][c]));
|
||||
}
|
||||
|
||||
for (long c = width/2; c < img.nc(); ++c)
|
||||
{
|
||||
while (!Q.empty() && img[r][c] >= Q.back().second)
|
||||
Q.pop_back();
|
||||
while (!Q.empty() && Q.front().first <= c-width)
|
||||
Q.pop_front();
|
||||
Q.push_back(make_pair(c,img[r][c]));
|
||||
|
||||
img[r][c-(width/2)] = Q.front().second;
|
||||
}
|
||||
|
||||
for (long c = last_col; c < img.nc() + (width/2); ++c)
|
||||
{
|
||||
while (!Q.empty() && Q.front().first <= c-width)
|
||||
Q.pop_front();
|
||||
|
||||
img[r][c-(width/2)] = Q.front().second;
|
||||
}
|
||||
}
|
||||
|
||||
// run max filter along columns of img. Store result in out.
|
||||
for (long cc = 0; cc < img.nc(); ++cc)
|
||||
{
|
||||
Q.clear();
|
||||
for (long rr = 0; rr < height/2 && rr < img.nr(); ++rr)
|
||||
{
|
||||
while (!Q.empty() && img[rr][cc] >= Q.back().second)
|
||||
Q.pop_back();
|
||||
Q.push_back(make_pair(rr,img[rr][cc]));
|
||||
}
|
||||
|
||||
for (long rr = height/2; rr < img.nr(); ++rr)
|
||||
{
|
||||
while (!Q.empty() && img[rr][cc] >= Q.back().second)
|
||||
Q.pop_back();
|
||||
while (!Q.empty() && Q.front().first <= rr-height)
|
||||
Q.pop_front();
|
||||
Q.push_back(make_pair(rr,img[rr][cc]));
|
||||
|
||||
out[rr-(height/2)][cc] += std::max(Q.front().second, thresh);
|
||||
}
|
||||
|
||||
for (long rr = last_row; rr < img.nr() + (height/2); ++rr)
|
||||
{
|
||||
while (!Q.empty() && Q.front().first <= rr-height)
|
||||
Q.pop_front();
|
||||
|
||||
out[rr-(height/2)][cc] += std::max(Q.front().second, thresh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
|
|
@ -338,6 +338,45 @@ namespace dlib
|
|||
- #out[r][c] == out[r][c] + SUM(r,c)
|
||||
!*/
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
typename image_type1,
|
||||
typename image_type2
|
||||
>
|
||||
void max_filter (
|
||||
image_type1& img,
|
||||
image_type2& out,
|
||||
const long width,
|
||||
const long height,
|
||||
const typename image_type1::type& thresh
|
||||
);
|
||||
/*!
|
||||
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
|
||||
- is_same_object(img,out) == false
|
||||
- (width%2)==1 && (height%2)==1
|
||||
(i.e. width and height must be odd)
|
||||
- width > 0 && height > 0
|
||||
ensures
|
||||
- for all valid r and c:
|
||||
- let MAX(r,c) == maximum of pixels from img which are inside the rectangle
|
||||
centered_rect(point(c,r), width, height)
|
||||
- if (MAX(r,c) >= thresh)
|
||||
- #out[r][c] == out[r][c] + MAX(r,c)
|
||||
- else
|
||||
- #out[r][c] == out[r][c] + thresh
|
||||
- Does not change the size of img.
|
||||
- Uses img as scratch space. Therefore, the pixel values in img will have
|
||||
been modified by this function. That is, max_filter() destroys the contents
|
||||
of img.
|
||||
!*/
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
|
|
@ -440,6 +440,105 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
typename image_type1,
|
||||
typename image_type2
|
||||
>
|
||||
void naive_max_filter (
|
||||
const image_type1& img,
|
||||
image_type2& out,
|
||||
const rectangle& rect,
|
||||
typename image_type1::type thresh
|
||||
)
|
||||
{
|
||||
typedef typename image_type1::type pixel_type;
|
||||
|
||||
const rectangle area = get_rect(img);
|
||||
for (long r = 0; r < img.nr(); ++r)
|
||||
{
|
||||
for (long c = 0; c < img.nc(); ++c)
|
||||
{
|
||||
const rectangle win = translate_rect(rect,point(c,r)).intersect(area);
|
||||
if (!win.is_empty())
|
||||
out[r][c] += std::max(dlib::max(subm(array_to_matrix(img),win)), thresh);
|
||||
else
|
||||
out[r][c] += thresh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
void test_max_filter(long rows, long cols, long width, long height, dlib::rand& rnd)
|
||||
{
|
||||
array2d<int> img(rows, cols);
|
||||
rectangle rect = centered_rect(0,0, width, height);
|
||||
|
||||
array2d<int> out(img.nr(),img.nc());
|
||||
assign_all_pixels(out, 0);
|
||||
array2d<int> out2(img.nr(),img.nc());
|
||||
assign_all_pixels(out2, 0);
|
||||
|
||||
for (long r = 0; r < img.nr(); ++r)
|
||||
{
|
||||
for (long c = 0; c < img.nc(); ++c)
|
||||
{
|
||||
img[r][c] = rnd.get_random_32bit_number();
|
||||
}
|
||||
}
|
||||
|
||||
const int thresh = rnd.get_random_32bit_number();
|
||||
|
||||
naive_max_filter(img, out2, rect, thresh);
|
||||
max_filter(img, out, rect.width(), rect.height(), thresh);
|
||||
|
||||
DLIB_TEST_MSG(array_to_matrix(out) == array_to_matrix(out2),
|
||||
"rows: "<< rows
|
||||
<< "\ncols: "<< rows
|
||||
<< "\nwidth: "<< width
|
||||
<< "\nheight: "<< height );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
void test_max_filter()
|
||||
{
|
||||
dlib::rand rnd;
|
||||
for (int iter = 0; iter < 300; ++iter)
|
||||
{
|
||||
print_spinner();
|
||||
test_max_filter(0,0,1,1,rnd);
|
||||
test_max_filter(0,0,3,1,rnd);
|
||||
test_max_filter(0,0,3,3,rnd);
|
||||
test_max_filter(0,0,1,3,rnd);
|
||||
test_max_filter(1,1,1,1,rnd);
|
||||
test_max_filter(2,2,1,1,rnd);
|
||||
test_max_filter(3,3,1,1,rnd);
|
||||
test_max_filter(3,3,3,3,rnd);
|
||||
test_max_filter(3,3,3,5,rnd);
|
||||
test_max_filter(20,20,901,901,rnd);
|
||||
test_max_filter(5,5,1,5,rnd);
|
||||
test_max_filter(50,50,9,9,rnd);
|
||||
test_max_filter(50,50,9,9,rnd);
|
||||
test_max_filter(50,50,9,9,rnd);
|
||||
test_max_filter(20,20,1,901,rnd);
|
||||
test_max_filter(20,20,3,901,rnd);
|
||||
test_max_filter(20,20,901,1,rnd);
|
||||
}
|
||||
|
||||
for (int iter = 0; iter < 200; ++iter)
|
||||
{
|
||||
print_spinner();
|
||||
test_max_filter((int)rnd.get_random_8bit_number()%100+1,
|
||||
(int)rnd.get_random_8bit_number()%100+1,
|
||||
(int)rnd.get_random_8bit_number()*2+1,
|
||||
(int)rnd.get_random_8bit_number()*2+1,
|
||||
rnd);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
class scan_image_tester : public tester
|
||||
|
@ -454,6 +553,8 @@ namespace
|
|||
void perform_test (
|
||||
)
|
||||
{
|
||||
test_max_filter();
|
||||
|
||||
run_test1();
|
||||
run_test2();
|
||||
run_test3<unsigned char>(1);
|
||||
|
|
Loading…
Reference in New Issue