mirror of
https://github.com/davisking/dlib.git
synced 2024-11-01 10:14:53 +08:00
Added an overload of spatially_filter_image() that uses a separable filter.
This commit is contained in:
parent
16ae5eaca7
commit
73a34f7fd4
@ -7,6 +7,7 @@
|
||||
#include "spatial_filtering_abstract.h"
|
||||
#include "../algs.h"
|
||||
#include "../assert.h"
|
||||
#include "../array2d.h"
|
||||
#include <limits>
|
||||
|
||||
namespace dlib
|
||||
@ -102,6 +103,114 @@ namespace dlib
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
typename in_image_type,
|
||||
typename out_image_type,
|
||||
typename filter_type,
|
||||
long M,
|
||||
long N
|
||||
>
|
||||
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],
|
||||
unsigned long scale = 1,
|
||||
bool use_abs = false
|
||||
)
|
||||
{
|
||||
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,
|
||||
"\tvoid spatially_filter_image()"
|
||||
<< "\n\tYou can't give a scale of zero"
|
||||
);
|
||||
DLIB_ASSERT(is_same_object(in_img, out_img) == false,
|
||||
"\tvoid spatially_filter_image()"
|
||||
<< "\n\tYou must give two different image objects"
|
||||
);
|
||||
|
||||
|
||||
|
||||
// if there isn't any input image then don't do anything
|
||||
if (in_img.size() == 0)
|
||||
{
|
||||
out_img.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
out_img.set_size(in_img.nr(),in_img.nc());
|
||||
|
||||
zero_border_pixels(out_img, M/2, N/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;
|
||||
|
||||
typedef typename pixel_traits<typename in_image_type::type>::basic_pixel_type bp_type;
|
||||
|
||||
typedef typename out_image_type::mem_manager_type mem_manager_type;
|
||||
|
||||
array2d<typename promote<bp_type>::type,mem_manager_type> temp_img;
|
||||
temp_img.set_size(in_img.nr(), in_img.nc());
|
||||
|
||||
// apply the row filter
|
||||
for (long r = 0; r < in_img.nr(); ++r)
|
||||
{
|
||||
for (long c = first_col; c < last_col; ++c)
|
||||
{
|
||||
typename promote<bp_type>::type p;
|
||||
typename promote<bp_type>::type temp = 0;
|
||||
for (long n = 0; n < N; ++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];
|
||||
}
|
||||
temp_img[r][c] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
// apply the column filter
|
||||
for (long r = first_row; r < last_row; ++r)
|
||||
{
|
||||
for (long c = first_col; c < last_col; ++c)
|
||||
{
|
||||
typename promote<bp_type>::type temp = 0;
|
||||
for (long m = 0; m < M; ++m)
|
||||
{
|
||||
temp += temp_img[r-M/2+m][c]*col_filter[m];
|
||||
}
|
||||
|
||||
temp /= scale;
|
||||
|
||||
// Catch any underflow or apply abs as appropriate
|
||||
if (temp < 0)
|
||||
{
|
||||
if (use_abs)
|
||||
{
|
||||
temp = -temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// save this pixel to the output image
|
||||
assign_pixel(out_img[r][c], in_img[r][c]);
|
||||
assign_pixel_intensity(out_img[r][c], temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
|
@ -47,8 +47,55 @@ namespace dlib
|
||||
- else
|
||||
- pixel values after filtering that are < 0 are assigned the value of 0
|
||||
- Pixels close enough to the edge of in_img to not have the filter still fit
|
||||
inside the image are not modified. i.e. Whatever value the border of out_img
|
||||
had to begin with is what it will have after this function returns.
|
||||
inside the image are set to zero.
|
||||
- #out_img.nc() == in_img.nc()
|
||||
- #out_img.nr() == in_img.nr()
|
||||
!*/
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
typename in_image_type,
|
||||
typename out_image_type,
|
||||
typename filter_type,
|
||||
long M,
|
||||
long N
|
||||
>
|
||||
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],
|
||||
unsigned long scale = 1,
|
||||
bool use_abs = false
|
||||
);
|
||||
/*!
|
||||
requires
|
||||
- in_image_type == is an implementation of array2d/array2d_kernel_abstract.h
|
||||
- out_image_type == is an implementation of array2d/array2d_kernel_abstract.h
|
||||
- pixel_traits<typename in_image_type::type>::has_alpha == false
|
||||
- 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)
|
||||
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]
|
||||
- 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
|
||||
- the pixel values are converted to the HSI color space and the filtering
|
||||
is done on the intensity channel only.
|
||||
- if (use_abs == true) then
|
||||
- pixel values after filtering that are < 0 are converted to their absolute values
|
||||
- else
|
||||
- pixel values after filtering that are < 0 are assigned the value of 0
|
||||
- Pixels close enough to the edge of in_img to not have the filter still fit
|
||||
inside the image are set to zero.
|
||||
- #out_img.nc() == in_img.nc()
|
||||
- #out_img.nr() == in_img.nr()
|
||||
!*/
|
||||
|
@ -762,6 +762,87 @@ namespace
|
||||
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void test_filtering(bool use_abs, unsigned long scale )
|
||||
{
|
||||
print_spinner();
|
||||
dlog << LINFO << "test_filtering(" << use_abs << "," << scale << ")";
|
||||
array2d<T> img, img2, img3;
|
||||
img.set_size(10,11);
|
||||
|
||||
assign_all_pixels(img, 10);
|
||||
|
||||
int filter[3][3] = { 1,1,1,
|
||||
1,1,1,
|
||||
1,1,1};
|
||||
|
||||
|
||||
assign_all_pixels(img2,3);
|
||||
spatially_filter_image(img, img2, filter);
|
||||
|
||||
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))
|
||||
{
|
||||
DLIB_TEST(img2[r][c] == 90);
|
||||
}
|
||||
else
|
||||
{
|
||||
DLIB_TEST(img2[r][c] == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
assign_all_pixels(img2,3);
|
||||
assign_all_pixels(img3,3);
|
||||
spatially_filter_image(img, img2, filter);
|
||||
|
||||
int row_filter[] = {1,1,1};
|
||||
int col_filter[] = {1,1,1};
|
||||
|
||||
spatially_filter_image(img, img3, row_filter, col_filter);
|
||||
|
||||
DLIB_TEST(array_to_matrix(img2) == array_to_matrix(img3));
|
||||
|
||||
|
||||
dlib::rand rnd;
|
||||
|
||||
for (int i = 0; i < 30; ++i)
|
||||
{
|
||||
for (long r = 0; r < img.nr(); ++r)
|
||||
{
|
||||
for (long c = 0; c < img.nc(); ++c)
|
||||
{
|
||||
img[r][c] = rnd.get_random_8bit_number();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
for (long rr = 0; rr < 3; ++rr)
|
||||
{
|
||||
for (long cc = 0; cc < 3; ++cc)
|
||||
{
|
||||
filter[rr][cc] = row_filter[cc]*col_filter[rr];
|
||||
}
|
||||
}
|
||||
|
||||
assign_all_pixels(img2,3);
|
||||
assign_all_pixels(img3,3);
|
||||
// Just make sure both filtering methods give the same results.
|
||||
spatially_filter_image(img, img2, filter, scale, use_abs);
|
||||
spatially_filter_image(img, img3, row_filter, col_filter, scale, use_abs);
|
||||
DLIB_TEST(array_to_matrix(img2) == array_to_matrix(img3));
|
||||
}
|
||||
}
|
||||
|
||||
class image_tester : public tester
|
||||
{
|
||||
@ -780,6 +861,15 @@ namespace
|
||||
test_integral_image<double, int>();
|
||||
test_integral_image<long, unsigned char>();
|
||||
test_integral_image<double, float>();
|
||||
|
||||
test_filtering<unsigned char>(false,1);
|
||||
test_filtering<unsigned char>(true,1);
|
||||
test_filtering<unsigned char>(false,3);
|
||||
test_filtering<unsigned char>(true,3);
|
||||
test_filtering<int>(false,1);
|
||||
test_filtering<int>(true,1);
|
||||
test_filtering<int>(false,3);
|
||||
test_filtering<int>(true,3);
|
||||
}
|
||||
} a;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user