diff options
Diffstat (limited to 'ml/dlib/dlib/image_transforms/spatial_filtering.h')
-rw-r--r-- | ml/dlib/dlib/image_transforms/spatial_filtering.h | 1580 |
1 files changed, 0 insertions, 1580 deletions
diff --git a/ml/dlib/dlib/image_transforms/spatial_filtering.h b/ml/dlib/dlib/image_transforms/spatial_filtering.h deleted file mode 100644 index 91dcae321..000000000 --- a/ml/dlib/dlib/image_transforms/spatial_filtering.h +++ /dev/null @@ -1,1580 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_SPATIAL_FILTERINg_H_ -#define DLIB_SPATIAL_FILTERINg_H_ - -#include "../pixel.h" -#include "spatial_filtering_abstract.h" -#include "../algs.h" -#include "../assert.h" -#include "../array2d.h" -#include "../matrix.h" -#include "../geometry/border_enumerator.h" -#include "../simd.h" -#include <limits> -#include "assign_image.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - namespace impl - { - template < - typename in_image_type, - typename out_image_type, - typename EXP, - typename T - > - rectangle grayscale_spatially_filter_image ( - const in_image_type& in_img_, - out_image_type& out_img_, - const matrix_exp<EXP>& filter_, - T scale, - bool use_abs, - bool add_to - ) - { - const_temp_matrix<EXP> filter(filter_); - COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false ); - COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false ); - - DLIB_ASSERT(scale != 0 && filter.size() != 0, - "\trectangle spatially_filter_image()" - << "\n\t You can't give a scale of zero or an empty filter." - << "\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, - "\trectangle spatially_filter_image()" - << "\n\tYou must give two different image objects" - ); - - - const_image_view<in_image_type> in_img(in_img_); - image_view<out_image_type> out_img(out_img_); - - // if there isn't any input image then don't do anything - if (in_img.size() == 0) - { - out_img.clear(); - return rectangle(); - } - - out_img.set_size(in_img.nr(),in_img.nc()); - - - // figure out the range that we should apply the filter to - const long first_row = filter.nr()/2; - const long first_col = filter.nc()/2; - const long last_row = in_img.nr() - ((filter.nr()-1)/2); - const long last_col = in_img.nc() - ((filter.nc()-1)/2); - - const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1); - if (!add_to) - zero_border_pixels(out_img_, non_border); - - // apply the filter to the image - for (long r = first_row; r < last_row; ++r) - { - for (long c = first_col; c < last_col; ++c) - { - typedef typename EXP::type ptype; - ptype p; - ptype temp = 0; - for (long m = 0; m < filter.nr(); ++m) - { - 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-first_row+m][c-first_col+n]); - temp += p*filter(m,n); - } - } - - temp /= scale; - - if (use_abs && temp < 0) - { - temp = -temp; - } - - // save this pixel to the output image - if (add_to == false) - { - assign_pixel(out_img[r][c], temp); - } - else - { - assign_pixel(out_img[r][c], temp + out_img[r][c]); - } - } - } - - return non_border; - } - - // ------------------------------------------------------------------------------------ - - template < - typename in_image_type, - typename out_image_type, - typename EXP - > - rectangle float_spatially_filter_image ( - const in_image_type& in_img_, - out_image_type& out_img_, - const matrix_exp<EXP>& filter_, - bool add_to - ) - { - - const_temp_matrix<EXP> filter(filter_); - DLIB_ASSERT(filter.size() != 0, - "\trectangle spatially_filter_image()" - << "\n\t You can't give an empty filter." - << "\n\t filter.nr(): "<< filter.nr() - << "\n\t filter.nc(): "<< filter.nc() - ); - DLIB_ASSERT(is_same_object(in_img_, out_img_) == false, - "\trectangle spatially_filter_image()" - << "\n\tYou must give two different image objects" - ); - - - const_image_view<in_image_type> in_img(in_img_); - image_view<out_image_type> out_img(out_img_); - - // if there isn't any input image then don't do anything - if (in_img.size() == 0) - { - out_img.clear(); - return rectangle(); - } - - out_img.set_size(in_img.nr(),in_img.nc()); - - - // figure out the range that we should apply the filter to - const long first_row = filter.nr()/2; - const long first_col = filter.nc()/2; - const long last_row = in_img.nr() - ((filter.nr()-1)/2); - const long last_col = in_img.nc() - ((filter.nc()-1)/2); - - const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1); - if (!add_to) - zero_border_pixels(out_img_, non_border); - - // apply the filter to the image - for (long r = first_row; r < last_row; ++r) - { - long c = first_col; - for (; c < last_col-7; c+=8) - { - simd8f p,p2,p3; - simd8f temp = 0, temp2=0, temp3=0; - for (long m = 0; m < filter.nr(); ++m) - { - long n = 0; - for (; n < filter.nc()-2; n+=3) - { - // pull out the current pixel and put it into p - p.load(&in_img[r-first_row+m][c-first_col+n]); - p2.load(&in_img[r-first_row+m][c-first_col+n+1]); - p3.load(&in_img[r-first_row+m][c-first_col+n+2]); - temp += p*filter(m,n); - temp2 += p2*filter(m,n+1); - temp3 += p3*filter(m,n+2); - } - for (; n < filter.nc(); ++n) - { - // pull out the current pixel and put it into p - p.load(&in_img[r-first_row+m][c-first_col+n]); - temp += p*filter(m,n); - } - } - temp += temp2+temp3; - - // save this pixel to the output image - if (add_to == false) - { - temp.store(&out_img[r][c]); - } - else - { - p.load(&out_img[r][c]); - temp += p; - temp.store(&out_img[r][c]); - } - } - for (; c < last_col; ++c) - { - float p; - float temp = 0; - for (long m = 0; m < filter.nr(); ++m) - { - for (long n = 0; n < filter.nc(); ++n) - { - // pull out the current pixel and put it into p - p = in_img[r-first_row+m][c-first_col+n]; - temp += p*filter(m,n); - } - } - - // save this pixel to the output image - if (add_to == false) - { - out_img[r][c] = temp; - } - else - { - out_img[r][c] += temp; - } - } - } - - return non_border; - } - } - -// ---------------------------------------------------------------------------------------- - - template < - typename in_image_type, - typename out_image_type, - typename EXP - > - struct is_float_filtering2 - { - const static bool value = is_same_type<typename image_traits<in_image_type>::pixel_type,float>::value && - is_same_type<typename image_traits<out_image_type>::pixel_type,float>::value && - is_same_type<typename EXP::type,float>::value; - }; - -// ---------------------------------------------------------------------------------------- - - template < - typename in_image_type, - typename out_image_type, - typename EXP, - typename T - > - typename enable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale && - is_float_filtering2<in_image_type,out_image_type,EXP>::value,rectangle>::type - spatially_filter_image ( - const in_image_type& in_img, - out_image_type& out_img, - const matrix_exp<EXP>& filter, - T scale, - bool use_abs = false, - bool add_to = false - ) - { - if (use_abs == false) - { - if (scale == 1) - return impl::float_spatially_filter_image(in_img, out_img, filter, add_to); - else - return impl::float_spatially_filter_image(in_img, out_img, filter/scale, add_to); - } - else - { - return impl::grayscale_spatially_filter_image(in_img, out_img, filter, scale, true, add_to); - } - } - -// ---------------------------------------------------------------------------------------- - - template < - typename in_image_type, - typename out_image_type, - typename EXP, - typename T - > - typename enable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale && - !is_float_filtering2<in_image_type,out_image_type,EXP>::value,rectangle>::type - spatially_filter_image ( - const in_image_type& in_img, - out_image_type& out_img, - const matrix_exp<EXP>& filter, - T scale, - bool use_abs = false, - bool add_to = false - ) - { - return impl::grayscale_spatially_filter_image(in_img,out_img,filter,scale,use_abs,add_to); - } - -// ---------------------------------------------------------------------------------------- - - template < - typename in_image_type, - typename out_image_type, - typename EXP, - typename T - > - typename disable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale,rectangle>::type - spatially_filter_image ( - const in_image_type& in_img_, - out_image_type& out_img_, - const matrix_exp<EXP>& filter_, - T scale - ) - { - const_temp_matrix<EXP> filter(filter_); - COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false ); - COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false ); - - DLIB_ASSERT(scale != 0 && filter.size() != 0, - "\trectangle spatially_filter_image()" - << "\n\t You can't give a scale of zero or an empty filter." - << "\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, - "\trectangle spatially_filter_image()" - << "\n\tYou must give two different image objects" - ); - - - const_image_view<in_image_type> in_img(in_img_); - image_view<out_image_type> out_img(out_img_); - - // if there isn't any input image then don't do anything - if (in_img.size() == 0) - { - out_img.clear(); - return rectangle(); - } - - out_img.set_size(in_img.nr(),in_img.nc()); - - - // figure out the range that we should apply the filter to - const long first_row = filter.nr()/2; - const long first_col = filter.nc()/2; - const long last_row = in_img.nr() - ((filter.nr()-1)/2); - const long last_col = in_img.nc() - ((filter.nc()-1)/2); - - const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1); - zero_border_pixels(out_img, non_border); - - // apply the filter to the image - for (long r = first_row; r < last_row; ++r) - { - for (long c = first_col; c < last_col; ++c) - { - typedef typename image_traits<in_image_type>::pixel_type pixel_type; - typedef matrix<typename EXP::type,pixel_traits<pixel_type>::num,1> ptype; - ptype p; - ptype temp; - temp = 0; - for (long m = 0; m < filter.nr(); ++m) - { - for (long n = 0; n < filter.nc(); ++n) - { - // pull out the current pixel and put it into p - p = pixel_to_vector<typename EXP::type>(in_img[r-first_row+m][c-first_col+n]); - temp += p*filter(m,n); - } - } - - temp /= scale; - - pixel_type pp; - vector_to_pixel(pp, temp); - assign_pixel(out_img[r][c], pp); - } - } - - return non_border; - } - -// ---------------------------------------------------------------------------------------- - - template < - typename in_image_type, - typename out_image_type, - typename EXP - > - rectangle spatially_filter_image ( - const in_image_type& in_img, - out_image_type& out_img, - const matrix_exp<EXP>& filter - ) - { - return spatially_filter_image(in_img,out_img,filter,1); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - namespace impl - { - template < - typename in_image_type, - typename out_image_type, - typename EXP1, - typename EXP2, - typename T - > - rectangle grayscale_spatially_filter_image_separable ( - const in_image_type& in_img_, - out_image_type& out_img_, - const matrix_exp<EXP1>& _row_filter, - const matrix_exp<EXP2>& _col_filter, - T scale, - bool use_abs, - bool add_to - ) - { - const_temp_matrix<EXP1> row_filter(_row_filter); - const_temp_matrix<EXP2> col_filter(_col_filter); - COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false ); - COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false ); - - DLIB_ASSERT(scale != 0 && row_filter.size() != 0 && col_filter.size() != 0 && - is_vector(row_filter) && - is_vector(col_filter), - "\trectangle spatially_filter_image_separable()" - << "\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, - "\trectangle spatially_filter_image_separable()" - << "\n\tYou must give two different image objects" - ); - - - const_image_view<in_image_type> in_img(in_img_); - image_view<out_image_type> out_img(out_img_); - - // if there isn't any input image then don't do anything - if (in_img.size() == 0) - { - out_img.clear(); - return rectangle(); - } - - out_img.set_size(in_img.nr(),in_img.nc()); - - - // figure out the range that we should apply the filter to - 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()-1)/2); - const long last_col = in_img.nc() - ((row_filter.size()-1)/2); - - const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1); - if (!add_to) - zero_border_pixels(out_img, non_border); - - typedef typename EXP1::type ptype; - - array2d<ptype> 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) - { - ptype p; - ptype temp = 0; - 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-first_col+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) - { - ptype temp = 0; - for (long m = 0; m < col_filter.size(); ++m) - { - temp += temp_img[r-first_row+m][c]*col_filter(m); - } - - temp /= scale; - - if (use_abs && temp < 0) - { - temp = -temp; - } - - // save this pixel to the output image - if (add_to == false) - { - assign_pixel(out_img[r][c], temp); - } - else - { - assign_pixel(out_img[r][c], temp + out_img[r][c]); - } - } - } - return non_border; - } - - } // namespace impl - -// ---------------------------------------------------------------------------------------- - - template < - typename in_image_type, - typename out_image_type, - typename EXP1, - typename EXP2 - > - struct is_float_filtering - { - const static bool value = is_same_type<typename image_traits<in_image_type>::pixel_type,float>::value && - is_same_type<typename image_traits<out_image_type>::pixel_type,float>::value && - is_same_type<typename EXP1::type,float>::value && - is_same_type<typename EXP2::type,float>::value; - }; - -// ---------------------------------------------------------------------------------------- - - // This overload is optimized to use SIMD instructions when filtering float images with - // float filters. - template < - typename in_image_type, - typename out_image_type, - typename EXP1, - typename EXP2 - > - rectangle float_spatially_filter_image_separable ( - const in_image_type& in_img_, - out_image_type& out_img_, - const matrix_exp<EXP1>& _row_filter, - const matrix_exp<EXP2>& _col_filter, - out_image_type& scratch_, - bool add_to = false - ) - { - // You can only use this function with images and filters containing float - // variables. - COMPILE_TIME_ASSERT((is_float_filtering<in_image_type,out_image_type,EXP1,EXP2>::value == true)); - - - const_temp_matrix<EXP1> row_filter(_row_filter); - const_temp_matrix<EXP2> col_filter(_col_filter); - DLIB_ASSERT(row_filter.size() != 0 && col_filter.size() != 0 && - is_vector(row_filter) && - is_vector(col_filter), - "\trectangle float_spatially_filter_image_separable()" - << "\n\t Invalid inputs were given to this function." - << "\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, - "\trectangle float_spatially_filter_image_separable()" - << "\n\tYou must give two different image objects" - ); - - - const_image_view<in_image_type> in_img(in_img_); - image_view<out_image_type> out_img(out_img_); - - // if there isn't any input image then don't do anything - if (in_img.size() == 0) - { - out_img.clear(); - return rectangle(); - } - - out_img.set_size(in_img.nr(),in_img.nc()); - - // figure out the range that we should apply the filter to - 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()-1)/2); - const long last_col = in_img.nc() - ((row_filter.size()-1)/2); - - const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1); - if (!add_to) - zero_border_pixels(out_img, non_border); - - image_view<out_image_type> scratch(scratch_); - scratch.set_size(in_img.nr(), in_img.nc()); - - // apply the row filter - for (long r = 0; r < in_img.nr(); ++r) - { - long c = first_col; - for (; c < last_col-7; c+=8) - { - simd8f p,p2,p3, temp = 0, temp2=0, temp3=0; - long n = 0; - for (; n < row_filter.size()-2; n+=3) - { - // pull out the current pixel and put it into p - p.load(&in_img[r][c-first_col+n]); - p2.load(&in_img[r][c-first_col+n+1]); - p3.load(&in_img[r][c-first_col+n+2]); - temp += p*row_filter(n); - temp2 += p2*row_filter(n+1); - temp3 += p3*row_filter(n+2); - } - for (; n < row_filter.size(); ++n) - { - // pull out the current pixel and put it into p - p.load(&in_img[r][c-first_col+n]); - temp += p*row_filter(n); - } - temp += temp2 + temp3; - temp.store(&scratch[r][c]); - } - for (; c < last_col; ++c) - { - float p; - float temp = 0; - for (long n = 0; n < row_filter.size(); ++n) - { - // pull out the current pixel and put it into p - p = in_img[r][c-first_col+n]; - temp += p*row_filter(n); - } - scratch[r][c] = temp; - } - } - - // apply the column filter - for (long r = first_row; r < last_row; ++r) - { - long c = first_col; - for (; c < last_col-7; c+=8) - { - simd8f p, p2, p3, temp = 0, temp2 = 0, temp3 = 0; - long m = 0; - for (; m < col_filter.size()-2; m+=3) - { - p.load(&scratch[r-first_row+m][c]); - p2.load(&scratch[r-first_row+m+1][c]); - p3.load(&scratch[r-first_row+m+2][c]); - temp += p*col_filter(m); - temp2 += p2*col_filter(m+1); - temp3 += p3*col_filter(m+2); - } - for (; m < col_filter.size(); ++m) - { - p.load(&scratch[r-first_row+m][c]); - temp += p*col_filter(m); - } - temp += temp2+temp3; - - // save this pixel to the output image - if (add_to == false) - { - temp.store(&out_img[r][c]); - } - else - { - p.load(&out_img[r][c]); - temp += p; - temp.store(&out_img[r][c]); - } - } - for (; c < last_col; ++c) - { - float temp = 0; - for (long m = 0; m < col_filter.size(); ++m) - { - temp += scratch[r-first_row+m][c]*col_filter(m); - } - - // save this pixel to the output image - if (add_to == false) - { - out_img[r][c] = temp; - } - else - { - out_img[r][c] += temp; - } - } - } - return non_border; - } - -// ---------------------------------------------------------------------------------------- - - template < - typename in_image_type, - typename out_image_type, - typename EXP1, - typename EXP2, - typename T - > - typename enable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale && - is_float_filtering<in_image_type,out_image_type,EXP1,EXP2>::value,rectangle>::type - spatially_filter_image_separable ( - const in_image_type& in_img, - out_image_type& out_img, - const matrix_exp<EXP1>& row_filter, - const matrix_exp<EXP2>& col_filter, - T scale, - bool use_abs = false, - bool add_to = false - ) - { - if (use_abs == false) - { - out_image_type scratch; - if (scale == 1) - return float_spatially_filter_image_separable(in_img, out_img, row_filter, col_filter, scratch, add_to); - else - return float_spatially_filter_image_separable(in_img, out_img, row_filter/scale, col_filter, scratch, add_to); - } - else - { - return impl::grayscale_spatially_filter_image_separable(in_img, out_img, row_filter, col_filter, scale, true, add_to); - } - } - -// ---------------------------------------------------------------------------------------- - - template < - typename in_image_type, - typename out_image_type, - typename EXP1, - typename EXP2, - typename T - > - typename enable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale && - !is_float_filtering<in_image_type,out_image_type,EXP1,EXP2>::value,rectangle>::type - spatially_filter_image_separable ( - const in_image_type& in_img, - out_image_type& out_img, - const matrix_exp<EXP1>& row_filter, - const matrix_exp<EXP2>& col_filter, - T scale, - bool use_abs = false, - bool add_to = false - ) - { - return impl::grayscale_spatially_filter_image_separable(in_img,out_img, row_filter, col_filter, scale, use_abs, add_to); - } - -// ---------------------------------------------------------------------------------------- - - template < - typename in_image_type, - typename out_image_type, - typename EXP1, - typename EXP2, - typename T - > - typename disable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale,rectangle>::type - spatially_filter_image_separable ( - const in_image_type& in_img_, - out_image_type& out_img_, - const matrix_exp<EXP1>& _row_filter, - const matrix_exp<EXP2>& _col_filter, - T scale - ) - { - const_temp_matrix<EXP1> row_filter(_row_filter); - const_temp_matrix<EXP2> col_filter(_col_filter); - COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false ); - COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false ); - - DLIB_ASSERT(scale != 0 && row_filter.size() != 0 && col_filter.size() != 0 && - is_vector(row_filter) && - is_vector(col_filter), - "\trectangle spatially_filter_image_separable()" - << "\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, - "\trectangle spatially_filter_image_separable()" - << "\n\tYou must give two different image objects" - ); - - - const_image_view<in_image_type> in_img(in_img_); - image_view<out_image_type> out_img(out_img_); - - // if there isn't any input image then don't do anything - if (in_img.size() == 0) - { - out_img.clear(); - return rectangle(); - } - - out_img.set_size(in_img.nr(),in_img.nc()); - - - // figure out the range that we should apply the filter to - 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()-1)/2); - const long last_col = in_img.nc() - ((row_filter.size()-1)/2); - - const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1); - zero_border_pixels(out_img, non_border); - - typedef typename image_traits<in_image_type>::pixel_type pixel_type; - typedef matrix<typename EXP1::type,pixel_traits<pixel_type>::num,1> ptype; - - array2d<ptype> 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) - { - ptype p; - ptype temp; - temp = 0; - for (long n = 0; n < row_filter.size(); ++n) - { - // pull out the current pixel and put it into p - p = pixel_to_vector<typename EXP1::type>(in_img[r][c-first_col+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) - { - ptype temp; - temp = 0; - for (long m = 0; m < col_filter.size(); ++m) - { - temp += temp_img[r-first_row+m][c]*col_filter(m); - } - - temp /= scale; - - - // save this pixel to the output image - pixel_type p; - vector_to_pixel(p, temp); - assign_pixel(out_img[r][c], p); - } - } - return non_border; - } - -// ---------------------------------------------------------------------------------------- - - template < - typename in_image_type, - typename out_image_type, - typename EXP1, - typename EXP2 - > - rectangle spatially_filter_image_separable ( - const in_image_type& in_img, - out_image_type& out_img, - const matrix_exp<EXP1>& row_filter, - const matrix_exp<EXP2>& col_filter - ) - { - return spatially_filter_image_separable(in_img,out_img,row_filter,col_filter,1); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - template < - typename in_image_type, - typename out_image_type, - typename EXP1, - typename EXP2, - typename T - > - rectangle spatially_filter_image_separable_down ( - const unsigned long downsample, - const in_image_type& in_img_, - out_image_type& out_img_, - const matrix_exp<EXP1>& row_filter, - const matrix_exp<EXP2>& col_filter, - T scale, - bool use_abs = false, - bool add_to = false - ) - { - COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false ); - COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false ); - COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale == true ); - - DLIB_ASSERT(downsample > 0 && - scale != 0 && - row_filter.size()%2 == 1 && - col_filter.size()%2 == 1 && - is_vector(row_filter) && - is_vector(col_filter), - "\trectangle spatially_filter_image_separable_down()" - << "\n\t Invalid inputs were given to this function." - << "\n\t downsample: "<< downsample - << "\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, - "\trectangle spatially_filter_image_separable_down()" - << "\n\tYou must give two different image objects" - ); - - - const_image_view<in_image_type> in_img(in_img_); - image_view<out_image_type> out_img(out_img_); - - // if there isn't any input image then don't do anything - if (in_img.size() == 0) - { - out_img.clear(); - return rectangle(); - } - - out_img.set_size((long)(std::ceil((double)in_img.nr()/downsample)), - (long)(std::ceil((double)in_img.nc()/downsample))); - - const double col_border = std::floor(col_filter.size()/2.0); - const double row_border = std::floor(row_filter.size()/2.0); - - // figure out the range that we should apply the filter to - const long first_row = (long)std::ceil(col_border/downsample); - const long first_col = (long)std::ceil(row_border/downsample); - const long last_row = (long)std::ceil((in_img.nr() - col_border)/downsample) - 1; - const long last_col = (long)std::ceil((in_img.nc() - row_border)/downsample) - 1; - - // zero border pixels - const rectangle non_border = rectangle(first_col, first_row, last_col, last_row); - zero_border_pixels(out_img,non_border); - - typedef typename EXP1::type ptype; - - array2d<ptype> temp_img; - temp_img.set_size(in_img.nr(), out_img.nc()); - - // apply the row filter - for (long r = 0; r < temp_img.nr(); ++r) - { - for (long c = non_border.left(); c <= non_border.right(); ++c) - { - ptype p; - ptype temp = 0; - 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*downsample-row_filter.size()/2+n]); - temp += p*row_filter(n); - } - temp_img[r][c] = temp; - } - } - - // apply the column filter - for (long r = non_border.top(); r <= non_border.bottom(); ++r) - { - for (long c = non_border.left(); c <= non_border.right(); ++c) - { - ptype temp = 0; - for (long m = 0; m < col_filter.size(); ++m) - { - temp += temp_img[r*downsample-col_filter.size()/2+m][c]*col_filter(m); - } - - temp /= scale; - - if (use_abs && temp < 0) - { - temp = -temp; - } - - // save this pixel to the output image - if (add_to == false) - { - assign_pixel(out_img[r][c], temp); - } - else - { - assign_pixel(out_img[r][c], temp + out_img[r][c]); - } - } - } - - return non_border; - } - - template < - typename in_image_type, - typename out_image_type, - typename EXP1, - typename EXP2 - > - rectangle spatially_filter_image_separable_down ( - const unsigned long downsample, - const in_image_type& in_img, - out_image_type& out_img, - const matrix_exp<EXP1>& row_filter, - const matrix_exp<EXP2>& col_filter - ) - { - return spatially_filter_image_separable_down(downsample,in_img,out_img,row_filter,col_filter,1); - } - -// ---------------------------------------------------------------------------------------- - - template < - long NR, - long NC, - typename T, - typename U, - typename in_image_type - > - inline void separable_3x3_filter_block_grayscale ( - T (&block)[NR][NC], - const in_image_type& img_, - const long& r, - const long& c, - const U& fe1, // separable filter end - const U& fm, // separable filter middle - const U& fe2 // separable filter end 2 - ) - { - const_image_view<in_image_type> img(img_); - // make sure requires clause is not broken - DLIB_ASSERT(shrink_rect(get_rect(img),1).contains(c,r) && - shrink_rect(get_rect(img),1).contains(c+NC-1,r+NR-1), - "\t void separable_3x3_filter_block_grayscale()" - << "\n\t The sub-window doesn't fit inside the given image." - << "\n\t get_rect(img): " << get_rect(img) - << "\n\t (c,r): " << point(c,r) - << "\n\t (c+NC-1,r+NR-1): " << point(c+NC-1,r+NR-1) - ); - - - T row_filt[NR+2][NC]; - for (long rr = 0; rr < NR+2; ++rr) - { - for (long cc = 0; cc < NC; ++cc) - { - row_filt[rr][cc] = get_pixel_intensity(img[r+rr-1][c+cc-1])*fe1 + - get_pixel_intensity(img[r+rr-1][c+cc])*fm + - get_pixel_intensity(img[r+rr-1][c+cc+1])*fe2; - } - } - - for (long rr = 0; rr < NR; ++rr) - { - for (long cc = 0; cc < NC; ++cc) - { - block[rr][cc] = (row_filt[rr][cc]*fe1 + - row_filt[rr+1][cc]*fm + - row_filt[rr+2][cc]*fe2); - } - } - - } - -// ---------------------------------------------------------------------------------------- - - template < - long NR, - long NC, - typename T, - typename U, - typename in_image_type - > - inline void separable_3x3_filter_block_rgb ( - T (&block)[NR][NC], - const in_image_type& img_, - const long& r, - const long& c, - const U& fe1, // separable filter end - const U& fm, // separable filter middle - const U& fe2 // separable filter end 2 - ) - { - const_image_view<in_image_type> img(img_); - // make sure requires clause is not broken - DLIB_ASSERT(shrink_rect(get_rect(img),1).contains(c,r) && - shrink_rect(get_rect(img),1).contains(c+NC-1,r+NR-1), - "\t void separable_3x3_filter_block_rgb()" - << "\n\t The sub-window doesn't fit inside the given image." - << "\n\t get_rect(img): " << get_rect(img) - << "\n\t (c,r): " << point(c,r) - << "\n\t (c+NC-1,r+NR-1): " << point(c+NC-1,r+NR-1) - ); - - T row_filt[NR+2][NC]; - for (long rr = 0; rr < NR+2; ++rr) - { - for (long cc = 0; cc < NC; ++cc) - { - row_filt[rr][cc].red = img[r+rr-1][c+cc-1].red*fe1 + img[r+rr-1][c+cc].red*fm + img[r+rr-1][c+cc+1].red*fe2; - row_filt[rr][cc].green = img[r+rr-1][c+cc-1].green*fe1 + img[r+rr-1][c+cc].green*fm + img[r+rr-1][c+cc+1].green*fe2; - row_filt[rr][cc].blue = img[r+rr-1][c+cc-1].blue*fe1 + img[r+rr-1][c+cc].blue*fm + img[r+rr-1][c+cc+1].blue*fe2; - } - } - - for (long rr = 0; rr < NR; ++rr) - { - for (long cc = 0; cc < NC; ++cc) - { - block[rr][cc].red = row_filt[rr][cc].red*fe1 + row_filt[rr+1][cc].red*fm + row_filt[rr+2][cc].red*fe2; - block[rr][cc].green = row_filt[rr][cc].green*fe1 + row_filt[rr+1][cc].green*fm + row_filt[rr+2][cc].green*fe2; - block[rr][cc].blue = row_filt[rr][cc].blue*fe1 + row_filt[rr+1][cc].blue*fm + row_filt[rr+2][cc].blue*fe2; - } - } - - } - -// ---------------------------------------------------------------------------------------- - - inline double gaussian ( - double x, - double sigma - ) - { - DLIB_ASSERT(sigma > 0, - "\tdouble gaussian(x)" - << "\n\t sigma must be bigger than 0" - << "\n\t sigma: " << sigma - ); - const double sqrt_2_pi = 2.5066282746310002416123552393401041626930; - return 1.0/(sigma*sqrt_2_pi) * std::exp( -(x*x)/(2*sigma*sigma)); - } - -// ---------------------------------------------------------------------------------------- - - template < - typename T - > - matrix<T,0,1> create_gaussian_filter ( - double sigma, - int max_size - ) - { - DLIB_ASSERT(sigma > 0 && max_size > 0 && (max_size%2)==1, - "\t matrix<T,0,1> create_gaussian_filter()" - << "\n\t Invalid inputs were given to this function." - << "\n\t sigma: " << sigma - << "\n\t max_size: " << max_size - ); - - // Adjust the size so that the ratio of the gaussian values isn't huge. - // This only matters when T is an integer type. However, we do it for - // all types so that the behavior of this function is always relatively - // the same. - while (gaussian(0,sigma)/gaussian(max_size/2,sigma) > 50) - --max_size; - - - matrix<double,0,1> f(max_size); - for (long i = 0; i < f.size(); ++i) - { - f(i) = gaussian(i-max_size/2, sigma); - } - - if (is_float_type<T>::value == false) - { - f /= f(0); - return matrix_cast<T>(round(f)); - } - else - { - return matrix_cast<T>(f); - } - } - -// ---------------------------------------------------------------------------------------- - - template < - typename in_image_type, - typename out_image_type - > - rectangle gaussian_blur ( - const in_image_type& in_img, - out_image_type& out_img, - double sigma = 1, - int max_size = 1001 - ) - { - DLIB_ASSERT(sigma > 0 && max_size > 0 && (max_size%2)==1 && - is_same_object(in_img, out_img) == false, - "\t void gaussian_blur()" - << "\n\t Invalid inputs were given to this function." - << "\n\t sigma: " << sigma - << "\n\t max_size: " << max_size - << "\n\t is_same_object(in_img,out_img): " << is_same_object(in_img,out_img) - ); - - if (sigma < 18) - { - typedef typename pixel_traits<typename image_traits<out_image_type>::pixel_type>::basic_pixel_type type; - typedef typename promote<type>::type ptype; - const matrix<ptype,0,1>& filt = create_gaussian_filter<ptype>(sigma, max_size); - ptype scale = sum(filt); - scale = scale*scale; - return spatially_filter_image_separable(in_img, out_img, filt, filt, scale); - } - else - { - // For large sigma we need to use a type with a lot of precision to avoid - // numerical problems. So we use double here. - typedef double ptype; - const matrix<ptype,0,1>& filt = create_gaussian_filter<ptype>(sigma, max_size); - ptype scale = sum(filt); - scale = scale*scale; - return spatially_filter_image_separable(in_img, out_img, filt, filt, scale); - } - - } - -// ---------------------------------------------------------------------------------------- - - namespace impl - { - template < - bool add_to, - typename image_type1, - typename image_type2 - > - void sum_filter ( - const image_type1& img_, - image_type2& out_, - const rectangle& rect - ) - { - const_image_view<image_type1> img(img_); - image_view<image_type2> out(out_); - DLIB_ASSERT(img.nr() == out.nr() && - img.nc() == out.nc() && - is_same_object(img_,out_) == false, - "\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() - << "\n\t is_same_object(img_,out_): " << is_same_object(img_,out_) - ); - - typedef typename image_traits<image_type1>::pixel_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(mat(img),strip))); - } - - ++left; - } - - - const rectangle area = get_rect(img); - - // Save width to avoid computing it over and over. - const long width = rect.width(); - - - // Now do the bulk of the filtering work. - for (long r = 0; r < img.nr(); ++r) - { - // set to sum at point(-1,r). i.e. should be equal to sum(mat(img), translate_rect(rect, 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]; - - if (add_to) - out[r][c] += static_cast<typename image_traits<image_type2>::pixel_type>(cur_sum); - else - out[r][c] = static_cast<typename image_traits<image_type2>::pixel_type>(cur_sum); - } - } - } - } - - template < - typename image_type1, - typename image_type2 - > - void sum_filter ( - const image_type1& img, - image_type2& out, - const rectangle& rect - ) - { - impl::sum_filter<true>(img,out,rect); - } - - template < - typename image_type1, - typename image_type2 - > - void sum_filter_assign ( - const image_type1& img, - image_type2& out, - const rectangle& rect - ) - { - set_image_size(out, num_rows(img), num_columns(img)); - impl::sum_filter<false>(img,out,rect); - } - -// ---------------------------------------------------------------------------------------- - - 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_traits<image_type1>::pixel_type& thresh - ) - { - image_view<image_type1> img(img_); - image_view<image_type2> out(out_); - DLIB_ASSERT( 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_traits<image_type1>::pixel_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-1)/2)); - const long last_row = std::max(img.nr(), ((height-1)/2)); - - // run max filter along rows of img - for (long r = 0; r < img.nr(); ++r) - { - Q.clear(); - for (long c = 0; c < (width-1)/2 && c < img.nc(); ++c) - { - while (!Q.empty() && img[r][c] >= Q.back().second) - Q.pop_back(); - Q.push_back(std::make_pair(c,img[r][c])); - } - - for (long c = (width-1)/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(std::make_pair(c,img[r][c])); - - img[r][c-((width-1)/2)] = Q.front().second; - } - - for (long c = last_col; c < img.nc() + ((width-1)/2); ++c) - { - while (!Q.empty() && Q.front().first <= c-width) - Q.pop_front(); - - img[r][c-((width-1)/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-1)/2 && rr < img.nr(); ++rr) - { - while (!Q.empty() && img[rr][cc] >= Q.back().second) - Q.pop_back(); - Q.push_back(std::make_pair(rr,img[rr][cc])); - } - - for (long rr = (height-1)/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(std::make_pair(rr,img[rr][cc])); - - out[rr-((height-1)/2)][cc] += std::max(Q.front().second, thresh); - } - - for (long rr = last_row; rr < img.nr() + ((height-1)/2); ++rr) - { - while (!Q.empty() && Q.front().first <= rr-height) - Q.pop_front(); - - out[rr-((height-1)/2)][cc] += std::max(Q.front().second, thresh); - } - } - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_SPATIAL_FILTERINg_H_ - - |