// Copyright (C) 2010 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_IMAGE_PYRaMID_H__ #define DLIB_IMAGE_PYRaMID_H__ #include "image_pyramid_abstract.h" #include "../pixel.h" #include "../array2d.h" #include "../geometry.h" #include "spatial_filtering.h" namespace dlib { // ---------------------------------------------------------------------------------------- class pyramid_disable : noncopyable { public: template <typename T> vector<double,2> point_down ( const vector<T,2>& ) const { return vector<double,2>(0,0); } template <typename T> vector<double,2> point_up ( const vector<T,2>& ) const { return vector<double,2>(0,0); } // ----------------------------- template <typename T> vector<double,2> point_down ( const vector<T,2>& p, unsigned int levels ) const { if (levels == 0) return p; else return vector<double,2>(0,0); } template <typename T> vector<double,2> point_up ( const vector<T,2>& p, unsigned int levels ) const { if (levels == 0) return p; else return vector<double,2>(0,0); } // ----------------------------- rectangle rect_up ( const rectangle& rect ) const { return rectangle(point_up(rect.tl_corner()), point_up(rect.br_corner())); } rectangle rect_up ( const rectangle& rect, unsigned int levels ) const { return rectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels)); } // ----------------------------- rectangle rect_down ( const rectangle& rect ) const { return rectangle(point_down(rect.tl_corner()), point_down(rect.br_corner())); } rectangle rect_down ( const rectangle& rect, unsigned int levels ) const { return rectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels)); } // ----------------------------- public: template < typename in_image_type, typename out_image_type > void operator() ( // we do this #ifdef stuff to avoid compiler warnings about unused variables. #ifdef ENABLE_ASSERTS const in_image_type& original, #else const in_image_type& , #endif out_image_type& down ) const { // make sure requires clause is not broken DLIB_ASSERT(is_same_object(original, down) == false, "\t void pyramid_disable::operator()" << "\n\t is_same_object(original, down): " << is_same_object(original, down) << "\n\t this: " << this ); 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 ); down.clear(); } }; // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- class pyramid_down : noncopyable { public: template <typename T> vector<double,2> point_down ( const vector<T,2>& p ) const { //do return (p - vector<T,2>(2,2))/2.0; return p/2.0 - vector<double,2>(1,1); } template <typename T> vector<double,2> point_up ( const vector<T,2>& p ) const { return p*2 + vector<T,2>(2,2); } // ----------------------------- template <typename T> vector<double,2> point_down ( const vector<T,2>& p, unsigned int levels ) const { vector<double,2> temp = p; for (unsigned int i = 0; i < levels; ++i) temp = point_down(temp); return temp; } template <typename T> vector<double,2> point_up ( const vector<T,2>& p, unsigned int levels ) const { vector<double,2> temp = p; for (unsigned int i = 0; i < levels; ++i) temp = point_up(temp); return temp; } // ----------------------------- rectangle rect_up ( const rectangle& rect ) const { return rectangle(point_up(rect.tl_corner()), point_up(rect.br_corner())); } rectangle rect_up ( const rectangle& rect, unsigned int levels ) const { return rectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels)); } // ----------------------------- rectangle rect_down ( const rectangle& rect ) const { return rectangle(point_down(rect.tl_corner()), point_down(rect.br_corner())); } rectangle rect_down ( const rectangle& rect, unsigned int levels ) const { return rectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels)); } // ----------------------------- private: template <typename T, typename U> struct both_images_rgb { const static bool value = pixel_traits<typename T::type>::rgb && pixel_traits<typename U::type>::rgb; }; public: template < typename in_image_type, typename out_image_type > typename disable_if<both_images_rgb<in_image_type,out_image_type> >::type operator() ( const in_image_type& original, out_image_type& down ) const { // make sure requires clause is not broken DLIB_ASSERT( is_same_object(original, down) == false, "\t void pyramid_down::operator()" << "\n\t is_same_object(original, down): " << is_same_object(original, down) << "\n\t this: " << this ); 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 ); if (original.nr() <= 8 || original.nc() <= 8) { down.clear(); return; } typedef typename pixel_traits<typename in_image_type::type>::basic_pixel_type bp_type; typedef typename promote<bp_type>::type ptype; array2d<ptype> temp_img; temp_img.set_size(original.nr(), (original.nc()-3)/2); down.set_size((original.nr()-3)/2, (original.nc()-3)/2); // This function applies a 5x5 Gaussian filter to the image. It // does this by separating the filter into its horizontal and vertical // components and then downsamples the image by dropping every other // row and column. Note that we can do these things all together in // one step. // apply row filter for (long r = 0; r < temp_img.nr(); ++r) { long oc = 0; for (long c = 0; c < temp_img.nc(); ++c) { ptype pix1; ptype pix2; ptype pix3; ptype pix4; ptype pix5; assign_pixel(pix1, original[r][oc]); assign_pixel(pix2, original[r][oc+1]); assign_pixel(pix3, original[r][oc+2]); assign_pixel(pix4, original[r][oc+3]); assign_pixel(pix5, original[r][oc+4]); pix2 *= 4; pix3 *= 6; pix4 *= 4; assign_pixel(temp_img[r][c], pix1 + pix2 + pix3 + pix4 + pix5); oc += 2; } } // apply column filter long dr = 0; for (long r = 2; r < temp_img.nr()-2; r += 2) { for (long c = 0; c < temp_img.nc(); ++c) { ptype temp = temp_img[r-2][c] + temp_img[r-1][c]*4 + temp_img[r ][c]*6 + temp_img[r-1][c]*4 + temp_img[r-2][c]; assign_pixel(down[dr][c],temp/256); } ++dr; } } private: struct rgbptype { uint16 red; uint16 green; uint16 blue; }; public: // ------------------------------------------ // OVERLOAD FOR RGB TO RGB IMAGES // ------------------------------------------ template < typename in_image_type, typename out_image_type > typename enable_if<both_images_rgb<in_image_type,out_image_type> >::type operator() ( const in_image_type& original, out_image_type& down ) const { // make sure requires clause is not broken DLIB_ASSERT( is_same_object(original, down) == false, "\t void pyramid_down::operator()" << "\n\t is_same_object(original, down): " << is_same_object(original, down) << "\n\t this: " << this ); 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 ); if (original.nr() <= 8 || original.nc() <= 8) { down.clear(); return; } array2d<rgbptype> temp_img; temp_img.set_size(original.nr(), (original.nc()-3)/2); down.set_size((original.nr()-3)/2, (original.nc()-3)/2); // This function applies a 5x5 Gaussian filter to the image. It // does this by separating the filter into its horizontal and vertical // components and then downsamples the image by dropping every other // row and column. Note that we can do these things all together in // one step. // apply row filter for (long r = 0; r < temp_img.nr(); ++r) { long oc = 0; for (long c = 0; c < temp_img.nc(); ++c) { rgbptype pix1; rgbptype pix2; rgbptype pix3; rgbptype pix4; rgbptype pix5; pix1.red = original[r][oc].red; pix2.red = original[r][oc+1].red; pix3.red = original[r][oc+2].red; pix4.red = original[r][oc+3].red; pix5.red = original[r][oc+4].red; pix1.green = original[r][oc].green; pix2.green = original[r][oc+1].green; pix3.green = original[r][oc+2].green; pix4.green = original[r][oc+3].green; pix5.green = original[r][oc+4].green; pix1.blue = original[r][oc].blue; pix2.blue = original[r][oc+1].blue; pix3.blue = original[r][oc+2].blue; pix4.blue = original[r][oc+3].blue; pix5.blue = original[r][oc+4].blue; pix2.red *= 4; pix3.red *= 6; pix4.red *= 4; pix2.green *= 4; pix3.green *= 6; pix4.green *= 4; pix2.blue *= 4; pix3.blue *= 6; pix4.blue *= 4; rgbptype temp; temp.red = pix1.red + pix2.red + pix3.red + pix4.red + pix5.red; temp.green = pix1.green + pix2.green + pix3.green + pix4.green + pix5.green; temp.blue = pix1.blue + pix2.blue + pix3.blue + pix4.blue + pix5.blue; temp_img[r][c] = temp; oc += 2; } } // apply column filter long dr = 0; for (long r = 2; r < temp_img.nr()-2; r += 2) { for (long c = 0; c < temp_img.nc(); ++c) { rgbptype temp; temp.red = temp_img[r-2][c].red + temp_img[r-1][c].red*4 + temp_img[r ][c].red*6 + temp_img[r-1][c].red*4 + temp_img[r-2][c].red; temp.green = temp_img[r-2][c].green + temp_img[r-1][c].green*4 + temp_img[r ][c].green*6 + temp_img[r-1][c].green*4 + temp_img[r-2][c].green; temp.blue = temp_img[r-2][c].blue + temp_img[r-1][c].blue*4 + temp_img[r ][c].blue*6 + temp_img[r-1][c].blue*4 + temp_img[r-2][c].blue; down[dr][c].red = temp.red/256; down[dr][c].green = temp.green/256; down[dr][c].blue = temp.blue/256; } ++dr; } } private: }; // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- class pyramid_down_3_2 : noncopyable { public: template <typename T> vector<double,2> point_down ( const vector<T,2>& p ) const { const double ratio = 2.0/3.0; //do return (p - vector<T,2>(1,1))*ratio; return p*ratio - vector<double,2>(ratio,ratio); } template <typename T> vector<double,2> point_up ( const vector<T,2>& p ) const { const double ratio = 3.0/2.0; return p*ratio + vector<T,2>(1,1); } // ----------------------------- template <typename T> vector<double,2> point_down ( const vector<T,2>& p, unsigned int levels ) const { vector<double,2> temp = p; for (unsigned int i = 0; i < levels; ++i) temp = point_down(temp); return temp; } template <typename T> vector<double,2> point_up ( const vector<T,2>& p, unsigned int levels ) const { vector<double,2> temp = p; for (unsigned int i = 0; i < levels; ++i) temp = point_up(temp); return temp; } // ----------------------------- rectangle rect_up ( const rectangle& rect ) const { return rectangle(point_up(rect.tl_corner()), point_up(rect.br_corner())); } rectangle rect_up ( const rectangle& rect, unsigned int levels ) const { return rectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels)); } // ----------------------------- rectangle rect_down ( const rectangle& rect ) const { return rectangle(point_down(rect.tl_corner()), point_down(rect.br_corner())); } rectangle rect_down ( const rectangle& rect, unsigned int levels ) const { return rectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels)); } // ----------------------------- private: template <typename T, typename U> struct both_images_rgb { const static bool value = pixel_traits<typename T::type>::rgb && pixel_traits<typename U::type>::rgb; }; public: template < typename in_image_type, typename out_image_type > typename disable_if<both_images_rgb<in_image_type,out_image_type> >::type operator() ( const in_image_type& original, out_image_type& down ) const { // make sure requires clause is not broken DLIB_ASSERT(is_same_object(original, down) == false, "\t void pyramid_down_3_2::operator()" << "\n\t is_same_object(original, down): " << is_same_object(original, down) << "\n\t this: " << this ); 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 ); if (original.nr() <= 8 || original.nc() <= 8) { down.clear(); return; } const long size_in = 3; const long size_out = 2; typedef typename pixel_traits<typename in_image_type::type>::basic_pixel_type bp_type; typedef typename promote<bp_type>::type ptype; const long full_nr = size_out*((original.nr()-2)/size_in); const long part_nr = (size_out*(original.nr()-2))/size_in; const long full_nc = size_out*((original.nc()-2)/size_in); const long part_nc = (size_out*(original.nc()-2))/size_in; down.set_size(part_nr, part_nc); long rr = 1; long r; for (r = 0; r < full_nr; r+=size_out) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { ptype block[size_in][size_in]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate block assign_pixel(down[r][c] , (block[0][0]*9 + block[1][0]*3 + block[0][1]*3 + block[1][1])/(16*256)); assign_pixel(down[r][c+1] , (block[0][2]*9 + block[1][2]*3 + block[0][1]*3 + block[1][1])/(16*256)); assign_pixel(down[r+1][c] , (block[2][0]*9 + block[1][0]*3 + block[2][1]*3 + block[1][1])/(16*256)); assign_pixel(down[r+1][c+1] , (block[2][2]*9 + block[1][2]*3 + block[2][1]*3 + block[1][1])/(16*256)); cc += size_in; } if (part_nc - full_nc == 1) { ptype block[size_in][2]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*9 + block[1][0]*3 + block[0][1]*3 + block[1][1])/(16*256)); assign_pixel(down[r+1][c] , (block[2][0]*9 + block[1][0]*3 + block[2][1]*3 + block[1][1])/(16*256)); } rr += size_in; } if (part_nr - full_nr == 1) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { ptype block[2][size_in]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*9 + block[1][0]*3 + block[0][1]*3 + block[1][1])/(16*256)); assign_pixel(down[r][c+1] , (block[0][2]*9 + block[1][2]*3 + block[0][1]*3 + block[1][1])/(16*256)); cc += size_in; } if (part_nc - full_nc == 1) { ptype block[2][2]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*9 + block[1][0]*3 + block[0][1]*3 + block[1][1])/(16*256)); } } } private: struct rgbptype { uint32 red; uint32 green; uint32 blue; }; public: // ------------------------------------------ // OVERLOAD FOR RGB TO RGB IMAGES // ------------------------------------------ template < typename in_image_type, typename out_image_type > typename enable_if<both_images_rgb<in_image_type,out_image_type> >::type operator() ( const in_image_type& original, out_image_type& down ) const { // make sure requires clause is not broken DLIB_ASSERT( is_same_object(original, down) == false, "\t void pyramid_down_3_2::operator()" << "\n\t is_same_object(original, down): " << is_same_object(original, down) << "\n\t this: " << this ); 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 ); if (original.nr() <= 8 || original.nc() <= 8) { down.clear(); return; } const long size_in = 3; const long size_out = 2; const long full_nr = size_out*((original.nr()-2)/size_in); const long part_nr = (size_out*(original.nr()-2))/size_in; const long full_nc = size_out*((original.nc()-2)/size_in); const long part_nc = (size_out*(original.nc()-2))/size_in; down.set_size(part_nr, part_nc); long rr = 1; long r; for (r = 0; r < full_nr; r+=size_out) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { rgbptype block[size_in][size_in]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate block down[r][c].red = (block[0][0].red*9 + block[1][0].red*3 + block[0][1].red*3 + block[1][1].red)/(16*256); down[r][c].green = (block[0][0].green*9 + block[1][0].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256); down[r][c].blue = (block[0][0].blue*9 + block[1][0].blue*3 + block[0][1].blue*3 + block[1][1].blue)/(16*256); down[r][c+1].red = (block[0][2].red*9 + block[1][2].red*3 + block[0][1].red*3 + block[1][1].red)/(16*256); down[r][c+1].green = (block[0][2].green*9 + block[1][2].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256); down[r][c+1].blue = (block[0][2].blue*9 + block[1][2].blue*3 + block[0][1].blue*3 + block[1][1].blue)/(16*256); down[r+1][c].red = (block[2][0].red*9 + block[1][0].red*3 + block[2][1].red*3 + block[1][1].red)/(16*256); down[r+1][c].green = (block[2][0].green*9 + block[1][0].green*3 + block[2][1].green*3 + block[1][1].green)/(16*256); down[r+1][c].blue = (block[2][0].blue*9 + block[1][0].blue*3 + block[2][1].blue*3 + block[1][1].blue)/(16*256); down[r+1][c+1].red = (block[2][2].red*9 + block[1][2].red*3 + block[2][1].red*3 + block[1][1].red)/(16*256); down[r+1][c+1].green = (block[2][2].green*9 + block[1][2].green*3 + block[2][1].green*3 + block[1][1].green)/(16*256); down[r+1][c+1].blue = (block[2][2].blue*9 + block[1][2].blue*3 + block[2][1].blue*3 + block[1][1].blue)/(16*256); cc += size_in; } if (part_nc - full_nc == 1) { rgbptype block[size_in][2]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*9 + block[1][0].red*3 + block[0][1].red*3 + block[1][1].red)/(16*256); down[r][c].green = (block[0][0].green*9 + block[1][0].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256); down[r][c].blue = (block[0][0].blue*9 + block[1][0].blue*3 + block[0][1].blue*3 + block[1][1].blue)/(16*256); down[r+1][c].red = (block[2][0].red*9 + block[1][0].red*3 + block[2][1].red*3 + block[1][1].red)/(16*256); down[r+1][c].green = (block[2][0].green*9 + block[1][0].green*3 + block[2][1].green*3 + block[1][1].green)/(16*256); down[r+1][c].blue = (block[2][0].blue*9 + block[1][0].blue*3 + block[2][1].blue*3 + block[1][1].blue)/(16*256); } rr += size_in; } if (part_nr - full_nr == 1) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { rgbptype block[2][size_in]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*9 + block[1][0].red*3 + block[0][1].red*3 + block[1][1].red)/(16*256); down[r][c].green = (block[0][0].green*9 + block[1][0].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256); down[r][c].blue = (block[0][0].blue*9 + block[1][0].blue*3 + block[0][1].blue*3 + block[1][1].blue)/(16*256); down[r][c+1].red = (block[0][2].red*9 + block[1][2].red*3 + block[0][1].red*3 + block[1][1].red)/(16*256); down[r][c+1].green = (block[0][2].green*9 + block[1][2].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256); down[r][c+1].blue = (block[0][2].blue*9 + block[1][2].blue*3 + block[0][1].blue*3 + block[1][1].blue)/(16*256); cc += size_in; } if (part_nc - full_nc == 1) { rgbptype block[2][2]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*9 + block[1][0].red*3 + block[0][1].red*3 + block[1][1].red)/(16*256); down[r][c].green = (block[0][0].green*9 + block[1][0].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256); down[r][c].blue = (block[0][0].blue*9 + block[1][0].blue*3 + block[0][1].blue*3 + block[1][1].blue)/(16*256); } } } private: }; // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- class pyramid_down_4_3 : noncopyable { public: template <typename T> vector<double,2> point_down ( const vector<T,2>& p ) const { const double ratio = 3.0/4.0; //do return (p - vector<T,2>(1,1))*ratio; return p*ratio - vector<double,2>(ratio,ratio); } template <typename T> vector<double,2> point_up ( const vector<T,2>& p ) const { const double ratio = 4.0/3.0; return p*ratio + vector<T,2>(1,1); } // ----------------------------- template <typename T> vector<double,2> point_down ( const vector<T,2>& p, unsigned int levels ) const { vector<double,2> temp = p; for (unsigned int i = 0; i < levels; ++i) temp = point_down(temp); return temp; } template <typename T> vector<double,2> point_up ( const vector<T,2>& p, unsigned int levels ) const { vector<double,2> temp = p; for (unsigned int i = 0; i < levels; ++i) temp = point_up(temp); return temp; } // ----------------------------- rectangle rect_up ( const rectangle& rect ) const { return rectangle(point_up(rect.tl_corner()), point_up(rect.br_corner())); } rectangle rect_up ( const rectangle& rect, unsigned int levels ) const { return rectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels)); } // ----------------------------- rectangle rect_down ( const rectangle& rect ) const { return rectangle(point_down(rect.tl_corner()), point_down(rect.br_corner())); } rectangle rect_down ( const rectangle& rect, unsigned int levels ) const { return rectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels)); } // ----------------------------- private: template <typename T, typename U> struct both_images_rgb { const static bool value = pixel_traits<typename T::type>::rgb && pixel_traits<typename U::type>::rgb; }; public: template < typename in_image_type, typename out_image_type > typename disable_if<both_images_rgb<in_image_type,out_image_type> >::type operator() ( const in_image_type& original, out_image_type& down ) const { // make sure requires clause is not broken DLIB_ASSERT( is_same_object(original, down) == false, "\t void pyramid_down_4_3::operator()" << "\n\t is_same_object(original, down): " << is_same_object(original, down) << "\n\t this: " << this ); 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 ); if (original.nr() <= 8 || original.nc() <= 8) { down.clear(); return; } const long size_in = 4; const long size_out = 3; typedef typename pixel_traits<typename in_image_type::type>::basic_pixel_type bp_type; typedef typename promote<bp_type>::type ptype; const long full_nr = size_out*((original.nr()-2)/size_in); const long part_nr = (size_out*(original.nr()-2))/size_in; const long full_nc = size_out*((original.nc()-2)/size_in); const long part_nc = (size_out*(original.nc()-2))/size_in; down.set_size(part_nr, part_nc); long rr = 1; long r; for (r = 0; r < full_nr; r+=size_out) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { ptype block[size_in][size_in]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate block assign_pixel(down[r][c] , (block[0][0]*25 + block[1][0]*5 + block[0][1]*5 + block[1][1])/(36*256)); assign_pixel(down[r][c+1] , (block[0][1]*5 + block[0][2]*5 + block[1][1] + block[1][2])/(12*256)); assign_pixel(down[r][c+2] , (block[0][3]*25 + block[1][3]*5 + block[0][2]*5 + block[1][2])/(36*256)); assign_pixel(down[r+1][c] , (block[1][0]*5 + block[2][0]*5 + block[1][1] + block[2][1])/(12*256)); assign_pixel(down[r+1][c+1] , (block[1][1] + block[1][2] + block[2][1] + block[2][2])/(4*256)); assign_pixel(down[r+1][c+2] , (block[1][3]*5 + block[2][3]*5 + block[1][2] + block[2][2])/(12*256)); assign_pixel(down[r+2][c] , (block[3][0]*25 + block[2][0]*5 + block[3][1]*5 + block[2][1])/(36*256)); assign_pixel(down[r+2][c+1] , (block[3][1]*5 + block[3][2]*5 + block[2][1] + block[2][2])/(12*256)); assign_pixel(down[r+2][c+2] , (block[3][3]*25 + block[2][3]*5 + block[3][2]*5 + block[2][2])/(36*256)); cc += size_in; } if (part_nc - full_nc == 2) { ptype block[size_in][3]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*25 + block[1][0]*5 + block[0][1]*5 + block[1][1])/(36*256)); assign_pixel(down[r][c+1] , (block[0][1]*5 + block[0][2]*5 + block[1][1] + block[1][2])/(12*256)); assign_pixel(down[r+1][c] , (block[1][0]*5 + block[2][0]*5 + block[1][1] + block[2][1])/(12*256)); assign_pixel(down[r+1][c+1] , (block[1][1] + block[1][2] + block[2][1] + block[2][2])/(4*256)); assign_pixel(down[r+2][c] , (block[3][0]*25 + block[2][0]*5 + block[3][1]*5 + block[2][1])/(36*256)); assign_pixel(down[r+2][c+1] , (block[3][1]*5 + block[3][2]*5 + block[2][1] + block[2][2])/(12*256)); } else if (part_nc - full_nc == 1) { ptype block[size_in][2]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*25 + block[1][0]*5 + block[0][1]*5 + block[1][1])/(36*256)); assign_pixel(down[r+1][c] , (block[1][0]*5 + block[2][0]*5 + block[1][1] + block[2][1])/(12*256)); assign_pixel(down[r+2][c] , (block[3][0]*25 + block[2][0]*5 + block[3][1]*5 + block[2][1])/(36*256)); } rr += size_in; } if (part_nr - full_nr == 2) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { ptype block[3][size_in]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate block assign_pixel(down[r][c] , (block[0][0]*25 + block[1][0]*5 + block[0][1]*5 + block[1][1])/(36*256)); assign_pixel(down[r][c+1] , (block[0][1]*5 + block[0][2]*5 + block[1][1] + block[1][2])/(12*256)); assign_pixel(down[r][c+2] , (block[0][3]*25 + block[1][3]*5 + block[0][2]*5 + block[1][2])/(36*256)); assign_pixel(down[r+1][c] , (block[1][0]*5 + block[2][0]*5 + block[1][1] + block[2][1])/(12*256)); assign_pixel(down[r+1][c+1] , (block[1][1] + block[1][2] + block[2][1] + block[2][2])/(4*256)); assign_pixel(down[r+1][c+2] , (block[1][3]*5 + block[2][3]*5 + block[1][2] + block[2][2])/(12*256)); cc += size_in; } if (part_nc - full_nc == 2) { ptype block[3][3]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*25 + block[1][0]*5 + block[0][1]*5 + block[1][1])/(36*256)); assign_pixel(down[r][c+1] , (block[0][1]*5 + block[0][2]*5 + block[1][1] + block[1][2])/(12*256)); assign_pixel(down[r+1][c] , (block[1][0]*5 + block[2][0]*5 + block[1][1] + block[2][1])/(12*256)); assign_pixel(down[r+1][c+1] , (block[1][1] + block[1][2] + block[2][1] + block[2][2])/(4*256)); } else if (part_nc - full_nc == 1) { ptype block[3][2]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*25 + block[1][0]*5 + block[0][1]*5 + block[1][1])/(36*256)); assign_pixel(down[r+1][c] , (block[1][0]*5 + block[2][0]*5 + block[1][1] + block[2][1])/(12*256)); } } else if (part_nr - full_nr == 1) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { ptype block[2][size_in]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate block assign_pixel(down[r][c] , (block[0][0]*25 + block[1][0]*5 + block[0][1]*5 + block[1][1])/(36*256)); assign_pixel(down[r][c+1] , (block[0][1]*5 + block[0][2]*5 + block[1][1] + block[1][2])/(12*256)); assign_pixel(down[r][c+2] , (block[0][3]*25 + block[1][3]*5 + block[0][2]*5 + block[1][2])/(36*256)); cc += size_in; } if (part_nc - full_nc == 2) { ptype block[2][3]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*25 + block[1][0]*5 + block[0][1]*5 + block[1][1])/(36*256)); assign_pixel(down[r][c+1] , (block[0][1]*5 + block[0][2]*5 + block[1][1] + block[1][2])/(12*256)); } else if (part_nc - full_nc == 1) { ptype block[2][2]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*25 + block[1][0]*5 + block[0][1]*5 + block[1][1])/(36*256)); } } } private: struct rgbptype { uint32 red; uint32 green; uint32 blue; }; public: // ------------------------------------------ // OVERLOAD FOR RGB TO RGB IMAGES // ------------------------------------------ template < typename in_image_type, typename out_image_type > typename enable_if<both_images_rgb<in_image_type,out_image_type> >::type operator() ( const in_image_type& original, out_image_type& down ) const { // make sure requires clause is not broken DLIB_ASSERT(is_same_object(original, down) == false, "\t void pyramid_down_4_3::operator()" << "\n\t is_same_object(original, down): " << is_same_object(original, down) << "\n\t this: " << this ); 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 ); if (original.nr() <= 8 || original.nc() <= 8) { down.clear(); return; } const long size_in = 4; const long size_out = 3; const long full_nr = size_out*((original.nr()-2)/size_in); const long part_nr = (size_out*(original.nr()-2))/size_in; const long full_nc = size_out*((original.nc()-2)/size_in); const long part_nc = (size_out*(original.nc()-2))/size_in; down.set_size(part_nr, part_nc); long rr = 1; long r; for (r = 0; r < full_nr; r+=size_out) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { rgbptype block[size_in][size_in]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate block down[r][c].red = (block[0][0].red*25 + block[1][0].red*5 + block[0][1].red*5 + block[1][1].red )/(36*256); down[r][c].green = (block[0][0].green*25 + block[1][0].green*5 + block[0][1].green*5 + block[1][1].green)/(36*256); down[r][c].blue = (block[0][0].blue*25 + block[1][0].blue*5 + block[0][1].blue*5 + block[1][1].blue )/(36*256); down[r][c+1].red = (block[0][1].red*5 + block[0][2].red*5 + block[1][1].red + block[1][2].red )/(12*256); down[r][c+1].green = (block[0][1].green*5 + block[0][2].green*5 + block[1][1].green + block[1][2].green)/(12*256); down[r][c+1].blue = (block[0][1].blue*5 + block[0][2].blue*5 + block[1][1].blue + block[1][2].blue )/(12*256); down[r][c+2].red = (block[0][3].red*25 + block[1][3].red*5 + block[0][2].red*5 + block[1][2].red )/(36*256); down[r][c+2].green = (block[0][3].green*25 + block[1][3].green*5 + block[0][2].green*5 + block[1][2].green)/(36*256); down[r][c+2].blue = (block[0][3].blue*25 + block[1][3].blue*5 + block[0][2].blue*5 + block[1][2].blue )/(36*256); down[r+1][c].red = (block[1][0].red*5 + block[2][0].red*5 + block[1][1].red + block[2][1].red )/(12*256); down[r+1][c].green = (block[1][0].green*5 + block[2][0].green*5 + block[1][1].green + block[2][1].green)/(12*256); down[r+1][c].blue = (block[1][0].blue*5 + block[2][0].blue*5 + block[1][1].blue + block[2][1].blue )/(12*256); down[r+1][c+1].red = (block[1][1].red + block[1][2].red + block[2][1].red + block[2][2].red )/(4*256); down[r+1][c+1].green = (block[1][1].green + block[1][2].green + block[2][1].green + block[2][2].green)/(4*256); down[r+1][c+1].blue = (block[1][1].blue + block[1][2].blue + block[2][1].blue + block[2][2].blue )/(4*256); down[r+1][c+2].red = (block[1][3].red*5 + block[2][3].red*5 + block[1][2].red + block[2][2].red )/(12*256); down[r+1][c+2].green = (block[1][3].green*5 + block[2][3].green*5 + block[1][2].green + block[2][2].green)/(12*256); down[r+1][c+2].blue = (block[1][3].blue*5 + block[2][3].blue*5 + block[1][2].blue + block[2][2].blue )/(12*256); down[r+2][c].red = (block[3][0].red*25 + block[2][0].red*5 + block[3][1].red*5 + block[2][1].red )/(36*256); down[r+2][c].green = (block[3][0].green*25 + block[2][0].green*5 + block[3][1].green*5 + block[2][1].green)/(36*256); down[r+2][c].blue = (block[3][0].blue*25 + block[2][0].blue*5 + block[3][1].blue*5 + block[2][1].blue )/(36*256); down[r+2][c+1].red = (block[3][1].red*5 + block[3][2].red*5 + block[2][1].red + block[2][2].red )/(12*256); down[r+2][c+1].green = (block[3][1].green*5 + block[3][2].green*5 + block[2][1].green + block[2][2].green)/(12*256); down[r+2][c+1].blue = (block[3][1].blue*5 + block[3][2].blue*5 + block[2][1].blue + block[2][2].blue )/(12*256); down[r+2][c+2].red = (block[3][3].red*25 + block[2][3].red*5 + block[3][2].red*5 + block[2][2].red )/(36*256); down[r+2][c+2].green = (block[3][3].green*25 + block[2][3].green*5 + block[3][2].green*5 + block[2][2].green)/(36*256); down[r+2][c+2].blue = (block[3][3].blue*25 + block[2][3].blue*5 + block[3][2].blue*5 + block[2][2].blue )/(36*256); cc += size_in; } if (part_nc - full_nc == 2) { rgbptype block[size_in][3]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*25 + block[1][0].red*5 + block[0][1].red*5 + block[1][1].red )/(36*256); down[r][c].green = (block[0][0].green*25 + block[1][0].green*5 + block[0][1].green*5 + block[1][1].green)/(36*256); down[r][c].blue = (block[0][0].blue*25 + block[1][0].blue*5 + block[0][1].blue*5 + block[1][1].blue )/(36*256); down[r][c+1].red = (block[0][1].red*5 + block[0][2].red*5 + block[1][1].red + block[1][2].red )/(12*256); down[r][c+1].green = (block[0][1].green*5 + block[0][2].green*5 + block[1][1].green + block[1][2].green)/(12*256); down[r][c+1].blue = (block[0][1].blue*5 + block[0][2].blue*5 + block[1][1].blue + block[1][2].blue )/(12*256); down[r+1][c].red = (block[1][0].red*5 + block[2][0].red*5 + block[1][1].red + block[2][1].red )/(12*256); down[r+1][c].green = (block[1][0].green*5 + block[2][0].green*5 + block[1][1].green + block[2][1].green)/(12*256); down[r+1][c].blue = (block[1][0].blue*5 + block[2][0].blue*5 + block[1][1].blue + block[2][1].blue )/(12*256); down[r+1][c+1].red = (block[1][1].red + block[1][2].red + block[2][1].red + block[2][2].red )/(4*256); down[r+1][c+1].green = (block[1][1].green + block[1][2].green + block[2][1].green + block[2][2].green)/(4*256); down[r+1][c+1].blue = (block[1][1].blue + block[1][2].blue + block[2][1].blue + block[2][2].blue )/(4*256); down[r+2][c].red = (block[3][0].red*25 + block[2][0].red*5 + block[3][1].red*5 + block[2][1].red )/(36*256); down[r+2][c].green = (block[3][0].green*25 + block[2][0].green*5 + block[3][1].green*5 + block[2][1].green)/(36*256); down[r+2][c].blue = (block[3][0].blue*25 + block[2][0].blue*5 + block[3][1].blue*5 + block[2][1].blue )/(36*256); down[r+2][c+1].red = (block[3][1].red*5 + block[3][2].red*5 + block[2][1].red + block[2][2].red )/(12*256); down[r+2][c+1].green = (block[3][1].green*5 + block[3][2].green*5 + block[2][1].green + block[2][2].green)/(12*256); down[r+2][c+1].blue = (block[3][1].blue*5 + block[3][2].blue*5 + block[2][1].blue + block[2][2].blue )/(12*256); } if (part_nc - full_nc == 1) { rgbptype block[size_in][2]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*25 + block[1][0].red*5 + block[0][1].red*5 + block[1][1].red )/(36*256); down[r][c].green = (block[0][0].green*25 + block[1][0].green*5 + block[0][1].green*5 + block[1][1].green)/(36*256); down[r][c].blue = (block[0][0].blue*25 + block[1][0].blue*5 + block[0][1].blue*5 + block[1][1].blue )/(36*256); down[r+1][c].red = (block[1][0].red*5 + block[2][0].red*5 + block[1][1].red + block[2][1].red )/(12*256); down[r+1][c].green = (block[1][0].green*5 + block[2][0].green*5 + block[1][1].green + block[2][1].green)/(12*256); down[r+1][c].blue = (block[1][0].blue*5 + block[2][0].blue*5 + block[1][1].blue + block[2][1].blue )/(12*256); down[r+2][c].red = (block[3][0].red*25 + block[2][0].red*5 + block[3][1].red*5 + block[2][1].red )/(36*256); down[r+2][c].green = (block[3][0].green*25 + block[2][0].green*5 + block[3][1].green*5 + block[2][1].green)/(36*256); down[r+2][c].blue = (block[3][0].blue*25 + block[2][0].blue*5 + block[3][1].blue*5 + block[2][1].blue )/(36*256); } rr += size_in; } if (part_nr - full_nr == 2) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { rgbptype block[3][size_in]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate block down[r][c].red = (block[0][0].red*25 + block[1][0].red*5 + block[0][1].red*5 + block[1][1].red )/(36*256); down[r][c].green = (block[0][0].green*25 + block[1][0].green*5 + block[0][1].green*5 + block[1][1].green)/(36*256); down[r][c].blue = (block[0][0].blue*25 + block[1][0].blue*5 + block[0][1].blue*5 + block[1][1].blue )/(36*256); down[r][c+1].red = (block[0][1].red*5 + block[0][2].red*5 + block[1][1].red + block[1][2].red )/(12*256); down[r][c+1].green = (block[0][1].green*5 + block[0][2].green*5 + block[1][1].green + block[1][2].green)/(12*256); down[r][c+1].blue = (block[0][1].blue*5 + block[0][2].blue*5 + block[1][1].blue + block[1][2].blue )/(12*256); down[r][c+2].red = (block[0][3].red*25 + block[1][3].red*5 + block[0][2].red*5 + block[1][2].red )/(36*256); down[r][c+2].green = (block[0][3].green*25 + block[1][3].green*5 + block[0][2].green*5 + block[1][2].green)/(36*256); down[r][c+2].blue = (block[0][3].blue*25 + block[1][3].blue*5 + block[0][2].blue*5 + block[1][2].blue )/(36*256); down[r+1][c].red = (block[1][0].red*5 + block[2][0].red*5 + block[1][1].red + block[2][1].red )/(12*256); down[r+1][c].green = (block[1][0].green*5 + block[2][0].green*5 + block[1][1].green + block[2][1].green)/(12*256); down[r+1][c].blue = (block[1][0].blue*5 + block[2][0].blue*5 + block[1][1].blue + block[2][1].blue )/(12*256); down[r+1][c+1].red = (block[1][1].red + block[1][2].red + block[2][1].red + block[2][2].red )/(4*256); down[r+1][c+1].green = (block[1][1].green + block[1][2].green + block[2][1].green + block[2][2].green)/(4*256); down[r+1][c+1].blue = (block[1][1].blue + block[1][2].blue + block[2][1].blue + block[2][2].blue )/(4*256); down[r+1][c+2].red = (block[1][3].red*5 + block[2][3].red*5 + block[1][2].red + block[2][2].red )/(12*256); down[r+1][c+2].green = (block[1][3].green*5 + block[2][3].green*5 + block[1][2].green + block[2][2].green)/(12*256); down[r+1][c+2].blue = (block[1][3].blue*5 + block[2][3].blue*5 + block[1][2].blue + block[2][2].blue )/(12*256); cc += size_in; } if (part_nc - full_nc == 2) { rgbptype block[3][3]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*25 + block[1][0].red*5 + block[0][1].red*5 + block[1][1].red )/(36*256); down[r][c].green = (block[0][0].green*25 + block[1][0].green*5 + block[0][1].green*5 + block[1][1].green)/(36*256); down[r][c].blue = (block[0][0].blue*25 + block[1][0].blue*5 + block[0][1].blue*5 + block[1][1].blue )/(36*256); down[r][c+1].red = (block[0][1].red*5 + block[0][2].red*5 + block[1][1].red + block[1][2].red )/(12*256); down[r][c+1].green = (block[0][1].green*5 + block[0][2].green*5 + block[1][1].green + block[1][2].green)/(12*256); down[r][c+1].blue = (block[0][1].blue*5 + block[0][2].blue*5 + block[1][1].blue + block[1][2].blue )/(12*256); down[r+1][c].red = (block[1][0].red*5 + block[2][0].red*5 + block[1][1].red + block[2][1].red )/(12*256); down[r+1][c].green = (block[1][0].green*5 + block[2][0].green*5 + block[1][1].green + block[2][1].green)/(12*256); down[r+1][c].blue = (block[1][0].blue*5 + block[2][0].blue*5 + block[1][1].blue + block[2][1].blue )/(12*256); down[r+1][c+1].red = (block[1][1].red + block[1][2].red + block[2][1].red + block[2][2].red )/(4*256); down[r+1][c+1].green = (block[1][1].green + block[1][2].green + block[2][1].green + block[2][2].green)/(4*256); down[r+1][c+1].blue = (block[1][1].blue + block[1][2].blue + block[2][1].blue + block[2][2].blue )/(4*256); } if (part_nc - full_nc == 1) { rgbptype block[3][2]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*25 + block[1][0].red*5 + block[0][1].red*5 + block[1][1].red )/(36*256); down[r][c].green = (block[0][0].green*25 + block[1][0].green*5 + block[0][1].green*5 + block[1][1].green)/(36*256); down[r][c].blue = (block[0][0].blue*25 + block[1][0].blue*5 + block[0][1].blue*5 + block[1][1].blue )/(36*256); down[r+1][c].red = (block[1][0].red*5 + block[2][0].red*5 + block[1][1].red + block[2][1].red )/(12*256); down[r+1][c].green = (block[1][0].green*5 + block[2][0].green*5 + block[1][1].green + block[2][1].green)/(12*256); down[r+1][c].blue = (block[1][0].blue*5 + block[2][0].blue*5 + block[1][1].blue + block[2][1].blue )/(12*256); } } if (part_nr - full_nr == 1) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { rgbptype block[2][size_in]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate block down[r][c].red = (block[0][0].red*25 + block[1][0].red*5 + block[0][1].red*5 + block[1][1].red )/(36*256); down[r][c].green = (block[0][0].green*25 + block[1][0].green*5 + block[0][1].green*5 + block[1][1].green)/(36*256); down[r][c].blue = (block[0][0].blue*25 + block[1][0].blue*5 + block[0][1].blue*5 + block[1][1].blue )/(36*256); down[r][c+1].red = (block[0][1].red*5 + block[0][2].red*5 + block[1][1].red + block[1][2].red )/(12*256); down[r][c+1].green = (block[0][1].green*5 + block[0][2].green*5 + block[1][1].green + block[1][2].green)/(12*256); down[r][c+1].blue = (block[0][1].blue*5 + block[0][2].blue*5 + block[1][1].blue + block[1][2].blue )/(12*256); down[r][c+2].red = (block[0][3].red*25 + block[1][3].red*5 + block[0][2].red*5 + block[1][2].red )/(36*256); down[r][c+2].green = (block[0][3].green*25 + block[1][3].green*5 + block[0][2].green*5 + block[1][2].green)/(36*256); down[r][c+2].blue = (block[0][3].blue*25 + block[1][3].blue*5 + block[0][2].blue*5 + block[1][2].blue )/(36*256); cc += size_in; } if (part_nc - full_nc == 2) { rgbptype block[2][3]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*25 + block[1][0].red*5 + block[0][1].red*5 + block[1][1].red )/(36*256); down[r][c].green = (block[0][0].green*25 + block[1][0].green*5 + block[0][1].green*5 + block[1][1].green)/(36*256); down[r][c].blue = (block[0][0].blue*25 + block[1][0].blue*5 + block[0][1].blue*5 + block[1][1].blue )/(36*256); down[r][c+1].red = (block[0][1].red*5 + block[0][2].red*5 + block[1][1].red + block[1][2].red )/(12*256); down[r][c+1].green = (block[0][1].green*5 + block[0][2].green*5 + block[1][1].green + block[1][2].green)/(12*256); down[r][c+1].blue = (block[0][1].blue*5 + block[0][2].blue*5 + block[1][1].blue + block[1][2].blue )/(12*256); } if (part_nc - full_nc == 1) { rgbptype block[2][2]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*25 + block[1][0].red*5 + block[0][1].red*5 + block[1][1].red )/(36*256); down[r][c].green = (block[0][0].green*25 + block[1][0].green*5 + block[0][1].green*5 + block[1][1].green)/(36*256); down[r][c].blue = (block[0][0].blue*25 + block[1][0].blue*5 + block[0][1].blue*5 + block[1][1].blue )/(36*256); } } } private: }; // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- class pyramid_down_5_4 : noncopyable { public: template <typename T> vector<double,2> point_down ( const vector<T,2>& p ) const { const double ratio = 4.0/5.0; //do return (p - vector<T,2>(1,1))*ratio; return p*ratio - vector<double,2>(ratio,ratio); } template <typename T> vector<double,2> point_up ( const vector<T,2>& p ) const { const double ratio = 5.0/4.0; return p*ratio + vector<T,2>(1,1); } // ----------------------------- template <typename T> vector<double,2> point_down ( const vector<T,2>& p, unsigned int levels ) const { vector<double,2> temp = p; for (unsigned int i = 0; i < levels; ++i) temp = point_down(temp); return temp; } template <typename T> vector<double,2> point_up ( const vector<T,2>& p, unsigned int levels ) const { vector<double,2> temp = p; for (unsigned int i = 0; i < levels; ++i) temp = point_up(temp); return temp; } // ----------------------------- rectangle rect_up ( const rectangle& rect ) const { return rectangle(point_up(rect.tl_corner()), point_up(rect.br_corner())); } rectangle rect_up ( const rectangle& rect, unsigned int levels ) const { return rectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels)); } // ----------------------------- rectangle rect_down ( const rectangle& rect ) const { return rectangle(point_down(rect.tl_corner()), point_down(rect.br_corner())); } rectangle rect_down ( const rectangle& rect, unsigned int levels ) const { return rectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels)); } // ----------------------------- private: template <typename T, typename U> struct both_images_rgb { const static bool value = pixel_traits<typename T::type>::rgb && pixel_traits<typename U::type>::rgb; }; public: template < typename in_image_type, typename out_image_type > typename disable_if<both_images_rgb<in_image_type,out_image_type> >::type operator() ( const in_image_type& original, out_image_type& down ) const { // make sure requires clause is not broken DLIB_ASSERT(is_same_object(original, down) == false, "\t void pyramid_down_5_4::operator()" << "\n\t is_same_object(original, down): " << is_same_object(original, down) << "\n\t this: " << this ); 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 ); if (original.nr() <= 8 || original.nc() <= 8) { down.clear(); return; } const long size_in = 5; const long size_out = 4; typedef typename pixel_traits<typename in_image_type::type>::basic_pixel_type bp_type; typedef typename promote<bp_type>::type ptype; const long full_nr = size_out*((original.nr()-2)/size_in); const long part_nr = (size_out*(original.nr()-2))/size_in; const long full_nc = size_out*((original.nc()-2)/size_in); const long part_nc = (size_out*(original.nc()-2))/size_in; down.set_size(part_nr, part_nc); long rr = 1; long r; for (r = 0; r < full_nr; r+=size_out) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { ptype block[size_in][size_in]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate block assign_pixel(down[r][c] , (block[0][0]*49 + block[1][0]*7 + block[0][1]*7 + block[1][1] )/(64*256)); assign_pixel(down[r][c+1] , (block[0][1]*35 + block[0][2]*21 + block[1][1]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r][c+2] , (block[0][3]*35 + block[0][2]*21 + block[1][3]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r][c+3] , (block[0][4]*49 + block[0][3]*7 + block[1][4]*7 + block[1][3] )/(64*256)); assign_pixel(down[r+1][c] , (block[1][0]*35 + block[1][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+1][c+1] , (block[1][1]*25 + block[1][2]*15 + block[2][1]*15 + block[2][2]*9 )/(64*256)); assign_pixel(down[r+1][c+2] , (block[1][2]*15 + block[1][3]*25 + block[2][2]*9 + block[2][3]*15)/(64*256)); assign_pixel(down[r+1][c+3] , (block[1][3]*5 + block[1][4]*35 + block[2][3]*3 + block[2][4]*21)/(64*256)); assign_pixel(down[r+2][c] , (block[3][0]*35 + block[3][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+2][c+1] , (block[3][1]*25 + block[3][2]*15 + block[2][1]*15 + block[2][2]*9 )/(64*256)); assign_pixel(down[r+2][c+2] , (block[3][2]*15 + block[3][3]*25 + block[2][2]*9 + block[2][3]*15)/(64*256)); assign_pixel(down[r+2][c+3] , (block[3][3]*5 + block[3][4]*35 + block[2][3]*3 + block[2][4]*21)/(64*256)); assign_pixel(down[r+3][c] , (block[4][0]*49 + block[3][0]*7 + block[4][1]*7 + block[3][1] )/(64*256)); assign_pixel(down[r+3][c+1] , (block[4][1]*35 + block[4][2]*21 + block[3][1]*5 + block[3][2]*3 )/(64*256)); assign_pixel(down[r+3][c+2] , (block[4][3]*35 + block[4][2]*21 + block[3][3]*5 + block[3][2]*3 )/(64*256)); assign_pixel(down[r+3][c+3] , (block[4][4]*49 + block[4][3]*7 + block[3][4]*7 + block[3][3] )/(64*256)); cc += size_in; } if (part_nc - full_nc == 3) { ptype block[size_in][4]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*49 + block[1][0]*7 + block[0][1]*7 + block[1][1] )/(64*256)); assign_pixel(down[r][c+1] , (block[0][1]*35 + block[0][2]*21 + block[1][1]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r][c+2] , (block[0][3]*35 + block[0][2]*21 + block[1][3]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r+1][c] , (block[1][0]*35 + block[1][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+1][c+1] , (block[1][1]*25 + block[1][2]*15 + block[2][1]*15 + block[2][2]*9 )/(64*256)); assign_pixel(down[r+1][c+2] , (block[1][2]*15 + block[1][3]*25 + block[2][2]*9 + block[2][3]*15)/(64*256)); assign_pixel(down[r+2][c] , (block[3][0]*35 + block[3][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+2][c+1] , (block[3][1]*25 + block[3][2]*15 + block[2][1]*15 + block[2][2]*9 )/(64*256)); assign_pixel(down[r+2][c+2] , (block[3][2]*15 + block[3][3]*25 + block[2][2]*9 + block[2][3]*15)/(64*256)); assign_pixel(down[r+3][c] , (block[4][0]*49 + block[3][0]*7 + block[4][1]*7 + block[3][1] )/(64*256)); assign_pixel(down[r+3][c+1] , (block[4][1]*35 + block[4][2]*21 + block[3][1]*5 + block[3][2]*3 )/(64*256)); assign_pixel(down[r+3][c+2] , (block[4][3]*35 + block[4][2]*21 + block[3][3]*5 + block[3][2]*3 )/(64*256)); } else if (part_nc - full_nc == 2) { ptype block[size_in][3]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*49 + block[1][0]*7 + block[0][1]*7 + block[1][1] )/(64*256)); assign_pixel(down[r][c+1] , (block[0][1]*35 + block[0][2]*21 + block[1][1]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r+1][c] , (block[1][0]*35 + block[1][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+1][c+1] , (block[1][1]*25 + block[1][2]*15 + block[2][1]*15 + block[2][2]*9 )/(64*256)); assign_pixel(down[r+2][c] , (block[3][0]*35 + block[3][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+2][c+1] , (block[3][1]*25 + block[3][2]*15 + block[2][1]*15 + block[2][2]*9 )/(64*256)); assign_pixel(down[r+3][c] , (block[4][0]*49 + block[3][0]*7 + block[4][1]*7 + block[3][1] )/(64*256)); assign_pixel(down[r+3][c+1] , (block[4][1]*35 + block[4][2]*21 + block[3][1]*5 + block[3][2]*3 )/(64*256)); } else if (part_nc - full_nc == 1) { ptype block[size_in][2]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*49 + block[1][0]*7 + block[0][1]*7 + block[1][1] )/(64*256)); assign_pixel(down[r+1][c] , (block[1][0]*35 + block[1][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+2][c] , (block[3][0]*35 + block[3][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+3][c] , (block[4][0]*49 + block[3][0]*7 + block[4][1]*7 + block[3][1] )/(64*256)); } rr += size_in; } if (part_nr - full_nr == 3) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { ptype block[4][size_in]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*49 + block[1][0]*7 + block[0][1]*7 + block[1][1] )/(64*256)); assign_pixel(down[r][c+1] , (block[0][1]*35 + block[0][2]*21 + block[1][1]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r][c+2] , (block[0][3]*35 + block[0][2]*21 + block[1][3]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r][c+3] , (block[0][4]*49 + block[0][3]*7 + block[1][4]*7 + block[1][3] )/(64*256)); assign_pixel(down[r+1][c] , (block[1][0]*35 + block[1][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+1][c+1] , (block[1][1]*25 + block[1][2]*15 + block[2][1]*15 + block[2][2]*9 )/(64*256)); assign_pixel(down[r+1][c+2] , (block[1][2]*15 + block[1][3]*25 + block[2][2]*9 + block[2][3]*15)/(64*256)); assign_pixel(down[r+1][c+3] , (block[1][3]*5 + block[1][4]*35 + block[2][3]*3 + block[2][4]*21)/(64*256)); assign_pixel(down[r+2][c] , (block[3][0]*35 + block[3][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+2][c+1] , (block[3][1]*25 + block[3][2]*15 + block[2][1]*15 + block[2][2]*9 )/(64*256)); assign_pixel(down[r+2][c+2] , (block[3][2]*15 + block[3][3]*25 + block[2][2]*9 + block[2][3]*15)/(64*256)); assign_pixel(down[r+2][c+3] , (block[3][3]*5 + block[3][4]*35 + block[2][3]*3 + block[2][4]*21)/(64*256)); cc += size_in; } if (part_nc - full_nc == 3) { ptype block[4][4]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*49 + block[1][0]*7 + block[0][1]*7 + block[1][1] )/(64*256)); assign_pixel(down[r][c+1] , (block[0][1]*35 + block[0][2]*21 + block[1][1]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r][c+2] , (block[0][3]*35 + block[0][2]*21 + block[1][3]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r+1][c] , (block[1][0]*35 + block[1][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+1][c+1] , (block[1][1]*25 + block[1][2]*15 + block[2][1]*15 + block[2][2]*9 )/(64*256)); assign_pixel(down[r+1][c+2] , (block[1][2]*15 + block[1][3]*25 + block[2][2]*9 + block[2][3]*15)/(64*256)); assign_pixel(down[r+2][c] , (block[3][0]*35 + block[3][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+2][c+1] , (block[3][1]*25 + block[3][2]*15 + block[2][1]*15 + block[2][2]*9 )/(64*256)); assign_pixel(down[r+2][c+2] , (block[3][2]*15 + block[3][3]*25 + block[2][2]*9 + block[2][3]*15)/(64*256)); } else if (part_nc - full_nc == 2) { ptype block[4][3]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*49 + block[1][0]*7 + block[0][1]*7 + block[1][1] )/(64*256)); assign_pixel(down[r][c+1] , (block[0][1]*35 + block[0][2]*21 + block[1][1]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r+1][c] , (block[1][0]*35 + block[1][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+1][c+1] , (block[1][1]*25 + block[1][2]*15 + block[2][1]*15 + block[2][2]*9 )/(64*256)); assign_pixel(down[r+2][c] , (block[3][0]*35 + block[3][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+2][c+1] , (block[3][1]*25 + block[3][2]*15 + block[2][1]*15 + block[2][2]*9 )/(64*256)); } else if (part_nc - full_nc == 1) { ptype block[4][2]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*49 + block[1][0]*7 + block[0][1]*7 + block[1][1] )/(64*256)); assign_pixel(down[r+1][c] , (block[1][0]*35 + block[1][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+2][c] , (block[3][0]*35 + block[3][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); } } else if (part_nr - full_nr == 2) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { ptype block[3][size_in]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*49 + block[1][0]*7 + block[0][1]*7 + block[1][1] )/(64*256)); assign_pixel(down[r][c+1] , (block[0][1]*35 + block[0][2]*21 + block[1][1]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r][c+2] , (block[0][3]*35 + block[0][2]*21 + block[1][3]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r][c+3] , (block[0][4]*49 + block[0][3]*7 + block[1][4]*7 + block[1][3] )/(64*256)); assign_pixel(down[r+1][c] , (block[1][0]*35 + block[1][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+1][c+1] , (block[1][1]*25 + block[1][2]*15 + block[2][1]*15 + block[2][2]*9 )/(64*256)); assign_pixel(down[r+1][c+2] , (block[1][2]*15 + block[1][3]*25 + block[2][2]*9 + block[2][3]*15)/(64*256)); assign_pixel(down[r+1][c+3] , (block[1][3]*5 + block[1][4]*35 + block[2][3]*3 + block[2][4]*21)/(64*256)); cc += size_in; } if (part_nc - full_nc == 3) { ptype block[3][4]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*49 + block[1][0]*7 + block[0][1]*7 + block[1][1] )/(64*256)); assign_pixel(down[r][c+1] , (block[0][1]*35 + block[0][2]*21 + block[1][1]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r][c+2] , (block[0][3]*35 + block[0][2]*21 + block[1][3]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r+1][c] , (block[1][0]*35 + block[1][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+1][c+1] , (block[1][1]*25 + block[1][2]*15 + block[2][1]*15 + block[2][2]*9 )/(64*256)); assign_pixel(down[r+1][c+2] , (block[1][2]*15 + block[1][3]*25 + block[2][2]*9 + block[2][3]*15)/(64*256)); } else if (part_nc - full_nc == 2) { ptype block[3][3]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*49 + block[1][0]*7 + block[0][1]*7 + block[1][1] )/(64*256)); assign_pixel(down[r][c+1] , (block[0][1]*35 + block[0][2]*21 + block[1][1]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r+1][c] , (block[1][0]*35 + block[1][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); assign_pixel(down[r+1][c+1] , (block[1][1]*25 + block[1][2]*15 + block[2][1]*15 + block[2][2]*9 )/(64*256)); } else if (part_nc - full_nc == 1) { ptype block[3][2]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*49 + block[1][0]*7 + block[0][1]*7 + block[1][1] )/(64*256)); assign_pixel(down[r+1][c] , (block[1][0]*35 + block[1][1]*5 + block[2][0]*21 + block[1][1]*3 )/(64*256)); } } else if (part_nr - full_nr == 1) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { ptype block[2][size_in]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*49 + block[1][0]*7 + block[0][1]*7 + block[1][1] )/(64*256)); assign_pixel(down[r][c+1] , (block[0][1]*35 + block[0][2]*21 + block[1][1]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r][c+2] , (block[0][3]*35 + block[0][2]*21 + block[1][3]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r][c+3] , (block[0][4]*49 + block[0][3]*7 + block[1][4]*7 + block[1][3] )/(64*256)); cc += size_in; } if (part_nc - full_nc == 3) { ptype block[2][4]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*49 + block[1][0]*7 + block[0][1]*7 + block[1][1] )/(64*256)); assign_pixel(down[r][c+1] , (block[0][1]*35 + block[0][2]*21 + block[1][1]*5 + block[1][2]*3 )/(64*256)); assign_pixel(down[r][c+2] , (block[0][3]*35 + block[0][2]*21 + block[1][3]*5 + block[1][2]*3 )/(64*256)); } else if (part_nc - full_nc == 2) { ptype block[2][3]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*49 + block[1][0]*7 + block[0][1]*7 + block[1][1] )/(64*256)); assign_pixel(down[r][c+1] , (block[0][1]*35 + block[0][2]*21 + block[1][1]*5 + block[1][2]*3 )/(64*256)); } else if (part_nc - full_nc == 1) { ptype block[2][2]; separable_3x3_filter_block_grayscale(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block assign_pixel(down[r][c] , (block[0][0]*49 + block[1][0]*7 + block[0][1]*7 + block[1][1] )/(64*256)); } } } private: struct rgbptype { uint32 red; uint32 green; uint32 blue; }; public: // ------------------------------------------ // OVERLOAD FOR RGB TO RGB IMAGES // ------------------------------------------ template < typename in_image_type, typename out_image_type > typename enable_if<both_images_rgb<in_image_type,out_image_type> >::type operator() ( const in_image_type& original, out_image_type& down ) const { // make sure requires clause is not broken DLIB_ASSERT(is_same_object(original, down) == false, "\t void pyramid_down_5_4::operator()" << "\n\t is_same_object(original, down): " << is_same_object(original, down) << "\n\t this: " << this ); 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 ); if (original.nr() <= 8 || original.nc() <= 8) { down.clear(); return; } const long size_in = 5; const long size_out = 4; const long full_nr = size_out*((original.nr()-2)/size_in); const long part_nr = (size_out*(original.nr()-2))/size_in; const long full_nc = size_out*((original.nc()-2)/size_in); const long part_nc = (size_out*(original.nc()-2))/size_in; down.set_size(part_nr, part_nc); long rr = 1; long r; for (r = 0; r < full_nr; r+=size_out) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { rgbptype block[size_in][size_in]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate block down[r][c].red = (block[0][0].red*49 + block[1][0].red*7 + block[0][1].red*7 + block[1][1].red )/(64*256); down[r][c].green = (block[0][0].green*49 + block[1][0].green*7 + block[0][1].green*7 + block[1][1].green )/(64*256); down[r][c].blue = (block[0][0].blue*49 + block[1][0].blue*7 + block[0][1].blue*7 + block[1][1].blue )/(64*256); down[r][c+1].red = (block[0][1].red*35 + block[0][2].red*21 + block[1][1].red*5 + block[1][2].red*3 )/(64*256); down[r][c+1].green = (block[0][1].green*35 + block[0][2].green*21 + block[1][1].green*5 + block[1][2].green*3 )/(64*256); down[r][c+1].blue = (block[0][1].blue*35 + block[0][2].blue*21 + block[1][1].blue*5 + block[1][2].blue*3 )/(64*256); down[r][c+2].red = (block[0][3].red*35 + block[0][2].red*21 + block[1][3].red*5 + block[1][2].red*3 )/(64*256); down[r][c+2].green = (block[0][3].green*35 + block[0][2].green*21 + block[1][3].green*5 + block[1][2].green*3 )/(64*256); down[r][c+2].blue = (block[0][3].blue*35 + block[0][2].blue*21 + block[1][3].blue*5 + block[1][2].blue*3 )/(64*256); down[r][c+3].red = (block[0][4].red*49 + block[0][3].red*7 + block[1][4].red*7 + block[1][3].red )/(64*256); down[r][c+3].green = (block[0][4].green*49 + block[0][3].green*7 + block[1][4].green*7 + block[1][3].green )/(64*256); down[r][c+3].blue = (block[0][4].blue*49 + block[0][3].blue*7 + block[1][4].blue*7 + block[1][3].blue )/(64*256); down[r+1][c].red = (block[1][0].red*35 + block[1][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+1][c].green = (block[1][0].green*35 + block[1][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+1][c].blue = (block[1][0].blue*35 + block[1][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+1][c+1].red = (block[1][1].red*25 + block[1][2].red*15 + block[2][1].red*15 + block[2][2].red*9 )/(64*256); down[r+1][c+1].green = (block[1][1].green*25 + block[1][2].green*15 + block[2][1].green*15 + block[2][2].green*9 )/(64*256); down[r+1][c+1].blue = (block[1][1].blue*25 + block[1][2].blue*15 + block[2][1].blue*15 + block[2][2].blue*9 )/(64*256); down[r+1][c+2].red = (block[1][2].red*15 + block[1][3].red*25 + block[2][2].red*9 + block[2][3].red*15 )/(64*256); down[r+1][c+2].green = (block[1][2].green*15 + block[1][3].green*25 + block[2][2].green*9 + block[2][3].green*15)/(64*256); down[r+1][c+2].blue = (block[1][2].blue*15 + block[1][3].blue*25 + block[2][2].blue*9 + block[2][3].blue*15 )/(64*256); down[r+1][c+3].red = (block[1][3].red*5 + block[1][4].red*35 + block[2][3].red*3 + block[2][4].red*21 )/(64*256); down[r+1][c+3].green = (block[1][3].green*5 + block[1][4].green*35 + block[2][3].green*3 + block[2][4].green*21)/(64*256); down[r+1][c+3].blue = (block[1][3].blue*5 + block[1][4].blue*35 + block[2][3].blue*3 + block[2][4].blue*21 )/(64*256); down[r+2][c].red = (block[3][0].red*35 + block[3][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+2][c].green = (block[3][0].green*35 + block[3][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+2][c].blue = (block[3][0].blue*35 + block[3][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+2][c+1].red = (block[3][1].red*25 + block[3][2].red*15 + block[2][1].red*15 + block[2][2].red*9 )/(64*256); down[r+2][c+1].green = (block[3][1].green*25 + block[3][2].green*15 + block[2][1].green*15 + block[2][2].green*9 )/(64*256); down[r+2][c+1].blue = (block[3][1].blue*25 + block[3][2].blue*15 + block[2][1].blue*15 + block[2][2].blue*9 )/(64*256); down[r+2][c+2].red = (block[3][2].red*15 + block[3][3].red*25 + block[2][2].red*9 + block[2][3].red*15 )/(64*256); down[r+2][c+2].green = (block[3][2].green*15 + block[3][3].green*25 + block[2][2].green*9 + block[2][3].green*15)/(64*256); down[r+2][c+2].blue = (block[3][2].blue*15 + block[3][3].blue*25 + block[2][2].blue*9 + block[2][3].blue*15 )/(64*256); down[r+2][c+3].red = (block[3][3].red*5 + block[3][4].red*35 + block[2][3].red*3 + block[2][4].red*21 )/(64*256); down[r+2][c+3].green = (block[3][3].green*5 + block[3][4].green*35 + block[2][3].green*3 + block[2][4].green*21)/(64*256); down[r+2][c+3].blue = (block[3][3].blue*5 + block[3][4].blue*35 + block[2][3].blue*3 + block[2][4].blue*21 )/(64*256); down[r+3][c].red = (block[4][0].red*49 + block[3][0].red*7 + block[4][1].red*7 + block[3][1].red )/(64*256); down[r+3][c].green = (block[4][0].green*49 + block[3][0].green*7 + block[4][1].green*7 + block[3][1].green )/(64*256); down[r+3][c].blue = (block[4][0].blue*49 + block[3][0].blue*7 + block[4][1].blue*7 + block[3][1].blue )/(64*256); down[r+3][c+1].red = (block[4][1].red*35 + block[4][2].red*21 + block[3][1].red*5 + block[3][2].red*3 )/(64*256); down[r+3][c+1].green = (block[4][1].green*35 + block[4][2].green*21 + block[3][1].green*5 + block[3][2].green*3 )/(64*256); down[r+3][c+1].blue = (block[4][1].blue*35 + block[4][2].blue*21 + block[3][1].blue*5 + block[3][2].blue*3 )/(64*256); down[r+3][c+2].red = (block[4][3].red*35 + block[4][2].red*21 + block[3][3].red*5 + block[3][2].red*3 )/(64*256); down[r+3][c+2].green = (block[4][3].green*35 + block[4][2].green*21 + block[3][3].green*5 + block[3][2].green*3 )/(64*256); down[r+3][c+2].blue = (block[4][3].blue*35 + block[4][2].blue*21 + block[3][3].blue*5 + block[3][2].blue*3 )/(64*256); down[r+3][c+3].red = (block[4][4].red*49 + block[4][3].red*7 + block[3][4].red*7 + block[3][3].red )/(64*256); down[r+3][c+3].green = (block[4][4].green*49 + block[4][3].green*7 + block[3][4].green*7 + block[3][3].green )/(64*256); down[r+3][c+3].blue = (block[4][4].blue*49 + block[4][3].blue*7 + block[3][4].blue*7 + block[3][3].blue )/(64*256); cc += size_in; } if (part_nc - full_nc == 3) { rgbptype block[size_in][4]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*49 + block[1][0].red*7 + block[0][1].red*7 + block[1][1].red )/(64*256); down[r][c].green = (block[0][0].green*49 + block[1][0].green*7 + block[0][1].green*7 + block[1][1].green )/(64*256); down[r][c].blue = (block[0][0].blue*49 + block[1][0].blue*7 + block[0][1].blue*7 + block[1][1].blue )/(64*256); down[r][c+1].red = (block[0][1].red*35 + block[0][2].red*21 + block[1][1].red*5 + block[1][2].red*3 )/(64*256); down[r][c+1].green = (block[0][1].green*35 + block[0][2].green*21 + block[1][1].green*5 + block[1][2].green*3 )/(64*256); down[r][c+1].blue = (block[0][1].blue*35 + block[0][2].blue*21 + block[1][1].blue*5 + block[1][2].blue*3 )/(64*256); down[r][c+2].red = (block[0][3].red*35 + block[0][2].red*21 + block[1][3].red*5 + block[1][2].red*3 )/(64*256); down[r][c+2].green = (block[0][3].green*35 + block[0][2].green*21 + block[1][3].green*5 + block[1][2].green*3 )/(64*256); down[r][c+2].blue = (block[0][3].blue*35 + block[0][2].blue*21 + block[1][3].blue*5 + block[1][2].blue*3 )/(64*256); down[r+1][c].red = (block[1][0].red*35 + block[1][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+1][c].green = (block[1][0].green*35 + block[1][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+1][c].blue = (block[1][0].blue*35 + block[1][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+1][c+1].red = (block[1][1].red*25 + block[1][2].red*15 + block[2][1].red*15 + block[2][2].red*9 )/(64*256); down[r+1][c+1].green = (block[1][1].green*25 + block[1][2].green*15 + block[2][1].green*15 + block[2][2].green*9 )/(64*256); down[r+1][c+1].blue = (block[1][1].blue*25 + block[1][2].blue*15 + block[2][1].blue*15 + block[2][2].blue*9 )/(64*256); down[r+1][c+2].red = (block[1][2].red*15 + block[1][3].red*25 + block[2][2].red*9 + block[2][3].red*15 )/(64*256); down[r+1][c+2].green = (block[1][2].green*15 + block[1][3].green*25 + block[2][2].green*9 + block[2][3].green*15)/(64*256); down[r+1][c+2].blue = (block[1][2].blue*15 + block[1][3].blue*25 + block[2][2].blue*9 + block[2][3].blue*15 )/(64*256); down[r+2][c].red = (block[3][0].red*35 + block[3][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+2][c].green = (block[3][0].green*35 + block[3][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+2][c].blue = (block[3][0].blue*35 + block[3][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+2][c+1].red = (block[3][1].red*25 + block[3][2].red*15 + block[2][1].red*15 + block[2][2].red*9 )/(64*256); down[r+2][c+1].green = (block[3][1].green*25 + block[3][2].green*15 + block[2][1].green*15 + block[2][2].green*9 )/(64*256); down[r+2][c+1].blue = (block[3][1].blue*25 + block[3][2].blue*15 + block[2][1].blue*15 + block[2][2].blue*9 )/(64*256); down[r+2][c+2].red = (block[3][2].red*15 + block[3][3].red*25 + block[2][2].red*9 + block[2][3].red*15 )/(64*256); down[r+2][c+2].green = (block[3][2].green*15 + block[3][3].green*25 + block[2][2].green*9 + block[2][3].green*15)/(64*256); down[r+2][c+2].blue = (block[3][2].blue*15 + block[3][3].blue*25 + block[2][2].blue*9 + block[2][3].blue*15 )/(64*256); down[r+3][c].red = (block[4][0].red*49 + block[3][0].red*7 + block[4][1].red*7 + block[3][1].red )/(64*256); down[r+3][c].green = (block[4][0].green*49 + block[3][0].green*7 + block[4][1].green*7 + block[3][1].green )/(64*256); down[r+3][c].blue = (block[4][0].blue*49 + block[3][0].blue*7 + block[4][1].blue*7 + block[3][1].blue )/(64*256); down[r+3][c+1].red = (block[4][1].red*35 + block[4][2].red*21 + block[3][1].red*5 + block[3][2].red*3 )/(64*256); down[r+3][c+1].green = (block[4][1].green*35 + block[4][2].green*21 + block[3][1].green*5 + block[3][2].green*3 )/(64*256); down[r+3][c+1].blue = (block[4][1].blue*35 + block[4][2].blue*21 + block[3][1].blue*5 + block[3][2].blue*3 )/(64*256); down[r+3][c+2].red = (block[4][3].red*35 + block[4][2].red*21 + block[3][3].red*5 + block[3][2].red*3 )/(64*256); down[r+3][c+2].green = (block[4][3].green*35 + block[4][2].green*21 + block[3][3].green*5 + block[3][2].green*3 )/(64*256); down[r+3][c+2].blue = (block[4][3].blue*35 + block[4][2].blue*21 + block[3][3].blue*5 + block[3][2].blue*3 )/(64*256); } else if (part_nc - full_nc == 2) { rgbptype block[size_in][3]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*49 + block[1][0].red*7 + block[0][1].red*7 + block[1][1].red )/(64*256); down[r][c].green = (block[0][0].green*49 + block[1][0].green*7 + block[0][1].green*7 + block[1][1].green )/(64*256); down[r][c].blue = (block[0][0].blue*49 + block[1][0].blue*7 + block[0][1].blue*7 + block[1][1].blue )/(64*256); down[r][c+1].red = (block[0][1].red*35 + block[0][2].red*21 + block[1][1].red*5 + block[1][2].red*3 )/(64*256); down[r][c+1].green = (block[0][1].green*35 + block[0][2].green*21 + block[1][1].green*5 + block[1][2].green*3 )/(64*256); down[r][c+1].blue = (block[0][1].blue*35 + block[0][2].blue*21 + block[1][1].blue*5 + block[1][2].blue*3 )/(64*256); down[r+1][c].red = (block[1][0].red*35 + block[1][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+1][c].green = (block[1][0].green*35 + block[1][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+1][c].blue = (block[1][0].blue*35 + block[1][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+1][c+1].red = (block[1][1].red*25 + block[1][2].red*15 + block[2][1].red*15 + block[2][2].red*9 )/(64*256); down[r+1][c+1].green = (block[1][1].green*25 + block[1][2].green*15 + block[2][1].green*15 + block[2][2].green*9 )/(64*256); down[r+1][c+1].blue = (block[1][1].blue*25 + block[1][2].blue*15 + block[2][1].blue*15 + block[2][2].blue*9 )/(64*256); down[r+2][c].red = (block[3][0].red*35 + block[3][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+2][c].green = (block[3][0].green*35 + block[3][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+2][c].blue = (block[3][0].blue*35 + block[3][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+2][c+1].red = (block[3][1].red*25 + block[3][2].red*15 + block[2][1].red*15 + block[2][2].red*9 )/(64*256); down[r+2][c+1].green = (block[3][1].green*25 + block[3][2].green*15 + block[2][1].green*15 + block[2][2].green*9 )/(64*256); down[r+2][c+1].blue = (block[3][1].blue*25 + block[3][2].blue*15 + block[2][1].blue*15 + block[2][2].blue*9 )/(64*256); down[r+3][c].red = (block[4][0].red*49 + block[3][0].red*7 + block[4][1].red*7 + block[3][1].red )/(64*256); down[r+3][c].green = (block[4][0].green*49 + block[3][0].green*7 + block[4][1].green*7 + block[3][1].green )/(64*256); down[r+3][c].blue = (block[4][0].blue*49 + block[3][0].blue*7 + block[4][1].blue*7 + block[3][1].blue )/(64*256); down[r+3][c+1].red = (block[4][1].red*35 + block[4][2].red*21 + block[3][1].red*5 + block[3][2].red*3 )/(64*256); down[r+3][c+1].green = (block[4][1].green*35 + block[4][2].green*21 + block[3][1].green*5 + block[3][2].green*3 )/(64*256); down[r+3][c+1].blue = (block[4][1].blue*35 + block[4][2].blue*21 + block[3][1].blue*5 + block[3][2].blue*3 )/(64*256); } else if (part_nc - full_nc == 1) { rgbptype block[size_in][2]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*49 + block[1][0].red*7 + block[0][1].red*7 + block[1][1].red )/(64*256); down[r][c].green = (block[0][0].green*49 + block[1][0].green*7 + block[0][1].green*7 + block[1][1].green )/(64*256); down[r][c].blue = (block[0][0].blue*49 + block[1][0].blue*7 + block[0][1].blue*7 + block[1][1].blue )/(64*256); down[r+1][c].red = (block[1][0].red*35 + block[1][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+1][c].green = (block[1][0].green*35 + block[1][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+1][c].blue = (block[1][0].blue*35 + block[1][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+2][c].red = (block[3][0].red*35 + block[3][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+2][c].green = (block[3][0].green*35 + block[3][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+2][c].blue = (block[3][0].blue*35 + block[3][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+3][c].red = (block[4][0].red*49 + block[3][0].red*7 + block[4][1].red*7 + block[3][1].red )/(64*256); down[r+3][c].green = (block[4][0].green*49 + block[3][0].green*7 + block[4][1].green*7 + block[3][1].green )/(64*256); down[r+3][c].blue = (block[4][0].blue*49 + block[3][0].blue*7 + block[4][1].blue*7 + block[3][1].blue )/(64*256); } rr += size_in; } if (part_nr - full_nr == 3) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { rgbptype block[4][size_in]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*49 + block[1][0].red*7 + block[0][1].red*7 + block[1][1].red )/(64*256); down[r][c].green = (block[0][0].green*49 + block[1][0].green*7 + block[0][1].green*7 + block[1][1].green )/(64*256); down[r][c].blue = (block[0][0].blue*49 + block[1][0].blue*7 + block[0][1].blue*7 + block[1][1].blue )/(64*256); down[r][c+1].red = (block[0][1].red*35 + block[0][2].red*21 + block[1][1].red*5 + block[1][2].red*3 )/(64*256); down[r][c+1].green = (block[0][1].green*35 + block[0][2].green*21 + block[1][1].green*5 + block[1][2].green*3 )/(64*256); down[r][c+1].blue = (block[0][1].blue*35 + block[0][2].blue*21 + block[1][1].blue*5 + block[1][2].blue*3 )/(64*256); down[r][c+2].red = (block[0][3].red*35 + block[0][2].red*21 + block[1][3].red*5 + block[1][2].red*3 )/(64*256); down[r][c+2].green = (block[0][3].green*35 + block[0][2].green*21 + block[1][3].green*5 + block[1][2].green*3 )/(64*256); down[r][c+2].blue = (block[0][3].blue*35 + block[0][2].blue*21 + block[1][3].blue*5 + block[1][2].blue*3 )/(64*256); down[r][c+3].red = (block[0][4].red*49 + block[0][3].red*7 + block[1][4].red*7 + block[1][3].red )/(64*256); down[r][c+3].green = (block[0][4].green*49 + block[0][3].green*7 + block[1][4].green*7 + block[1][3].green )/(64*256); down[r][c+3].blue = (block[0][4].blue*49 + block[0][3].blue*7 + block[1][4].blue*7 + block[1][3].blue )/(64*256); down[r+1][c].red = (block[1][0].red*35 + block[1][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+1][c].green = (block[1][0].green*35 + block[1][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+1][c].blue = (block[1][0].blue*35 + block[1][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+1][c+1].red = (block[1][1].red*25 + block[1][2].red*15 + block[2][1].red*15 + block[2][2].red*9 )/(64*256); down[r+1][c+1].green = (block[1][1].green*25 + block[1][2].green*15 + block[2][1].green*15 + block[2][2].green*9 )/(64*256); down[r+1][c+1].blue = (block[1][1].blue*25 + block[1][2].blue*15 + block[2][1].blue*15 + block[2][2].blue*9 )/(64*256); down[r+1][c+2].red = (block[1][2].red*15 + block[1][3].red*25 + block[2][2].red*9 + block[2][3].red*15 )/(64*256); down[r+1][c+2].green = (block[1][2].green*15 + block[1][3].green*25 + block[2][2].green*9 + block[2][3].green*15)/(64*256); down[r+1][c+2].blue = (block[1][2].blue*15 + block[1][3].blue*25 + block[2][2].blue*9 + block[2][3].blue*15 )/(64*256); down[r+1][c+3].red = (block[1][3].red*5 + block[1][4].red*35 + block[2][3].red*3 + block[2][4].red*21 )/(64*256); down[r+1][c+3].green = (block[1][3].green*5 + block[1][4].green*35 + block[2][3].green*3 + block[2][4].green*21)/(64*256); down[r+1][c+3].blue = (block[1][3].blue*5 + block[1][4].blue*35 + block[2][3].blue*3 + block[2][4].blue*21 )/(64*256); down[r+2][c].red = (block[3][0].red*35 + block[3][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+2][c].green = (block[3][0].green*35 + block[3][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+2][c].blue = (block[3][0].blue*35 + block[3][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+2][c+1].red = (block[3][1].red*25 + block[3][2].red*15 + block[2][1].red*15 + block[2][2].red*9 )/(64*256); down[r+2][c+1].green = (block[3][1].green*25 + block[3][2].green*15 + block[2][1].green*15 + block[2][2].green*9 )/(64*256); down[r+2][c+1].blue = (block[3][1].blue*25 + block[3][2].blue*15 + block[2][1].blue*15 + block[2][2].blue*9 )/(64*256); down[r+2][c+2].red = (block[3][2].red*15 + block[3][3].red*25 + block[2][2].red*9 + block[2][3].red*15 )/(64*256); down[r+2][c+2].green = (block[3][2].green*15 + block[3][3].green*25 + block[2][2].green*9 + block[2][3].green*15)/(64*256); down[r+2][c+2].blue = (block[3][2].blue*15 + block[3][3].blue*25 + block[2][2].blue*9 + block[2][3].blue*15 )/(64*256); down[r+2][c+3].red = (block[3][3].red*5 + block[3][4].red*35 + block[2][3].red*3 + block[2][4].red*21 )/(64*256); down[r+2][c+3].green = (block[3][3].green*5 + block[3][4].green*35 + block[2][3].green*3 + block[2][4].green*21)/(64*256); down[r+2][c+3].blue = (block[3][3].blue*5 + block[3][4].blue*35 + block[2][3].blue*3 + block[2][4].blue*21 )/(64*256); cc += size_in; } if (part_nc - full_nc == 3) { rgbptype block[4][4]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*49 + block[1][0].red*7 + block[0][1].red*7 + block[1][1].red )/(64*256); down[r][c].green = (block[0][0].green*49 + block[1][0].green*7 + block[0][1].green*7 + block[1][1].green )/(64*256); down[r][c].blue = (block[0][0].blue*49 + block[1][0].blue*7 + block[0][1].blue*7 + block[1][1].blue )/(64*256); down[r][c+1].red = (block[0][1].red*35 + block[0][2].red*21 + block[1][1].red*5 + block[1][2].red*3 )/(64*256); down[r][c+1].green = (block[0][1].green*35 + block[0][2].green*21 + block[1][1].green*5 + block[1][2].green*3 )/(64*256); down[r][c+1].blue = (block[0][1].blue*35 + block[0][2].blue*21 + block[1][1].blue*5 + block[1][2].blue*3 )/(64*256); down[r][c+2].red = (block[0][3].red*35 + block[0][2].red*21 + block[1][3].red*5 + block[1][2].red*3 )/(64*256); down[r][c+2].green = (block[0][3].green*35 + block[0][2].green*21 + block[1][3].green*5 + block[1][2].green*3 )/(64*256); down[r][c+2].blue = (block[0][3].blue*35 + block[0][2].blue*21 + block[1][3].blue*5 + block[1][2].blue*3 )/(64*256); down[r+1][c].red = (block[1][0].red*35 + block[1][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+1][c].green = (block[1][0].green*35 + block[1][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+1][c].blue = (block[1][0].blue*35 + block[1][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+1][c+1].red = (block[1][1].red*25 + block[1][2].red*15 + block[2][1].red*15 + block[2][2].red*9 )/(64*256); down[r+1][c+1].green = (block[1][1].green*25 + block[1][2].green*15 + block[2][1].green*15 + block[2][2].green*9 )/(64*256); down[r+1][c+1].blue = (block[1][1].blue*25 + block[1][2].blue*15 + block[2][1].blue*15 + block[2][2].blue*9 )/(64*256); down[r+1][c+2].red = (block[1][2].red*15 + block[1][3].red*25 + block[2][2].red*9 + block[2][3].red*15 )/(64*256); down[r+1][c+2].green = (block[1][2].green*15 + block[1][3].green*25 + block[2][2].green*9 + block[2][3].green*15)/(64*256); down[r+1][c+2].blue = (block[1][2].blue*15 + block[1][3].blue*25 + block[2][2].blue*9 + block[2][3].blue*15 )/(64*256); down[r+2][c].red = (block[3][0].red*35 + block[3][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+2][c].green = (block[3][0].green*35 + block[3][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+2][c].blue = (block[3][0].blue*35 + block[3][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+2][c+1].red = (block[3][1].red*25 + block[3][2].red*15 + block[2][1].red*15 + block[2][2].red*9 )/(64*256); down[r+2][c+1].green = (block[3][1].green*25 + block[3][2].green*15 + block[2][1].green*15 + block[2][2].green*9 )/(64*256); down[r+2][c+1].blue = (block[3][1].blue*25 + block[3][2].blue*15 + block[2][1].blue*15 + block[2][2].blue*9 )/(64*256); down[r+2][c+2].red = (block[3][2].red*15 + block[3][3].red*25 + block[2][2].red*9 + block[2][3].red*15 )/(64*256); down[r+2][c+2].green = (block[3][2].green*15 + block[3][3].green*25 + block[2][2].green*9 + block[2][3].green*15)/(64*256); down[r+2][c+2].blue = (block[3][2].blue*15 + block[3][3].blue*25 + block[2][2].blue*9 + block[2][3].blue*15 )/(64*256); } else if (part_nc - full_nc == 2) { rgbptype block[4][3]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*49 + block[1][0].red*7 + block[0][1].red*7 + block[1][1].red )/(64*256); down[r][c].green = (block[0][0].green*49 + block[1][0].green*7 + block[0][1].green*7 + block[1][1].green )/(64*256); down[r][c].blue = (block[0][0].blue*49 + block[1][0].blue*7 + block[0][1].blue*7 + block[1][1].blue )/(64*256); down[r][c+1].red = (block[0][1].red*35 + block[0][2].red*21 + block[1][1].red*5 + block[1][2].red*3 )/(64*256); down[r][c+1].green = (block[0][1].green*35 + block[0][2].green*21 + block[1][1].green*5 + block[1][2].green*3 )/(64*256); down[r][c+1].blue = (block[0][1].blue*35 + block[0][2].blue*21 + block[1][1].blue*5 + block[1][2].blue*3 )/(64*256); down[r+1][c].red = (block[1][0].red*35 + block[1][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+1][c].green = (block[1][0].green*35 + block[1][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+1][c].blue = (block[1][0].blue*35 + block[1][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+1][c+1].red = (block[1][1].red*25 + block[1][2].red*15 + block[2][1].red*15 + block[2][2].red*9 )/(64*256); down[r+1][c+1].green = (block[1][1].green*25 + block[1][2].green*15 + block[2][1].green*15 + block[2][2].green*9 )/(64*256); down[r+1][c+1].blue = (block[1][1].blue*25 + block[1][2].blue*15 + block[2][1].blue*15 + block[2][2].blue*9 )/(64*256); down[r+2][c].red = (block[3][0].red*35 + block[3][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+2][c].green = (block[3][0].green*35 + block[3][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+2][c].blue = (block[3][0].blue*35 + block[3][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+2][c+1].red = (block[3][1].red*25 + block[3][2].red*15 + block[2][1].red*15 + block[2][2].red*9 )/(64*256); down[r+2][c+1].green = (block[3][1].green*25 + block[3][2].green*15 + block[2][1].green*15 + block[2][2].green*9 )/(64*256); down[r+2][c+1].blue = (block[3][1].blue*25 + block[3][2].blue*15 + block[2][1].blue*15 + block[2][2].blue*9 )/(64*256); } else if (part_nc - full_nc == 1) { rgbptype block[4][2]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*49 + block[1][0].red*7 + block[0][1].red*7 + block[1][1].red )/(64*256); down[r][c].green = (block[0][0].green*49 + block[1][0].green*7 + block[0][1].green*7 + block[1][1].green )/(64*256); down[r][c].blue = (block[0][0].blue*49 + block[1][0].blue*7 + block[0][1].blue*7 + block[1][1].blue )/(64*256); down[r+1][c].red = (block[1][0].red*35 + block[1][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+1][c].green = (block[1][0].green*35 + block[1][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+1][c].blue = (block[1][0].blue*35 + block[1][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+2][c].red = (block[3][0].red*35 + block[3][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+2][c].green = (block[3][0].green*35 + block[3][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+2][c].blue = (block[3][0].blue*35 + block[3][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); } } else if (part_nr - full_nr == 2) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { rgbptype block[3][size_in]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*49 + block[1][0].red*7 + block[0][1].red*7 + block[1][1].red )/(64*256); down[r][c].green = (block[0][0].green*49 + block[1][0].green*7 + block[0][1].green*7 + block[1][1].green )/(64*256); down[r][c].blue = (block[0][0].blue*49 + block[1][0].blue*7 + block[0][1].blue*7 + block[1][1].blue )/(64*256); down[r][c+1].red = (block[0][1].red*35 + block[0][2].red*21 + block[1][1].red*5 + block[1][2].red*3 )/(64*256); down[r][c+1].green = (block[0][1].green*35 + block[0][2].green*21 + block[1][1].green*5 + block[1][2].green*3 )/(64*256); down[r][c+1].blue = (block[0][1].blue*35 + block[0][2].blue*21 + block[1][1].blue*5 + block[1][2].blue*3 )/(64*256); down[r][c+2].red = (block[0][3].red*35 + block[0][2].red*21 + block[1][3].red*5 + block[1][2].red*3 )/(64*256); down[r][c+2].green = (block[0][3].green*35 + block[0][2].green*21 + block[1][3].green*5 + block[1][2].green*3 )/(64*256); down[r][c+2].blue = (block[0][3].blue*35 + block[0][2].blue*21 + block[1][3].blue*5 + block[1][2].blue*3 )/(64*256); down[r][c+3].red = (block[0][4].red*49 + block[0][3].red*7 + block[1][4].red*7 + block[1][3].red )/(64*256); down[r][c+3].green = (block[0][4].green*49 + block[0][3].green*7 + block[1][4].green*7 + block[1][3].green )/(64*256); down[r][c+3].blue = (block[0][4].blue*49 + block[0][3].blue*7 + block[1][4].blue*7 + block[1][3].blue )/(64*256); down[r+1][c].red = (block[1][0].red*35 + block[1][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+1][c].green = (block[1][0].green*35 + block[1][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+1][c].blue = (block[1][0].blue*35 + block[1][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+1][c+1].red = (block[1][1].red*25 + block[1][2].red*15 + block[2][1].red*15 + block[2][2].red*9 )/(64*256); down[r+1][c+1].green = (block[1][1].green*25 + block[1][2].green*15 + block[2][1].green*15 + block[2][2].green*9 )/(64*256); down[r+1][c+1].blue = (block[1][1].blue*25 + block[1][2].blue*15 + block[2][1].blue*15 + block[2][2].blue*9 )/(64*256); down[r+1][c+2].red = (block[1][2].red*15 + block[1][3].red*25 + block[2][2].red*9 + block[2][3].red*15 )/(64*256); down[r+1][c+2].green = (block[1][2].green*15 + block[1][3].green*25 + block[2][2].green*9 + block[2][3].green*15)/(64*256); down[r+1][c+2].blue = (block[1][2].blue*15 + block[1][3].blue*25 + block[2][2].blue*9 + block[2][3].blue*15 )/(64*256); down[r+1][c+3].red = (block[1][3].red*5 + block[1][4].red*35 + block[2][3].red*3 + block[2][4].red*21 )/(64*256); down[r+1][c+3].green = (block[1][3].green*5 + block[1][4].green*35 + block[2][3].green*3 + block[2][4].green*21)/(64*256); down[r+1][c+3].blue = (block[1][3].blue*5 + block[1][4].blue*35 + block[2][3].blue*3 + block[2][4].blue*21 )/(64*256); cc += size_in; } if (part_nc - full_nc == 3) { rgbptype block[3][4]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*49 + block[1][0].red*7 + block[0][1].red*7 + block[1][1].red )/(64*256); down[r][c].green = (block[0][0].green*49 + block[1][0].green*7 + block[0][1].green*7 + block[1][1].green )/(64*256); down[r][c].blue = (block[0][0].blue*49 + block[1][0].blue*7 + block[0][1].blue*7 + block[1][1].blue )/(64*256); down[r][c+1].red = (block[0][1].red*35 + block[0][2].red*21 + block[1][1].red*5 + block[1][2].red*3 )/(64*256); down[r][c+1].green = (block[0][1].green*35 + block[0][2].green*21 + block[1][1].green*5 + block[1][2].green*3 )/(64*256); down[r][c+1].blue = (block[0][1].blue*35 + block[0][2].blue*21 + block[1][1].blue*5 + block[1][2].blue*3 )/(64*256); down[r][c+2].red = (block[0][3].red*35 + block[0][2].red*21 + block[1][3].red*5 + block[1][2].red*3 )/(64*256); down[r][c+2].green = (block[0][3].green*35 + block[0][2].green*21 + block[1][3].green*5 + block[1][2].green*3 )/(64*256); down[r][c+2].blue = (block[0][3].blue*35 + block[0][2].blue*21 + block[1][3].blue*5 + block[1][2].blue*3 )/(64*256); down[r+1][c].red = (block[1][0].red*35 + block[1][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+1][c].green = (block[1][0].green*35 + block[1][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+1][c].blue = (block[1][0].blue*35 + block[1][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+1][c+1].red = (block[1][1].red*25 + block[1][2].red*15 + block[2][1].red*15 + block[2][2].red*9 )/(64*256); down[r+1][c+1].green = (block[1][1].green*25 + block[1][2].green*15 + block[2][1].green*15 + block[2][2].green*9 )/(64*256); down[r+1][c+1].blue = (block[1][1].blue*25 + block[1][2].blue*15 + block[2][1].blue*15 + block[2][2].blue*9 )/(64*256); down[r+1][c+2].red = (block[1][2].red*15 + block[1][3].red*25 + block[2][2].red*9 + block[2][3].red*15 )/(64*256); down[r+1][c+2].green = (block[1][2].green*15 + block[1][3].green*25 + block[2][2].green*9 + block[2][3].green*15)/(64*256); down[r+1][c+2].blue = (block[1][2].blue*15 + block[1][3].blue*25 + block[2][2].blue*9 + block[2][3].blue*15 )/(64*256); } else if (part_nc - full_nc == 2) { rgbptype block[3][3]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*49 + block[1][0].red*7 + block[0][1].red*7 + block[1][1].red )/(64*256); down[r][c].green = (block[0][0].green*49 + block[1][0].green*7 + block[0][1].green*7 + block[1][1].green )/(64*256); down[r][c].blue = (block[0][0].blue*49 + block[1][0].blue*7 + block[0][1].blue*7 + block[1][1].blue )/(64*256); down[r][c+1].red = (block[0][1].red*35 + block[0][2].red*21 + block[1][1].red*5 + block[1][2].red*3 )/(64*256); down[r][c+1].green = (block[0][1].green*35 + block[0][2].green*21 + block[1][1].green*5 + block[1][2].green*3 )/(64*256); down[r][c+1].blue = (block[0][1].blue*35 + block[0][2].blue*21 + block[1][1].blue*5 + block[1][2].blue*3 )/(64*256); down[r+1][c].red = (block[1][0].red*35 + block[1][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+1][c].green = (block[1][0].green*35 + block[1][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+1][c].blue = (block[1][0].blue*35 + block[1][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); down[r+1][c+1].red = (block[1][1].red*25 + block[1][2].red*15 + block[2][1].red*15 + block[2][2].red*9 )/(64*256); down[r+1][c+1].green = (block[1][1].green*25 + block[1][2].green*15 + block[2][1].green*15 + block[2][2].green*9 )/(64*256); down[r+1][c+1].blue = (block[1][1].blue*25 + block[1][2].blue*15 + block[2][1].blue*15 + block[2][2].blue*9 )/(64*256); } else if (part_nc - full_nc == 1) { rgbptype block[3][2]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*49 + block[1][0].red*7 + block[0][1].red*7 + block[1][1].red )/(64*256); down[r][c].green = (block[0][0].green*49 + block[1][0].green*7 + block[0][1].green*7 + block[1][1].green )/(64*256); down[r][c].blue = (block[0][0].blue*49 + block[1][0].blue*7 + block[0][1].blue*7 + block[1][1].blue )/(64*256); down[r+1][c].red = (block[1][0].red*35 + block[1][1].red*5 + block[2][0].red*21 + block[1][1].red*3 )/(64*256); down[r+1][c].green = (block[1][0].green*35 + block[1][1].green*5 + block[2][0].green*21 + block[1][1].green*3 )/(64*256); down[r+1][c].blue = (block[1][0].blue*35 + block[1][1].blue*5 + block[2][0].blue*21 + block[1][1].blue*3 )/(64*256); } } else if (part_nr - full_nr == 1) { long cc = 1; long c; for (c = 0; c < full_nc; c+=size_out) { rgbptype block[2][size_in]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*49 + block[1][0].red*7 + block[0][1].red*7 + block[1][1].red )/(64*256); down[r][c].green = (block[0][0].green*49 + block[1][0].green*7 + block[0][1].green*7 + block[1][1].green )/(64*256); down[r][c].blue = (block[0][0].blue*49 + block[1][0].blue*7 + block[0][1].blue*7 + block[1][1].blue )/(64*256); down[r][c+1].red = (block[0][1].red*35 + block[0][2].red*21 + block[1][1].red*5 + block[1][2].red*3 )/(64*256); down[r][c+1].green = (block[0][1].green*35 + block[0][2].green*21 + block[1][1].green*5 + block[1][2].green*3 )/(64*256); down[r][c+1].blue = (block[0][1].blue*35 + block[0][2].blue*21 + block[1][1].blue*5 + block[1][2].blue*3 )/(64*256); down[r][c+2].red = (block[0][3].red*35 + block[0][2].red*21 + block[1][3].red*5 + block[1][2].red*3 )/(64*256); down[r][c+2].green = (block[0][3].green*35 + block[0][2].green*21 + block[1][3].green*5 + block[1][2].green*3 )/(64*256); down[r][c+2].blue = (block[0][3].blue*35 + block[0][2].blue*21 + block[1][3].blue*5 + block[1][2].blue*3 )/(64*256); down[r][c+3].red = (block[0][4].red*49 + block[0][3].red*7 + block[1][4].red*7 + block[1][3].red )/(64*256); down[r][c+3].green = (block[0][4].green*49 + block[0][3].green*7 + block[1][4].green*7 + block[1][3].green )/(64*256); down[r][c+3].blue = (block[0][4].blue*49 + block[0][3].blue*7 + block[1][4].blue*7 + block[1][3].blue )/(64*256); cc += size_in; } if (part_nc - full_nc == 3) { rgbptype block[2][4]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*49 + block[1][0].red*7 + block[0][1].red*7 + block[1][1].red )/(64*256); down[r][c].green = (block[0][0].green*49 + block[1][0].green*7 + block[0][1].green*7 + block[1][1].green )/(64*256); down[r][c].blue = (block[0][0].blue*49 + block[1][0].blue*7 + block[0][1].blue*7 + block[1][1].blue )/(64*256); down[r][c+1].red = (block[0][1].red*35 + block[0][2].red*21 + block[1][1].red*5 + block[1][2].red*3 )/(64*256); down[r][c+1].green = (block[0][1].green*35 + block[0][2].green*21 + block[1][1].green*5 + block[1][2].green*3 )/(64*256); down[r][c+1].blue = (block[0][1].blue*35 + block[0][2].blue*21 + block[1][1].blue*5 + block[1][2].blue*3 )/(64*256); down[r][c+2].red = (block[0][3].red*35 + block[0][2].red*21 + block[1][3].red*5 + block[1][2].red*3 )/(64*256); down[r][c+2].green = (block[0][3].green*35 + block[0][2].green*21 + block[1][3].green*5 + block[1][2].green*3 )/(64*256); down[r][c+2].blue = (block[0][3].blue*35 + block[0][2].blue*21 + block[1][3].blue*5 + block[1][2].blue*3 )/(64*256); } else if (part_nc - full_nc == 2) { rgbptype block[2][3]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*49 + block[1][0].red*7 + block[0][1].red*7 + block[1][1].red )/(64*256); down[r][c].green = (block[0][0].green*49 + block[1][0].green*7 + block[0][1].green*7 + block[1][1].green )/(64*256); down[r][c].blue = (block[0][0].blue*49 + block[1][0].blue*7 + block[0][1].blue*7 + block[1][1].blue )/(64*256); down[r][c+1].red = (block[0][1].red*35 + block[0][2].red*21 + block[1][1].red*5 + block[1][2].red*3 )/(64*256); down[r][c+1].green = (block[0][1].green*35 + block[0][2].green*21 + block[1][1].green*5 + block[1][2].green*3 )/(64*256); down[r][c+1].blue = (block[0][1].blue*35 + block[0][2].blue*21 + block[1][1].blue*5 + block[1][2].blue*3 )/(64*256); } else if (part_nc - full_nc == 1) { rgbptype block[2][2]; separable_3x3_filter_block_rgb(block, original, rr, cc, 3, 10, 3); // bi-linearly interpolate partial block down[r][c].red = (block[0][0].red*49 + block[1][0].red*7 + block[0][1].red*7 + block[1][1].red )/(64*256); down[r][c].green = (block[0][0].green*49 + block[1][0].green*7 + block[0][1].green*7 + block[1][1].green )/(64*256); down[r][c].blue = (block[0][0].blue*49 + block[1][0].blue*7 + block[0][1].blue*7 + block[1][1].blue )/(64*256); } } } private: }; // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- } #endif // DLIB_IMAGE_PYRaMID_H__