// Copyright (C) 2006 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #undef DLIB_SPATIAL_FILTERINg_ABSTRACT_ #ifdef DLIB_SPATIAL_FILTERINg_ABSTRACT_ #include "../pixel.h" #include "../matrix.h" namespace dlib { // ---------------------------------------------------------------------------------------- template < typename in_image_type, typename out_image_type, typename EXP, typename T > rectangle spatially_filter_image ( const in_image_type& in_img, out_image_type& out_img, const matrix_exp<EXP>& filter, T scale = 1, bool use_abs = false, bool add_to = 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 - T must be some scalar type - scale != 0 - 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 (i.e. cross-correlates in_img with filter). Also divides each resulting pixel by scale. - The intermediate filter computations will be carried out using variables of type EXP::type. This is whatever scalar type is used inside the filter matrix. - Pixel values are stored into out_img using the assign_pixel() function and therefore any applicable color space conversion or value saturation is performed. Note that if add_to is true then the filtered output value will be added to out_img rather than overwriting the original value. - 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. - Pixels close enough to the edge of in_img to not have the filter still fit inside the image are always set to zero. - #out_img.nc() == in_img.nc() - #out_img.nr() == in_img.nr() - returns a rectangle which indicates what pixels in #out_img are considered non-border pixels and therefore contain output from the filter. !*/ // ---------------------------------------------------------------------------------------- template < typename in_image_type, typename out_image_type, typename EXP1, typename EXP2, typename T > 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, T scale = 1, bool use_abs = false, bool add_to = 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 - T must be some scalar type - scale != 0 - 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) - The intermediate filter computations will be carried out using variables of type EXP1::type. This is whatever scalar type is used inside the row_filter matrix. - Pixel values are stored into out_img using the assign_pixel() function and therefore any applicable color space conversion or value saturation is performed. Note that if add_to is true then the filtered output value will be added to out_img rather than overwriting the original value. - 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 - Pixels close enough to the edge of in_img to not have the filter still fit inside the image are always set to zero. - #out_img.nc() == in_img.nc() - #out_img.nr() == in_img.nr() - returns a rectangle which indicates what pixels in #out_img are considered non-border pixels and therefore contain output from the filter. !*/ // ---------------------------------------------------------------------------------------- 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 = 1, bool use_abs = false, bool add_to = 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 - T must be some scalar type - scale != 0 - 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) - downsample > 0 ensures - This function is equivalent to calling spatially_filter_image_separable(in_img,out_img,row_filter,col_filter,scale,use_abs,add_to) and then downsampling the output image by a factor of downsample. Therefore, we will have that: - #out_img.nr() == ceil((double)in_img.nr()/downsample) - #out_img.nc() == ceil((double)in_img.nc()/downsample) - #out_img[r][c] == filtered pixel corresponding to in_img[r*downsample][c*downsample] - returns a rectangle which indicates what pixels in #out_img are considered non-border pixels and therefore contain output from the filter. - Note that the first row and column of non-zero padded data are the following - first_row == ceil(floor(col_filter.size()/2.0)/downsample) - first_col == ceil(floor(row_filter.size()/2.0)/downsample) !*/ // ---------------------------------------------------------------------------------------- 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, const U& fm, const U& fe2 ); /*! requires - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h - pixel_traits<typename in_image_type::type> must be defined - T and U should be scalar types - shrink_rect(get_rect(img),1).contains(c,r) - shrink_rect(get_rect(img),1).contains(c+NC-1,r+NR-1) ensures - Filters the image in the sub-window of img defined by a rectangle with its upper left corner at (c,r) and lower right at (c+NC-1,r+NR-1). - The output of the filter is stored in #block. Note that img will be interpreted as a grayscale image. - The filter used is defined by the separable filter [fe1 fm fe2]. So the spatial filter is thus: fe1*fe1 fe1*fm fe2*fe1 fe1*fm fm*fm fe2*fm fe1*fe2 fe2*fm fe2*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, const U& fm, const U& fe2 ); /*! requires - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h - pixel_traits<typename in_image_type::type>::rgb == true - T should be a struct with .red .green and .blue members. - U should be a scalar type - shrink_rect(get_rect(img),1).contains(c,r) - shrink_rect(get_rect(img),1).contains(c+NC-1,r+NR-1) ensures - Filters the image in the sub-window of img defined by a rectangle with its upper left corner at (c,r) and lower right at (c+NC-1,r+NR-1). - The output of the filter is stored in #block. Note that the filter is applied to each color component independently. - The filter used is defined by the separable filter [fe1 fm fe2]. So the spatial filter is thus: fe1*fe1 fe1*fm fe2*fe1 fe1*fm fm*fm fe2*fm fe1*fe2 fe2*fm fe2*fe2 !*/ // ---------------------------------------------------------------------------------------- inline double gaussian ( double x, double sigma ); /*! requires - sigma > 0 ensures - computes and returns the value of a 1D Gaussian function with mean 0 and standard deviation sigma at the given x value. !*/ // ---------------------------------------------------------------------------------------- template < typename T > matrix<T,0,1> create_gaussian_filter ( double sigma, int size ); /*! requires - sigma > 0 - size > 0 - size is an odd number ensures - returns a separable Gaussian filter F such that: - is_vector(F) == true - F.size() == size - F is suitable for use with the spatially_filter_image_separable() routine and its use with this function corresponds to running a Gaussian filter of sigma width over an image. !*/ // ---------------------------------------------------------------------------------------- template < typename in_image_type, typename out_image_type > void gaussian_blur ( const in_image_type& in_img, out_image_type& out_img, double sigma = 1, int max_size = 1001 ); /*! 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 - sigma > 0 - max_size > 0 - max_size is an odd number ensures - Filters in_img with a Gaussian filter of sigma width. The actual spatial filter will be applied to pixel blocks that are at most max_size wide and max_size tall (note that this function will automatically select a smaller block size as appropriate). The results are stored into #out_img. - Pixel values are stored into out_img using the assign_pixel() function and therefore any applicable color space conversion or value saturation is performed. - 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. - 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() !*/ // ---------------------------------------------------------------------------------------- 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 - is_same_object(img,out) == false ensures - for all valid r and c: - let SUM(r,c) == sum of pixels from img which are inside the rectangle translate_rect(rect, point(c,r)). - #out[r][c] == out[r][c] + SUM(r,c) !*/ // ---------------------------------------------------------------------------------------- template < typename image_type1, typename image_type2 > void sum_filter_assign ( 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 - is_same_object(img,out) == false ensures - for all valid r and c: - let SUM(r,c) == sum of pixels from img which are inside the rectangle translate_rect(rect, point(c,r)). - #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 > 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. !*/ // ---------------------------------------------------------------------------------------- } #endif // DLIB_SPATIAL_FILTERINg_ABSTRACT_