mirror of
https://github.com/davisking/dlib.git
synced 2024-11-01 10:14:53 +08:00
Changed the interface for the spatially_filter_image() routines to take the filter
as a matrix rather than C-array. I also fixed a bug which showed up when using non-square filters. The bug would cause the edges of the output image to be incorrect.
This commit is contained in:
parent
3dc0f5a756
commit
4d8e96ef66
@ -8,6 +8,7 @@
|
||||
#include "../algs.h"
|
||||
#include "../assert.h"
|
||||
#include "../array2d.h"
|
||||
#include "../matrix.h"
|
||||
#include <limits>
|
||||
|
||||
namespace dlib
|
||||
@ -18,14 +19,12 @@ namespace dlib
|
||||
template <
|
||||
typename in_image_type,
|
||||
typename out_image_type,
|
||||
typename filter_type,
|
||||
long M,
|
||||
long N
|
||||
typename EXP
|
||||
>
|
||||
void spatially_filter_image (
|
||||
const in_image_type& in_img,
|
||||
out_image_type& out_img,
|
||||
const filter_type (&filter)[M][N],
|
||||
const matrix_exp<EXP>& filter,
|
||||
unsigned long scale = 1,
|
||||
bool use_abs = false
|
||||
)
|
||||
@ -33,11 +32,14 @@ namespace dlib
|
||||
COMPILE_TIME_ASSERT( pixel_traits<typename in_image_type::type>::has_alpha == false );
|
||||
COMPILE_TIME_ASSERT( pixel_traits<typename out_image_type::type>::has_alpha == false );
|
||||
|
||||
COMPILE_TIME_ASSERT(M%2 == 1);
|
||||
COMPILE_TIME_ASSERT(N%2 == 1);
|
||||
DLIB_ASSERT(scale > 0,
|
||||
DLIB_ASSERT(scale > 0 &&
|
||||
filter.nr()%2 == 1 &&
|
||||
filter.nc()%2 == 1,
|
||||
"\tvoid spatially_filter_image()"
|
||||
<< "\n\tYou can't give a scale of zero"
|
||||
<< "\n\t You can't give a scale of zero or a filter with even dimensions"
|
||||
<< "\n\t scale: "<< scale
|
||||
<< "\n\t filter.nr(): "<< filter.nr()
|
||||
<< "\n\t filter.nc(): "<< filter.nc()
|
||||
);
|
||||
DLIB_ASSERT(is_same_object(in_img, out_img) == false,
|
||||
"\tvoid spatially_filter_image()"
|
||||
@ -55,13 +57,13 @@ namespace dlib
|
||||
|
||||
out_img.set_size(in_img.nr(),in_img.nc());
|
||||
|
||||
zero_border_pixels(out_img, M/2, N/2);
|
||||
zero_border_pixels(out_img, filter.nc()/2, filter.nr()/2);
|
||||
|
||||
// figure out the range that we should apply the filter to
|
||||
const long first_row = M/2;
|
||||
const long first_col = N/2;
|
||||
const long last_row = in_img.nr() - M/2;
|
||||
const long last_col = in_img.nc() - N/2;
|
||||
const long first_row = filter.nr()/2;
|
||||
const long first_col = filter.nc()/2;
|
||||
const long last_row = in_img.nr() - filter.nr()/2;
|
||||
const long last_col = in_img.nc() - filter.nc()/2;
|
||||
|
||||
// apply the filter to the image
|
||||
for (long r = first_row; r < last_row; ++r)
|
||||
@ -71,13 +73,13 @@ namespace dlib
|
||||
typedef typename pixel_traits<typename in_image_type::type>::basic_pixel_type bp_type;
|
||||
typename promote<bp_type>::type p;
|
||||
typename promote<bp_type>::type temp = 0;
|
||||
for (long m = 0; m < M; ++m)
|
||||
for (long m = 0; m < filter.nr(); ++m)
|
||||
{
|
||||
for (long n = 0; n < N; ++n)
|
||||
for (long n = 0; n < filter.nc(); ++n)
|
||||
{
|
||||
// pull out the current pixel and put it into p
|
||||
p = get_pixel_intensity(in_img[r-M/2+m][c-N/2+n]);
|
||||
temp += p*filter[m][n];
|
||||
p = get_pixel_intensity(in_img[r-filter.nr()/2+m][c-filter.nc()/2+n]);
|
||||
temp += p*filter(m,n);
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,15 +110,14 @@ namespace dlib
|
||||
template <
|
||||
typename in_image_type,
|
||||
typename out_image_type,
|
||||
typename filter_type,
|
||||
long M,
|
||||
long N
|
||||
typename EXP1,
|
||||
typename EXP2
|
||||
>
|
||||
void spatially_filter_image (
|
||||
const in_image_type& in_img,
|
||||
out_image_type& out_img,
|
||||
const filter_type (&row_filter)[N],
|
||||
const filter_type (&col_filter)[M],
|
||||
const matrix_exp<EXP1>& row_filter,
|
||||
const matrix_exp<EXP2>& col_filter,
|
||||
unsigned long scale = 1,
|
||||
bool use_abs = false
|
||||
)
|
||||
@ -124,11 +125,18 @@ namespace dlib
|
||||
COMPILE_TIME_ASSERT( pixel_traits<typename in_image_type::type>::has_alpha == false );
|
||||
COMPILE_TIME_ASSERT( pixel_traits<typename out_image_type::type>::has_alpha == false );
|
||||
|
||||
COMPILE_TIME_ASSERT(M%2 == 1);
|
||||
COMPILE_TIME_ASSERT(N%2 == 1);
|
||||
DLIB_ASSERT(scale > 0,
|
||||
DLIB_ASSERT(scale > 0 &&
|
||||
row_filter.size()%2 == 1 &&
|
||||
col_filter.size()%2 == 1 &&
|
||||
is_vector(row_filter) &&
|
||||
is_vector(col_filter),
|
||||
"\tvoid spatially_filter_image()"
|
||||
<< "\n\tYou can't give a scale of zero"
|
||||
<< "\n\t Invalid inputs were given to this function."
|
||||
<< "\n\t scale: "<< scale
|
||||
<< "\n\t row_filter.size(): "<< row_filter.size()
|
||||
<< "\n\t col_filter.size(): "<< col_filter.size()
|
||||
<< "\n\t is_vector(row_filter): "<< is_vector(row_filter)
|
||||
<< "\n\t is_vector(col_filter): "<< is_vector(col_filter)
|
||||
);
|
||||
DLIB_ASSERT(is_same_object(in_img, out_img) == false,
|
||||
"\tvoid spatially_filter_image()"
|
||||
@ -146,13 +154,13 @@ namespace dlib
|
||||
|
||||
out_img.set_size(in_img.nr(),in_img.nc());
|
||||
|
||||
zero_border_pixels(out_img, M/2, N/2);
|
||||
zero_border_pixels(out_img, row_filter.size()/2, col_filter.size()/2);
|
||||
|
||||
// figure out the range that we should apply the filter to
|
||||
const long first_row = M/2;
|
||||
const long first_col = N/2;
|
||||
const long last_row = in_img.nr() - M/2;
|
||||
const long last_col = in_img.nc() - N/2;
|
||||
const long first_row = col_filter.size()/2;
|
||||
const long first_col = row_filter.size()/2;
|
||||
const long last_row = in_img.nr() - col_filter.size()/2;
|
||||
const long last_col = in_img.nc() - row_filter.size()/2;
|
||||
|
||||
typedef typename pixel_traits<typename in_image_type::type>::basic_pixel_type bp_type;
|
||||
|
||||
@ -168,11 +176,11 @@ namespace dlib
|
||||
{
|
||||
typename promote<bp_type>::type p;
|
||||
typename promote<bp_type>::type temp = 0;
|
||||
for (long n = 0; n < N; ++n)
|
||||
for (long n = 0; n < row_filter.size(); ++n)
|
||||
{
|
||||
// pull out the current pixel and put it into p
|
||||
p = get_pixel_intensity(in_img[r][c-N/2+n]);
|
||||
temp += p*row_filter[n];
|
||||
p = get_pixel_intensity(in_img[r][c-row_filter.size()/2+n]);
|
||||
temp += p*row_filter(n);
|
||||
}
|
||||
temp_img[r][c] = temp;
|
||||
}
|
||||
@ -184,9 +192,9 @@ namespace dlib
|
||||
for (long c = first_col; c < last_col; ++c)
|
||||
{
|
||||
typename promote<bp_type>::type temp = 0;
|
||||
for (long m = 0; m < M; ++m)
|
||||
for (long m = 0; m < col_filter.size(); ++m)
|
||||
{
|
||||
temp += temp_img[r-M/2+m][c]*col_filter[m];
|
||||
temp += temp_img[r-col_filter.size()/2+m][c]*col_filter(m);
|
||||
}
|
||||
|
||||
temp /= scale;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifdef DLIB_SPATIAL_FILTERINg_ABSTRACT_
|
||||
|
||||
#include "../pixel.h"
|
||||
#include "../matrix.h"
|
||||
|
||||
namespace dlib
|
||||
{
|
||||
@ -13,14 +14,12 @@ namespace dlib
|
||||
template <
|
||||
typename in_image_type,
|
||||
typename out_image_type,
|
||||
typename filter_type,
|
||||
long M,
|
||||
long N
|
||||
typename EXP
|
||||
>
|
||||
void spatially_filter_image (
|
||||
const in_image_type& in_img,
|
||||
out_image_type& out_img,
|
||||
const filter_type (&filter)[M][N],
|
||||
const matrix_exp<EXP>& filter,
|
||||
unsigned long scale = 1,
|
||||
bool use_abs = false
|
||||
);
|
||||
@ -32,8 +31,8 @@ namespace dlib
|
||||
- pixel_traits<typename out_image_type::type>::has_alpha == false
|
||||
- is_same_object(in_img, out_img) == false
|
||||
- scale > 0
|
||||
- M % 2 == 1 (i.e. M must be odd)
|
||||
- N % 2 == 1 (i.e. N must be odd)
|
||||
- filter.nr() % 2 == 1 (i.e. must be odd)
|
||||
- filter.nc() % 2 == 1 (i.e. must be odd)
|
||||
ensures
|
||||
- Applies the given spatial filter to in_img and stores the result in out_img. Also
|
||||
divides each resulting pixel by scale.
|
||||
@ -57,15 +56,14 @@ namespace dlib
|
||||
template <
|
||||
typename in_image_type,
|
||||
typename out_image_type,
|
||||
typename filter_type,
|
||||
long M,
|
||||
long N
|
||||
typename EXP1,
|
||||
typename EXP2
|
||||
>
|
||||
void spatially_filter_image (
|
||||
const in_image_type& in_img,
|
||||
out_image_type& out_img,
|
||||
const filter_type (&row_filter)[N],
|
||||
const filter_type (&col_filter)[M],
|
||||
const matrix_exp<EXP1>& row_filter,
|
||||
const matrix_exp<EXP2>& col_filter,
|
||||
unsigned long scale = 1,
|
||||
bool use_abs = false
|
||||
);
|
||||
@ -77,14 +75,16 @@ namespace dlib
|
||||
- pixel_traits<typename out_image_type::type>::has_alpha == false
|
||||
- is_same_object(in_img, out_img) == false
|
||||
- scale > 0
|
||||
- M % 2 == 1 (i.e. M must be odd)
|
||||
- N % 2 == 1 (i.e. N must be odd)
|
||||
- is_vector(row_filter) == true
|
||||
- is_vector(col_filter) == true
|
||||
- row_filter.size() % 2 == 1 (i.e. must be odd)
|
||||
- col_filter.size() % 2 == 1 (i.e. must be odd)
|
||||
ensures
|
||||
- Applies the given separable spatial filter to in_img and stores the result in out_img.
|
||||
Also divides each resulting pixel by scale. Calling this function has the same
|
||||
effect as calling the regular spatially_filter_image() routine with a filter,
|
||||
FILT, defined as follows:
|
||||
- FILT[r][c] == col_filter[r]*row_filter[c]
|
||||
- FILT(r,c) == col_filter(r)*row_filter(c)
|
||||
- pixel values after filtering that are > pixel_traits<out_image_type>::max() are
|
||||
set to pixel_traits<out_image_type>::max()
|
||||
- if (pixel_traits<typename in_image_type::type>::grayscale == false) then
|
||||
|
@ -772,25 +772,27 @@ namespace
|
||||
|
||||
assign_all_pixels(img, 10);
|
||||
|
||||
int filter[3][3] = { {1,1,1},
|
||||
{1,1,1},
|
||||
{1,1,1}};
|
||||
|
||||
matrix<int,3,5> filter2;
|
||||
filter2 = 1,1,1,1,1,
|
||||
1,1,1,1,1,
|
||||
1,1,1,1,1;
|
||||
|
||||
assign_all_pixels(img2,3);
|
||||
spatially_filter_image(img, img2, filter);
|
||||
spatially_filter_image(img, img2, filter2);
|
||||
|
||||
const rectangle rect(2,1,img.nc()-3,img.nr()-2);
|
||||
|
||||
for (long r = 0; r<img2.nr(); ++r)
|
||||
{
|
||||
for (long c = 0; c<img2.nc(); ++c)
|
||||
{
|
||||
if (shrink_rect(get_rect(img2),1).contains(c,r))
|
||||
if (rect.contains(c,r))
|
||||
{
|
||||
DLIB_TEST(img2[r][c] == 90);
|
||||
DLIB_TEST_MSG(img2[r][c] == 150, (int)img2[r][c]);
|
||||
}
|
||||
else
|
||||
{
|
||||
DLIB_TEST(img2[r][c] == 0);
|
||||
DLIB_TEST_MSG(img2[r][c] == 0,(int)img2[r][c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -798,10 +800,13 @@ namespace
|
||||
|
||||
assign_all_pixels(img2,3);
|
||||
assign_all_pixels(img3,3);
|
||||
spatially_filter_image(img, img2, filter);
|
||||
spatially_filter_image(img, img2, filter2);
|
||||
|
||||
int row_filter[] = {1,1,1};
|
||||
int col_filter[] = {1,1,1};
|
||||
matrix<int,1,5> row_filter;
|
||||
matrix<int,1,3> col_filter;
|
||||
|
||||
row_filter = 1,1,1,1,1;
|
||||
col_filter = 1,1,1;
|
||||
|
||||
spatially_filter_image(img, img3, row_filter, col_filter);
|
||||
|
||||
@ -820,20 +825,16 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
row_filter[0] = ((int)rnd.get_random_8bit_number() - 100)/10;
|
||||
row_filter[1] = ((int)rnd.get_random_8bit_number() - 100)/10;
|
||||
row_filter[2] = ((int)rnd.get_random_8bit_number() - 100)/10;
|
||||
col_filter[0] = ((int)rnd.get_random_8bit_number() - 100)/10;
|
||||
col_filter[1] = ((int)rnd.get_random_8bit_number() - 100)/10;
|
||||
col_filter[2] = ((int)rnd.get_random_8bit_number() - 100)/10;
|
||||
row_filter(0) = ((int)rnd.get_random_8bit_number() - 100)/10;
|
||||
row_filter(1) = ((int)rnd.get_random_8bit_number() - 100)/10;
|
||||
row_filter(2) = ((int)rnd.get_random_8bit_number() - 100)/10;
|
||||
row_filter(3) = ((int)rnd.get_random_8bit_number() - 100)/10;
|
||||
row_filter(4) = ((int)rnd.get_random_8bit_number() - 100)/10;
|
||||
col_filter(0) = ((int)rnd.get_random_8bit_number() - 100)/10;
|
||||
col_filter(1) = ((int)rnd.get_random_8bit_number() - 100)/10;
|
||||
col_filter(2) = ((int)rnd.get_random_8bit_number() - 100)/10;
|
||||
|
||||
for (long rr = 0; rr < 3; ++rr)
|
||||
{
|
||||
for (long cc = 0; cc < 3; ++cc)
|
||||
{
|
||||
filter[rr][cc] = row_filter[cc]*col_filter[rr];
|
||||
}
|
||||
}
|
||||
const matrix<int,3,5> filter = trans(col_filter)*row_filter;
|
||||
|
||||
assign_all_pixels(img2,3);
|
||||
assign_all_pixels(img3,3);
|
||||
@ -844,6 +845,40 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
void test_zero_border_pixels(
|
||||
)
|
||||
{
|
||||
array2d<unsigned char> img;
|
||||
img.set_size(4,5);
|
||||
|
||||
assign_all_pixels(img, 1);
|
||||
zero_border_pixels(img, 2,1);
|
||||
|
||||
DLIB_TEST(img[0][0] == 0);
|
||||
DLIB_TEST(img[1][0] == 0);
|
||||
DLIB_TEST(img[2][0] == 0);
|
||||
DLIB_TEST(img[3][0] == 0);
|
||||
DLIB_TEST(img[0][1] == 0);
|
||||
DLIB_TEST(img[1][1] == 0);
|
||||
DLIB_TEST(img[2][1] == 0);
|
||||
DLIB_TEST(img[3][1] == 0);
|
||||
|
||||
DLIB_TEST(img[0][3] == 0);
|
||||
DLIB_TEST(img[1][3] == 0);
|
||||
DLIB_TEST(img[2][3] == 0);
|
||||
DLIB_TEST(img[3][3] == 0);
|
||||
DLIB_TEST(img[0][4] == 0);
|
||||
DLIB_TEST(img[1][4] == 0);
|
||||
DLIB_TEST(img[2][4] == 0);
|
||||
DLIB_TEST(img[3][4] == 0);
|
||||
|
||||
DLIB_TEST(img[0][2] == 0);
|
||||
DLIB_TEST(img[3][2] == 0);
|
||||
|
||||
DLIB_TEST(img[1][2] == 1);
|
||||
DLIB_TEST(img[2][2] == 1);
|
||||
}
|
||||
|
||||
class image_tester : public tester
|
||||
{
|
||||
public:
|
||||
@ -862,6 +897,8 @@ namespace
|
||||
test_integral_image<long, unsigned char>();
|
||||
test_integral_image<double, float>();
|
||||
|
||||
test_zero_border_pixels();
|
||||
|
||||
test_filtering<unsigned char>(false,1);
|
||||
test_filtering<unsigned char>(true,1);
|
||||
test_filtering<unsigned char>(false,3);
|
||||
|
Loading…
Reference in New Issue
Block a user