/*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // // By downloading, copying, installing or using the software you agree to this license. // If you do not agree to this license, do not download, install, // copy or use the software. // // // Intel License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000, Intel Corporation, all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of Intel Corporation may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, // indirect, incidental, special, exemplary, or consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. // //M*/ #include "_cv.h" /****************************************************************************************\ Down-sampling pyramids core functions \****************************************************************************************/ //////////// Filtering macros ///////////// /* COMMON CASE */ /* 1/16[1 4 6 4 1] */ /* ...| x0 | x1 | x2 | x3 | x4 |... */ #define PD_FILTER( x0, x1, x2, x3, x4 ) ((x2)*6+((x1)+(x3))*4+(x0)+(x4)) /* MACROS FOR BORDERS */ /* | b I a | b | reflection used ("I" denotes the image boundary) */ /* LEFT/TOP */ /* 1/16[1 4 6 4 1] */ /* | x2 | x1 I x0 | x1 | x2 |... */ #define PD_LT(x0,x1,x2) ((x0)*6 + (x1)*8 + (x2)*2) /* RIGHT/BOTTOM */ /* 1/16[1 4 6 4 1] */ /* ...| x0 | x1 | x2 | x3 I x2 | */ #define PD_RB(x0,x1,x2,x3) ((x0) + ((x1) + (x3))*4 + (x2)*7) /* SINGULAR CASE ( width == 2 || height == 2 ) */ /* 1/16[1 4 6 4 1] */ /* | x0 | x1 I x0 | x1 I x0 | */ #define PD_SINGULAR(x0,x1) (((x0) + (x1))*8) #define PD_SCALE_INT(x) (((x) + (1<<7)) >> 8) #define PD_SCALE_FLT(x) ((x)*0.00390625f) #define PD_SZ 5 ////////// generic macro //////////// #define ICV_DEF_PYR_DOWN_FUNC( flavor, type, worktype, _pd_scale_ ) \ static CvStatus CV_STDCALL \ icvPyrDownG5x5_##flavor##_CnR( const type* src, int srcstep, type* dst, \ int dststep, CvSize size, void *buf, int Cs ) \ { \ worktype* buffer = (worktype*)buf; /* pointer to temporary buffer */ \ worktype* rows[PD_SZ]; /* array of rows pointers. dim(rows) is PD_SZ */ \ int y, top_row = 0; \ int Wd = size.width/2, Wdn = Wd*Cs; \ int buffer_step = Wdn; \ int pd_sz = (PD_SZ + 1)*buffer_step; \ int fst = 0, lst = size.height <= PD_SZ/2 ? size.height : PD_SZ/2 + 1; \ \ assert( Cs == 1 || Cs == 3 ); \ srcstep /= sizeof(src[0]); dststep /= sizeof(dst[0]); \ \ /* main loop */ \ for( y = 0; y < size.height; y += 2, dst += dststep ) \ { \ /* set first and last indices of buffer rows which are need to be filled */ \ int x, y1, k = top_row; \ int x1 = buffer_step; \ worktype *row01, *row23, *row4; \ \ /* assign rows pointers */ \ for( y1 = 0; y1 < PD_SZ; y1++ ) \ { \ rows[y1] = buffer + k; \ k += buffer_step; \ k &= k < pd_sz ? -1 : 0; \ } \ \ row01 = rows[0]; \ row23 = rows[2]; \ row4 = rows[4]; \ \ /* fill new buffer rows with filtered source (horizontal conv) */ \ if( Cs == 1 ) \ { \ if( size.width > PD_SZ/2 ) \ for( y1 = fst; y1 < lst; y1++, src += srcstep ) \ { \ worktype *row = rows[y1]; \ \ /* process left & right bounds */ \ row[0] = PD_LT( src[0], src[1], src[2] ); \ row[Wd-1] = PD_RB( src[Wd*2-4], src[Wd*2-3], \ src[Wd*2-2], src[Wd*2-1]); \ /* other points (even) */ \ for( x = 1; x < Wd - 1; x++ ) \ { \ row[x] = PD_FILTER( src[2*x-2], src[2*x-1], src[2*x], \ src[2*x+1], src[2*x+2] ); \ } \ } \ else \ for( y1 = fst; y1 < lst; y1++, src += srcstep ) \ { \ rows[y1][0] = PD_SINGULAR( src[0], src[1] ); \ } \ } \ else /* Cs == 3 */ \ { \ for( y1 = fst; y1 < lst; y1++, src += srcstep ) \ { \ worktype *row = rows[y1]; \ \ if( size.width > PD_SZ/2 ) \ { \ int c; \ for( c = 0; c < 3; c++ ) \ { \ /* process left & right bounds */ \ row[c] = PD_LT( src[c], src[3+c], src[6+c] ); \ row[Wdn-3+c] = PD_RB( src[Wdn*2-12+c], src[Wdn*2-9+c], \ src[Wdn*2-6+c], src[Wdn*2-3+c] ); \ } \ /* other points (even) */ \ for( x = 3; x < Wdn - 3; x += 3 ) \ { \ row[x] = PD_FILTER( src[2*x-6], src[2*x-3], src[2*x], \ src[2*x+3], src[2*x+6] ); \ row[x+1] = PD_FILTER( src[2*x-5], src[2*x-2], src[2*x+1], \ src[2*x+4], src[2*x+7] ); \ row[x+2] = PD_FILTER( src[2*x-4], src[2*x-1], src[2*x+2], \ src[2*x+5], src[2*x+8] ); \ } \ } \ else /* size.width <= PD_SZ/2 */ \ { \ row[0] = PD_SINGULAR( src[0], src[3] ); \ row[1] = PD_SINGULAR( src[1], src[4] ); \ row[2] = PD_SINGULAR( src[2], src[5] ); \ } \ } \ } \ \ /* second pass. Do vertical conv and write results do destination image */ \ if( y > 0 ) \ { \ if( y < size.height - PD_SZ/2 ) \ { \ for( x = 0; x < Wdn; x++, x1++ ) \ { \ dst[x] = (type)_pd_scale_( PD_FILTER( row01[x], row01[x1], \ row23[x], row23[x1], row4[x] )); \ } \ top_row += 2*buffer_step; \ top_row &= top_row < pd_sz ? -1 : 0; \ } \ else /* bottom */ \ for( x = 0; x < Wdn; x++, x1++ ) \ dst[x] = (type)_pd_scale_( PD_RB( row01[x], row01[x1], \ row23[x], row23[x1])); \ } \ else \ { \ if( size.height > PD_SZ/2 ) /* top */ \ { \ for( x = 0; x < Wdn; x++, x1++ ) \ dst[x] = (type)_pd_scale_( PD_LT( row01[x], row01[x1], row23[x] )); \ } \ else /* size.height <= PD_SZ/2 */ \ { \ for( x = 0; x < Wdn; x++, x1++ ) \ dst[x] = (type)_pd_scale_( PD_SINGULAR( row01[x], row01[x1] )); \ } \ fst = PD_SZ - 2; \ } \ \ lst = y + 2 + PD_SZ/2 < size.height ? PD_SZ : size.height - y; \ } \ \ return CV_OK; \ } ICV_DEF_PYR_DOWN_FUNC( 8u, uchar, int, PD_SCALE_INT ) ICV_DEF_PYR_DOWN_FUNC( 16s, short, int, PD_SCALE_INT ) ICV_DEF_PYR_DOWN_FUNC( 16u, ushort, int, PD_SCALE_INT ) ICV_DEF_PYR_DOWN_FUNC( 32f, float, float, PD_SCALE_FLT ) ICV_DEF_PYR_DOWN_FUNC( 64f, double, double, PD_SCALE_FLT ) /****************************************************************************************\ Up-sampling pyramids core functions \****************************************************************************************/ /////////// filtering macros ////////////// /* COMMON CASE: NON ZERO */ /* 1/16[1 4 6 4 1] */ /* ...| x0 | 0 | x1 | 0 | x2 |... */ #define PU_FILTER( x0, x1, x2 ) ((x1)*6 + (x0) + (x2)) /* ZERO POINT AT CENTER */ /* 1/16[1 4 6 4 1] */ /* ...| 0 | x0 | 0 | x1 | 0 |... */ #define PU_FILTER_ZI( x0, x1 ) (((x0) + (x1))*4) /* MACROS FOR BORDERS */ /* | b I a | b | reflection */ /* LEFT/TOP */ /* 1/16[1 4 6 4 1] */ /* | x1 | 0 I x0 | 0 | x1 |... */ #define PU_LT( x0, x1 ) ((x0)*6 + (x1)*2) /* 1/16[1 4 6 4 1] */ /* | 0 I x0 | 0 | x1 | 0 |... */ #define PU_LT_ZI( x0, x1 ) PU_FILTER_ZI((x0),(x1)) /* RIGHT/BOTTOM: NON ZERO */ /* 1/16[1 4 6 4 1] */ /* ...| x0 | 0 | x1 | 0 I x1 | */ #define PU_RB( x0, x1 ) ((x0) + (x1)*7) /* RIGHT/BOTTOM: ZERO POINT AT CENTER */ /* 1/16[1 4 6 4 1] */ /* ...| 0 | x0 | 0 I x0 | 0 | */ #define PU_RB_ZI( x0 ) ((x0)*8) /* SINGULAR CASE */ /* 1/16[1 4 6 4 1] */ /* | x0 | 0 I x0 | 0 I x0 | */ #define PU_SINGULAR( x0 ) PU_RB_ZI((x0)) /* <--| the same formulas */ #define PU_SINGULAR_ZI( x0 ) PU_RB_ZI((x0)) /* <--| */ /* x/64 - scaling in up-sampling functions */ #define PU_SCALE_INT(x) (((x) + (1<<5)) >> 6) #define PU_SCALE_FLT(x) ((x)*0.015625f) #define PU_SZ 3 //////////// generic macro ///////////// #define ICV_DEF_PYR_UP_FUNC( flavor, type, worktype, _pu_scale_ ) \ static CvStatus CV_STDCALL \ icvPyrUpG5x5_##flavor##_CnR( const type* src, int srcstep, type* dst, \ int dststep, CvSize size, void *buf, int Cs ) \ { \ worktype *buffer = (worktype*)buf; \ worktype *rows[PU_SZ]; \ int y, top_row = 0; \ int Wd = size.width * 2, Wdn = Wd * Cs, Wn = size.width * Cs; \ int buffer_step = Wdn; \ int pu_sz = PU_SZ*buffer_step; \ int fst = 0, lst = size.height <= PU_SZ/2 ? size.height : PU_SZ/2 + 1; \ \ assert( Cs == 1 || Cs == 3 ); \ srcstep /= sizeof(src[0]); dststep /= sizeof(dst[0]); \ \ /* main loop */ \ for( y = 0; y < size.height; y++, dst += 2 * dststep ) \ { \ int x, y1, k = top_row; \ worktype *row0, *row1, *row2; \ type *dst1; \ \ /* assign rows pointers */ \ for( y1 = 0; y1 < PU_SZ; y1++ ) \ { \ rows[y1] = buffer + k; \ k += buffer_step; \ k &= k < pu_sz ? -1 : 0; \ } \ \ row0 = rows[0]; \ row1 = rows[1]; \ row2 = rows[2]; \ dst1 = dst + dststep; \ \ /* fill new buffer rows with filtered source (horizontal conv) */ \ if( Cs == 1 ) \ if( size.width > PU_SZ / 2 ) \ for( y1 = fst; y1 < lst; y1++, src += srcstep ) \ { \ worktype *row = rows[y1]; \ \ /* process left & right bounds */ \ row[0] = PU_LT( src[0], src[1] ); \ row[1] = PU_LT_ZI( src[0], src[1] ); \ row[size.width * 2 - 2] = PU_RB( src[size.width - 2], \ src[size.width - 1] ); \ row[size.width * 2 - 1] = PU_RB_ZI( src[size.width - 1] ); \ /* other points */ \ for( x = 1; x < size.width - 1; x++ ) \ { \ row[2 * x] = PU_FILTER( src[x - 1], src[x], src[x + 1] ); \ row[2 * x + 1] = PU_FILTER_ZI( src[x], src[x + 1] ); \ } \ } \ else /* size.width <= PU_SZ/2 */ \ for( y1 = fst; y1 < lst; y1++, src += srcstep ) \ { \ worktype *row = rows[y1]; \ worktype val = src[0]; \ \ row[0] = PU_SINGULAR( val ); \ row[1] = PU_SINGULAR_ZI( val ); \ } \ else /* Cs == 3 */ \ for( y1 = fst; y1 < lst; y1++, src += srcstep ) \ { \ worktype *row = rows[y1]; \ \ if( size.width > PU_SZ / 2 ) \ { \ int c; \ \ for( c = 0; c < 3; c++ ) \ { \ /* process left & right bounds */ \ row[c] = PU_LT( src[c], src[3 + c] ); \ row[3 + c] = PU_LT_ZI( src[c], src[3 + c] ); \ row[Wn * 2 - 6 + c] = PU_RB( src[Wn - 6 + c], src[Wn - 3 + c]); \ row[Wn * 2 - 3 + c] = PU_RB_ZI( src[Wn - 3 + c] ); \ } \ /* other points */ \ for( x = 3; x < Wn - 3; x += 3 ) \ { \ row[2 * x] = PU_FILTER( src[x - 3], src[x], src[x + 3] ); \ row[2 * x + 3] = PU_FILTER_ZI( src[x], src[x + 3] ); \ \ row[2 * x + 1] = PU_FILTER( src[x - 2], src[x + 1], src[x + 4]);\ row[2 * x + 4] = PU_FILTER_ZI( src[x + 1], src[x + 4] ); \ \ row[2 * x + 2] = PU_FILTER( src[x - 1], src[x + 2], src[x + 5]);\ row[2 * x + 5] = PU_FILTER_ZI( src[x + 2], src[x + 5] ); \ } \ } \ else /* size.width <= PU_SZ/2 */ \ { \ int c; \ \ for( c = 0; c < 3; c++ ) \ { \ row[c] = PU_SINGULAR( src[c] ); \ row[3 + c] = PU_SINGULAR_ZI( src[c] ); \ } \ } \ } \ \ /* second pass. Do vertical conv and write results do destination image */ \ if( y > 0 ) \ { \ if( y < size.height - PU_SZ / 2 ) \ { \ for( x = 0; x < Wdn; x++ ) \ { \ dst[x] = (type)_pu_scale_( PU_FILTER( row0[x], row1[x], row2[x] )); \ dst1[x] = (type)_pu_scale_( PU_FILTER_ZI( row1[x], row2[x] )); \ } \ top_row += buffer_step; \ top_row &= top_row < pu_sz ? -1 : 0; \ } \ else /* bottom */ \ for( x = 0; x < Wdn; x++ ) \ { \ dst[x] = (type)_pu_scale_( PU_RB( row0[x], row1[x] )); \ dst1[x] = (type)_pu_scale_( PU_RB_ZI( row1[x] )); \ } \ } \ else \ { \ if( size.height > PU_SZ / 2 ) /* top */ \ for( x = 0; x < Wdn; x++ ) \ { \ dst[x] = (type)_pu_scale_( PU_LT( row0[x], row1[x] )); \ dst1[x] = (type)_pu_scale_( PU_LT_ZI( row0[x], row1[x] )); \ } \ else /* size.height <= PU_SZ/2 */ \ for( x = 0; x < Wdn; x++ ) \ { \ dst[x] = (type)_pu_scale_( PU_SINGULAR( row0[x] )); \ dst1[x] = (type)_pu_scale_( PU_SINGULAR_ZI( row0[x] )); \ } \ fst = PU_SZ - 1; \ } \ \ lst = y < size.height - PU_SZ/2 - 1 ? PU_SZ : size.height + PU_SZ/2 - y - 1; \ } \ \ return CV_OK; \ } ICV_DEF_PYR_UP_FUNC( 8u, uchar, int, PU_SCALE_INT ) ICV_DEF_PYR_UP_FUNC( 16s, short, int, PU_SCALE_INT ) ICV_DEF_PYR_UP_FUNC( 16u, ushort, int, PU_SCALE_INT ) ICV_DEF_PYR_UP_FUNC( 32f, float, float, PU_SCALE_FLT ) ICV_DEF_PYR_UP_FUNC( 64f, double, double, PU_SCALE_FLT ) static CvStatus CV_STDCALL icvPyrUpG5x5_GetBufSize( int roiWidth, CvDataType dataType, int channels, int *bufSize ) { int bufStep; if( !bufSize ) return CV_NULLPTR_ERR; *bufSize = 0; if( roiWidth < 0 ) return CV_BADSIZE_ERR; if( channels != 1 && channels != 3 ) return CV_UNSUPPORTED_CHANNELS_ERR; bufStep = 2*roiWidth*channels; if( dataType == cv64f ) bufStep *= sizeof(double); else bufStep *= sizeof(int); *bufSize = bufStep * PU_SZ; return CV_OK; } static CvStatus CV_STDCALL icvPyrDownG5x5_GetBufSize( int roiWidth, CvDataType dataType, int channels, int *bufSize ) { int bufStep; if( !bufSize ) return CV_NULLPTR_ERR; *bufSize = 0; if( roiWidth < 0 || (roiWidth & 1) != 0 ) return CV_BADSIZE_ERR; if( channels != 1 && channels != 3 ) return CV_UNSUPPORTED_CHANNELS_ERR; bufStep = 2*roiWidth*channels; if( dataType == cv64f ) bufStep *= sizeof(double); else bufStep *= sizeof(int); *bufSize = bufStep * (PD_SZ + 1); return CV_OK; } /****************************************************************************************\ Downsampled image border completion \****************************************************************************************/ #define ICV_DEF_PYR_BORDER_FUNC( flavor, arrtype, worktype, _pd_scale_ ) \ static CvStatus CV_STDCALL \ icvPyrDownBorder_##flavor##_CnR( const arrtype *src, int src_step, CvSize src_size, \ arrtype *dst, int dst_step, CvSize dst_size, int channels ) \ { \ int local_alloc = 0; \ worktype *buf = 0, *buf0 = 0; \ const arrtype* src2; \ arrtype* dst2; \ int buf_size; \ int i, j; \ int W = src_size.width, H = src_size.height; \ int Wd = dst_size.width, Hd = dst_size.height; \ int Wd_, Hd_; \ int Wn = W*channels; \ int bufW; \ int cols, rows; /* columns and rows to modify */ \ \ assert( channels == 1 || channels == 3 ); \ \ buf_size = MAX(src_size.width,src_size.height) * sizeof(buf[0]) * 2 * channels; \ if( buf_size > (1 << 14) ) \ { \ buf = (worktype*)cvAlloc( buf_size ); \ if( !buf ) \ return CV_OUTOFMEM_ERR; \ } \ else \ { \ buf = (worktype*)cvAlignPtr(alloca( buf_size+8 ), 8); \ local_alloc = 1; \ } \ \ buf0 = buf; \ \ src_step /= sizeof(src[0]); \ dst_step /= sizeof(dst[0]); \ \ cols = (W & 1) + (Wd*2 > W); \ rows = (H & 1) + (Hd*2 > H); \ \ src2 = src + (H-1)*src_step; \ dst2 = dst + (Hd - rows)*dst_step; \ src += (W - 1)*channels; \ dst += (Wd - cols)*channels; \ \ /* part of row(column) from 1 to Wd_(Hd_) is processed using PD_FILTER macro */ \ Wd_ = Wd - 1 + (cols == 1 && (W & 1) != 0); \ Hd_ = Hd - 1 + (rows == 1 && (H & 1) != 0); \ \ bufW = channels * cols; \ \ /******************* STAGE 1. ******************/ \ \ /* do horizontal convolution of the 1-2 right columns and write results to buffer */\ if( cols > 0 ) \ { \ if( W <= 2 ) \ { \ assert( Wd == 1 ); \ for( i = 0; i < H; i++, src += src_step, buf += channels ) \ { \ if( channels == 1 ) \ buf[0] = PD_SINGULAR( src[1-Wn], src[0] ); \ else \ { \ buf[0] = PD_SINGULAR( src[3-Wn], src[0] ); \ buf[1] = PD_SINGULAR( src[4-Wn], src[1] ); \ buf[2] = PD_SINGULAR( src[5-Wn], src[2] ); \ } \ } \ } \ else if( (W == 3 && Wd == 1) || (W > 3 && !(Wd & 1)) ) \ { \ for( i = 0; i < H; i++, src += src_step, buf += channels ) \ { \ if( channels == 1 ) \ buf[0] = PD_LT( src[-2], src[-1], src[0] ); \ else \ { \ buf[0] = PD_LT( src[-6], src[-3], src[0] ); \ buf[1] = PD_LT( src[-5], src[-2], src[1] ); \ buf[2] = PD_LT( src[-4], src[-1], src[2] ); \ } \ } \ } \ else if( W == 3 ) \ { \ for( i = 0; i < H; i++, src += src_step, buf += channels*2 ) \ { \ if( channels == 1 ) \ { \ buf[0] = PD_LT( src[-2], src[-1], src[0] ); \ buf[1] = PD_LT( src[0], src[-1], src[-2] ); \ } \ else \ { \ buf[0] = PD_LT( src[-6], src[-3], src[0] ); \ buf[1] = PD_LT( src[-5], src[-2], src[1] ); \ buf[2] = PD_LT( src[-4], src[-1], src[2] ); \ buf[3] = PD_LT( src[0], src[-3], src[-6] ); \ buf[4] = PD_LT( src[1], src[-2], src[-5] ); \ buf[5] = PD_LT( src[2], src[-1], src[-4] ); \ } \ } \ } \ else if( cols == 1 ) \ { \ for( i = 0; i < H; i++, src += src_step, buf += channels ) \ { \ if( channels == 1 ) \ buf[0] = PD_FILTER( src[-4], src[-3], src[-2], src[-1], src[0]); \ else \ { \ buf[0] = PD_FILTER( src[-12], src[-9], src[-6], src[-3], src[0]); \ buf[1] = PD_FILTER( src[-11], src[-8], src[-5], src[-2], src[1]); \ buf[2] = PD_FILTER( src[-10], src[-7], src[-4], src[-1], src[2]); \ } \ } \ } \ else \ { \ for( i = 0; i < H; i++, src += src_step, buf += channels*2 ) \ { \ if( channels == 1 ) \ { \ buf[0] = PD_FILTER( src[-4], src[-3], src[-2], src[-1], src[0] ); \ buf[1] = PD_LT( src[0], src[-1], src[-2] ); \ } \ else \ { \ buf[0] = PD_FILTER( src[-12], src[-9], src[-6], src[-3], src[0] ); \ buf[1] = PD_FILTER( src[-11], src[-8], src[-5], src[-2], src[1] ); \ buf[2] = PD_FILTER( src[-10], src[-7], src[-4], src[-1], src[2] ); \ buf[3] = PD_LT( src[0], src[-3], src[-6] ); \ buf[4] = PD_LT( src[1], src[-2], src[-5] ); \ buf[5] = PD_LT( src[2], src[-1], src[-4] ); \ } \ } \ } \ buf = buf0; \ } \ \ src = src2; \ \ /******************* STAGE 2. ******************/ \ \ /* do vertical convolution of the pre-processed right columns, */ \ /* stored in buffer, and write results to the destination */ \ /* do vertical convolution of the 1-2 bottom rows */ \ /* and write results to the buffer */ \ if( H <= 2 ) \ { \ if( cols > 0 ) \ { \ assert( Hd == 1 ); \ for( j = 0; j < bufW; j++ ) \ dst[j] = (arrtype)_pd_scale_( PD_SINGULAR( buf[j], buf[j+(H-1)*bufW] ));\ } \ \ if( rows > 0 ) \ { \ for( j = 0; j < Wn; j++ ) \ buf[j] = PD_SINGULAR( src[j-src_step], src[j] ); \ } \ } \ else if( H == 3 ) \ { \ if( cols > 0 ) \ { \ for( j = 0; j < bufW; j++ ) \ { \ dst[j]= (arrtype)_pd_scale_(PD_LT( buf[j], buf[j+bufW], buf[j+bufW*2]));\ } \ if( Hd == 2 ) \ { \ dst += dst_step; \ for( j = 0; j < bufW; j++ ) \ dst[j] = (arrtype)_pd_scale_( PD_LT( buf[j+bufW*2], \ buf[j+bufW], buf[j] )); \ } \ } \ \ if( Hd == 1 ) \ { \ for( j = 0; j < Wn; j++ ) \ buf[j] = PD_LT( src[j-src_step*2], src[j - src_step], src[j] ); \ } \ else \ { \ for( j = 0; j < Wn; j++ ) \ { \ buf[j] = PD_LT( src[j-src_step*2], src[j - src_step], src[j] ); \ buf[j+Wn] = PD_LT( src[j],src[j-src_step],src[j-src_step*2] ); \ } \ } \ } \ else \ { \ if( cols > 0 ) \ { \ /* top of the right border */ \ for( j = 0; j < bufW; j++ ) \ dst[j]=(arrtype)_pd_scale_( PD_LT( buf[j], buf[j+bufW], buf[j+bufW*2]));\ \ /* middle part of the right border */ \ buf += bufW*2; \ dst += dst_step; \ for( i = 1; i < Hd_; i++, dst += dst_step, buf += bufW*2 ) \ { \ for( j = 0; j < bufW; j++ ) \ dst[j] = (arrtype)_pd_scale_( PD_FILTER( buf[j-bufW*2], buf[j-bufW],\ buf[j], buf[j+bufW], buf[j+bufW*2] ));\ } \ \ /* bottom of the right border */ \ if( !(H & 1) ) \ { \ for( j = 0; j < bufW; j++ ) \ dst[j] = (arrtype)_pd_scale_( PD_RB( buf[j-bufW*2], buf[j-bufW], \ buf[j], buf[j+bufW] )); \ } \ else if( rows > 1 ) \ { \ for( j = 0; j < bufW; j++ ) \ dst[j]=(arrtype)_pd_scale_( PD_LT( buf[j-bufW*2], \ buf[j-bufW], buf[j])); \ } \ \ buf = buf0; \ } \ \ if( rows > 0 ) \ { \ if( !(H & 1) ) \ { \ for( j = 0; j < Wn; j++ ) \ buf[j] = PD_LT( src[j], src[j-src_step], src[j-src_step*2] ); \ } \ else if( cols == 1 ) \ { \ for( j = 0; j < Wn; j++ ) \ buf[j] = PD_FILTER( src[j-src_step*4], src[j-src_step*3], \ src[j-src_step*2], src[j-src_step], src[j] ); \ } \ else \ { \ for( j = 0; j < Wn; j++ ) \ { \ buf[j] = PD_FILTER( src[j-src_step*4], src[j-src_step*3], \ src[j-src_step*2], src[j-src_step], src[j] ); \ buf[j+Wn] = PD_LT( src[j], src[j-src_step], src[j-src_step*2] ); \ } \ } \ } \ } \ \ \ /******************* STAGE 3. ******************/ \ \ /* do horizontal convolution of the pre-processed bottom rows,*/ \ /* stored in buffer, and write results to the destination */ \ if( rows > 0 ) \ { \ dst = dst2; \ \ if( W <= 2 ) \ { \ assert( Wd == 1 ); \ for( ; rows--; dst += dst_step, buf += Wn ) \ { \ if( channels == 1 ) \ dst[0] = (arrtype)_pd_scale_( PD_SINGULAR( buf[0], buf[Wn-1] )); \ else \ { \ dst[0] = (arrtype)_pd_scale_( PD_SINGULAR( buf[0], buf[Wn-3] )); \ dst[1] = (arrtype)_pd_scale_( PD_SINGULAR( buf[1], buf[Wn-2] )); \ dst[2] = (arrtype)_pd_scale_( PD_SINGULAR( buf[2], buf[Wn-1] )); \ } \ } \ } \ else if( W == 3 ) \ { \ if( Wd == 1 ) \ { \ for( ; rows--; dst += dst_step, buf += Wn ) \ { \ if( channels == 1 ) \ dst[0] = (arrtype)_pd_scale_( PD_LT(buf[0], buf[1], buf[2] )); \ else \ { \ dst[0] = (arrtype)_pd_scale_( PD_LT(buf[0], buf[3], buf[6] )); \ dst[1] = (arrtype)_pd_scale_( PD_LT(buf[1], buf[4], buf[7] )); \ dst[2] = (arrtype)_pd_scale_( PD_LT(buf[2], buf[5], buf[8] )); \ } \ } \ } \ else \ { \ for( ; rows--; dst += dst_step, buf += Wn ) \ { \ if( channels == 1 ) \ { \ dst[0] = (arrtype)_pd_scale_( PD_LT(buf[0], buf[1], buf[2] )); \ dst[1] = (arrtype)_pd_scale_( PD_LT(buf[2], buf[1], buf[0] )); \ } \ else \ { \ dst[0] = (arrtype)_pd_scale_( PD_LT(buf[0], buf[3], buf[6] )); \ dst[1] = (arrtype)_pd_scale_( PD_LT(buf[1], buf[4], buf[7] )); \ dst[2] = (arrtype)_pd_scale_( PD_LT(buf[2], buf[5], buf[8] )); \ dst[3] = (arrtype)_pd_scale_( PD_LT(buf[6], buf[3], buf[0] )); \ dst[4] = (arrtype)_pd_scale_( PD_LT(buf[7], buf[4], buf[1] )); \ dst[5] = (arrtype)_pd_scale_( PD_LT(buf[8], buf[5], buf[2] )); \ } \ } \ } \ } \ else \ { \ for( ; rows--; dst += dst_step, buf += Wn ) \ { \ if( channels == 1 ) \ { \ /* left part of the bottom row */ \ dst[0] = (arrtype)_pd_scale_( PD_LT( buf[0], buf[1], buf[2] )); \ \ /* middle part of the bottom row */ \ for( i = 1; i < Wd_; i++ ) \ { \ dst[i] = (arrtype)_pd_scale_( PD_FILTER(buf[i*2-2], buf[i*2-1], \ buf[i*2],buf[i*2+1], buf[i*2+2] )); \ } \ \ /* right part of the bottom row */ \ if( !(W & 1) ) \ dst[i] = (arrtype)_pd_scale_( PD_RB( buf[i*2-2],buf[i*2-1], \ buf[i*2], buf[i*2+1] )); \ else if( cols > 1 ) \ dst[i] = (arrtype)_pd_scale_( PD_LT( buf[i*2-2], \ buf[i*2-1], buf[i*2] )); \ } \ else \ { \ /* left part of the bottom row */ \ dst[0] = (arrtype)_pd_scale_( PD_LT( buf[0], buf[3], buf[6] )); \ dst[1] = (arrtype)_pd_scale_( PD_LT( buf[1], buf[4], buf[7] )); \ dst[2] = (arrtype)_pd_scale_( PD_LT( buf[2], buf[5], buf[8] )); \ \ /* middle part of the bottom row */ \ for( i = 3; i < Wd_*3; i++ ) \ { \ dst[i] = (arrtype)_pd_scale_( PD_FILTER(buf[i*2-6], buf[i*2-3], \ buf[i*2],buf[i*2+3], buf[i*2+6]));\ } \ \ /* right part of the bottom row */ \ if( !(W & 1) ) \ { \ dst[i] = (arrtype)_pd_scale_( PD_RB( buf[i*2-6],buf[i*2-3], \ buf[i*2], buf[i*2+3] )); \ dst[i+1] = (arrtype)_pd_scale_( PD_RB( buf[i*2-5],buf[i*2-2], \ buf[i*2+1], buf[i*2+4] )); \ dst[i+2] = (arrtype)_pd_scale_( PD_RB( buf[i*2-4],buf[i*2-1], \ buf[i*2+2], buf[i*2+5] )); \ } \ else if( cols > 1 ) \ { \ dst[i] = (arrtype)_pd_scale_( PD_LT( buf[i*2-6], buf[i*2-3], buf[i*2] )); \ dst[i+1] = (arrtype)_pd_scale_( PD_LT( buf[i*2-5], buf[i*2-2], buf[i*2+1]));\ dst[i+2] = (arrtype)_pd_scale_( PD_LT( buf[i*2-4], buf[i*2-1], buf[i*2+2]));\ } \ } \ } \ } \ } \ \ if( !local_alloc ) \ cvFree( &buf0 ); \ \ return CV_OK; \ } #define ICV_DEF_INIT_PYR_TABLE( FUNCNAME ) \ static void icvInit##FUNCNAME##Table( CvFuncTable* tab ) \ { \ tab->fn_2d[CV_8U] = (void*)icv##FUNCNAME##_8u_CnR; \ tab->fn_2d[CV_8S] = 0; \ tab->fn_2d[CV_16S] = (void*)icv##FUNCNAME##_16s_CnR; \ tab->fn_2d[CV_16U] = (void*)icv##FUNCNAME##_16u_CnR; \ tab->fn_2d[CV_32F] = (void*)icv##FUNCNAME##_32f_CnR; \ tab->fn_2d[CV_64F] = (void*)icv##FUNCNAME##_64f_CnR; \ } static void icvInitPyrDownBorderTable( CvFuncTable* tab ); ICV_DEF_INIT_PYR_TABLE( PyrUpG5x5 ) ICV_DEF_INIT_PYR_TABLE( PyrDownG5x5 ) typedef CvStatus (CV_STDCALL * CvPyrDownBorderFunc)( const void* src, int srcstep, CvSize srcsize, void* dst, int dststep, CvSize dstsize, int cn ); ////////////////////////////// IPP pyramid functions ///////////////////////////////////// icvPyrDown_Gauss5x5_8u_C1R_t icvPyrDown_Gauss5x5_8u_C1R_p = 0; icvPyrDown_Gauss5x5_8u_C3R_t icvPyrDown_Gauss5x5_8u_C3R_p = 0; icvPyrDown_Gauss5x5_32f_C1R_t icvPyrDown_Gauss5x5_32f_C1R_p = 0; icvPyrDown_Gauss5x5_32f_C3R_t icvPyrDown_Gauss5x5_32f_C3R_p = 0; icvPyrUp_Gauss5x5_8u_C1R_t icvPyrUp_Gauss5x5_8u_C1R_p = 0; icvPyrUp_Gauss5x5_8u_C3R_t icvPyrUp_Gauss5x5_8u_C3R_p = 0; icvPyrUp_Gauss5x5_32f_C1R_t icvPyrUp_Gauss5x5_32f_C1R_p = 0; icvPyrUp_Gauss5x5_32f_C3R_t icvPyrUp_Gauss5x5_32f_C3R_p = 0; icvPyrUpGetBufSize_Gauss5x5_t icvPyrUpGetBufSize_Gauss5x5_p = 0; icvPyrDownGetBufSize_Gauss5x5_t icvPyrDownGetBufSize_Gauss5x5_p = 0; typedef CvStatus (CV_STDCALL * CvPyramidFunc) ( const void* src, int srcstep, void* dst, int dststep, CvSize size, void* buffer, int cn ); typedef CvStatus (CV_STDCALL * CvPyramidIPPFunc) ( const void* src, int srcstep, void* dst, int dststep, CvSize size, void* buffer ); ////////////////////////////////////////////////////////////////////////////////////////// /****************************************************************************************\ * External functions * \****************************************************************************************/ CV_IMPL void cvPyrUp( const void* srcarr, void* dstarr, int _filter ) { static CvFuncTable pyrup_tab; static int inittab = 0; void *buffer = 0; int local_alloc = 0; CV_FUNCNAME( "cvPyrUp" ); __BEGIN__; int coi1 = 0, coi2 = 0; int buffer_size = 0; int type, depth, cn; CvMat srcstub, *src = (CvMat*)srcarr; CvMat dststub, *dst = (CvMat*)dstarr; CvFilter filter = (CvFilter) _filter; CvPyramidFunc func; CvPyramidIPPFunc ipp_func = 0; int use_ipp = 0; CvSize size; if( !inittab ) { icvInitPyrUpG5x5Table( &pyrup_tab ); inittab = 1; } CV_CALL( src = cvGetMat( src, &srcstub, &coi1 )); CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 )); if( coi1 != 0 || coi2 != 0 ) CV_ERROR( CV_BadCOI, "" ); if( filter != CV_GAUSSIAN_5x5 ) CV_ERROR( CV_StsBadArg, "this filter type not supported" ); if( !CV_ARE_TYPES_EQ( src, dst )) CV_ERROR( CV_StsUnmatchedFormats, "" ); if( src->cols*2 != dst->cols || src->rows*2 != dst->rows ) CV_ERROR( CV_StsUnmatchedSizes, "" ); size = cvGetMatSize(src); type = CV_MAT_TYPE(src->type); depth = CV_MAT_DEPTH(type); cn = CV_MAT_CN(type); if( cn != 1 && cn != 3 ) CV_ERROR( CV_StsUnsupportedFormat, "The images must have 1 or 3 channel" ); func = (CvPyramidFunc)pyrup_tab.fn_2d[depth]; if( !func ) CV_ERROR( CV_StsUnsupportedFormat, "" ); if( icvPyrUpGetBufSize_Gauss5x5_p ) { ipp_func = type == CV_8UC1 ? icvPyrUp_Gauss5x5_8u_C1R_p : type == CV_8UC3 ? icvPyrUp_Gauss5x5_8u_C3R_p : type == CV_32FC1 ? icvPyrUp_Gauss5x5_32f_C1R_p : type == CV_32FC3 ? icvPyrUp_Gauss5x5_32f_C3R_p : 0; use_ipp = ipp_func && icvPyrUpGetBufSize_Gauss5x5_p( size.width, icvDepthToDataType(type), cn, &buffer_size ) >= 0; } if( !use_ipp ) icvPyrUpG5x5_GetBufSize( size.width, icvDepthToDataType(type), cn, &buffer_size ); if( buffer_size <= CV_MAX_LOCAL_SIZE ) { buffer = cvStackAlloc( buffer_size ); local_alloc = 1; } else CV_CALL( buffer = cvAlloc( buffer_size )); if( !use_ipp ) func( src->data.ptr, src->step, dst->data.ptr, dst->step, size, buffer, cn ); else IPPI_CALL( ipp_func( src->data.ptr, src->step ? src->step : CV_STUB_STEP, dst->data.ptr, dst->step ? dst->step : CV_STUB_STEP, size, buffer )); __END__; if( buffer && !local_alloc ) cvFree( &buffer ); } CV_IMPL void cvPyrDown( const void* srcarr, void* dstarr, int _filter ) { static CvFuncTable pyrdown_tab; static CvFuncTable pyrdownborder_tab; static int inittab = 0; void *buffer = 0; int local_alloc = 0; CV_FUNCNAME( "cvPyrDown" ); __BEGIN__; int coi1 = 0, coi2 = 0; int buffer_size = 0; int type, depth, cn; CvMat srcstub, *src = (CvMat*)srcarr; CvMat dststub, *dst = (CvMat*)dstarr; CvFilter filter = (CvFilter) _filter; CvPyramidFunc func; CvPyramidIPPFunc ipp_func = 0; int use_ipp = 0; CvSize src_size, src_size2, dst_size; if( !inittab ) { icvInitPyrDownG5x5Table( &pyrdown_tab ); icvInitPyrDownBorderTable( &pyrdownborder_tab ); inittab = 1; } CV_CALL( src = cvGetMat( src, &srcstub, &coi1 )); CV_CALL( dst = cvGetMat( dst, &dststub, &coi2 )); if( coi1 != 0 || coi2 != 0 ) CV_ERROR( CV_BadCOI, "" ); if( filter != CV_GAUSSIAN_5x5 ) CV_ERROR( CV_StsBadArg, "this filter type not supported" ); if( !CV_ARE_TYPES_EQ( src, dst )) CV_ERROR( CV_StsUnmatchedFormats, "" ); src_size = cvGetMatSize(src); dst_size = cvGetMatSize(dst); src_size2.width = src_size.width & -2; src_size2.height = src_size.height & -2; if( (unsigned)(dst_size.width - src_size.width/2) > 1 || (unsigned)(dst_size.height - src_size.height/2) > 1 ) CV_ERROR( CV_StsUnmatchedSizes, "" ); // current restriction of PyrDownBorder* if( (src_size.width <= 2 && dst_size.width != 1) || (src_size.height <= 2 && dst_size.height != 1) ) CV_ERROR( CV_StsUnmatchedSizes, "" ); /*if( src->data.ptr == dst->data.ptr ) CV_ERROR( CV_StsInplaceNotSupported, "" );*/ type = CV_MAT_TYPE(src->type); depth = CV_MAT_DEPTH(type); cn = CV_MAT_CN(type); if( cn != 1 && cn != 3 ) CV_ERROR( CV_StsUnsupportedFormat, "The images must have 1 or 3 channel" ); func = (CvPyramidFunc)pyrdown_tab.fn_2d[depth]; if( !func ) CV_ERROR( CV_StsUnsupportedFormat, "" ); if( icvPyrDownGetBufSize_Gauss5x5_p ) { ipp_func = type == CV_8UC1 ? icvPyrDown_Gauss5x5_8u_C1R_p : type == CV_8UC3 ? icvPyrDown_Gauss5x5_8u_C3R_p : type == CV_32FC1 ? icvPyrDown_Gauss5x5_32f_C1R_p : type == CV_32FC3 ? icvPyrDown_Gauss5x5_32f_C3R_p : 0; use_ipp = ipp_func && icvPyrDownGetBufSize_Gauss5x5_p( src_size2.width, icvDepthToDataType(type), cn, &buffer_size ) >= 0; } if( !use_ipp ) icvPyrDownG5x5_GetBufSize( src_size2.width, icvDepthToDataType(type), cn, &buffer_size ); if( buffer_size <= CV_MAX_LOCAL_SIZE ) { buffer = cvStackAlloc( buffer_size ); local_alloc = 1; } else CV_CALL( buffer = cvAlloc( buffer_size )); if( !use_ipp ) func( src->data.ptr, src->step, dst->data.ptr, dst->step, src_size2, buffer, cn ); else IPPI_CALL( ipp_func( src->data.ptr, src->step ? src->step : CV_STUB_STEP, dst->data.ptr, dst->step ? dst->step : CV_STUB_STEP, src_size2, buffer )); if( src_size.width != dst_size.width*2 || src_size.height != dst_size.height*2 ) { CvPyrDownBorderFunc border_func = (CvPyrDownBorderFunc) pyrdownborder_tab.fn_2d[CV_MAT_DEPTH(type)]; if( !border_func ) CV_ERROR( CV_StsUnsupportedFormat, "" ); IPPI_CALL( border_func( src->data.ptr, src->step, src_size, dst->data.ptr, dst->step, dst_size, CV_MAT_CN(type) )); } __END__; if( buffer && !local_alloc ) cvFree( &buffer ); } CV_IMPL void cvReleasePyramid( CvMat*** _pyramid, int extra_layers ) { CV_FUNCNAME( "cvReleasePyramid" ); __BEGIN__; CvMat** pyramid; int i; if( !_pyramid ) CV_ERROR( CV_StsNullPtr, "" ); pyramid = *_pyramid; if( pyramid ) { for( i = 0; i <= extra_layers; i++ ) cvReleaseMat( &pyramid[i] ); } cvFree( _pyramid ); __END__; } CV_IMPL CvMat** cvCreatePyramid( const CvArr* srcarr, int extra_layers, double rate, const CvSize* layer_sizes, CvArr* bufarr, int calc, int filter ) { CvMat** pyramid = 0; const float eps = 0.1f; CV_FUNCNAME( "cvCreatePyramid" ); __BEGIN__; int i, elem_size, layer_step; CvMat stub, *src; CvSize size, layer_size; uchar* ptr = 0; CV_CALL( src = cvGetMat( srcarr, &stub )); if( extra_layers < 0 ) CV_ERROR( CV_StsOutOfRange, "The number of extra layers must be non negative" ); elem_size = CV_ELEM_SIZE(src->type); size = cvGetMatSize(src); if( bufarr ) { CvMat bstub, *buf; int bufsize = 0; CV_CALL( buf = cvGetMat( bufarr, &bstub )); bufsize = buf->rows*buf->cols*CV_ELEM_SIZE(buf->type); layer_size = size; for( i = 1; i <= extra_layers; i++ ) { if( !layer_sizes ) { layer_size.width = cvRound(layer_size.width*rate+eps); layer_size.height = cvRound(layer_size.height*rate+eps); } else layer_size = layer_sizes[i-1]; layer_step = layer_size.width*elem_size; bufsize -= layer_step*layer_size.height; } if( bufsize < 0 ) CV_ERROR( CV_StsOutOfRange, "The buffer is too small to fit the pyramid" ); ptr = buf->data.ptr; } CV_CALL( pyramid = (CvMat**)cvAlloc( (extra_layers+1)*sizeof(pyramid[0]) )); memset( pyramid, 0, (extra_layers+1)*sizeof(pyramid[0]) ); pyramid[0] = cvCreateMatHeader( size.height, size.width, src->type ); cvSetData( pyramid[0], src->data.ptr, src->step ); layer_size = size; for( i = 1; i <= extra_layers; i++ ) { if( !layer_sizes ) { layer_size.width = cvRound(layer_size.width*rate + eps); layer_size.height = cvRound(layer_size.height*rate + eps); } else layer_size = layer_sizes[i]; if( bufarr ) { pyramid[i] = cvCreateMatHeader( layer_size.height, layer_size.width, src->type ); layer_step = layer_size.width*elem_size; cvSetData( pyramid[i], ptr, layer_step ); ptr += layer_step*layer_size.height; } else pyramid[i] = cvCreateMat( layer_size.height, layer_size.width, src->type ); if( calc ) cvPyrDown( pyramid[i-1], pyramid[i], filter ); //cvResize( pyramid[i-1], pyramid[i], CV_INTER_LINEAR ); } __END__; if( cvGetErrStatus() < 0 ) cvReleasePyramid( &pyramid, extra_layers ); return pyramid; } /* MSVC .NET 2003 spends a long time building this, thus, as the code is not performance-critical, we turn off the optimization here */ #if defined _MSC_VER && _MSC_VER > 1300 && !defined CV_ICC #pragma optimize("", off) #endif ICV_DEF_PYR_BORDER_FUNC( 8u, uchar, int, PD_SCALE_INT ) ICV_DEF_PYR_BORDER_FUNC( 16u, ushort, int, PD_SCALE_INT ) ICV_DEF_PYR_BORDER_FUNC( 16s, short, int, PD_SCALE_INT ) ICV_DEF_PYR_BORDER_FUNC( 32f, float, float, PD_SCALE_FLT ) ICV_DEF_PYR_BORDER_FUNC( 64f, double, double, PD_SCALE_FLT ) #define ICV_DEF_INIT_PYR_BORDER_TABLE( FUNCNAME ) \ static void icvInit##FUNCNAME##Table( CvFuncTable* tab ) \ { \ tab->fn_2d[CV_8U] = (void*)icv##FUNCNAME##_8u_CnR; \ tab->fn_2d[CV_8S] = 0; \ tab->fn_2d[CV_16U] = (void*)icv##FUNCNAME##_16u_CnR; \ tab->fn_2d[CV_16S] = (void*)icv##FUNCNAME##_16s_CnR; \ tab->fn_2d[CV_32F] = (void*)icv##FUNCNAME##_32f_CnR; \ tab->fn_2d[CV_64F] = (void*)icv##FUNCNAME##_64f_CnR; \ } ICV_DEF_INIT_PYR_BORDER_TABLE( PyrDownBorder ) /* End of file. */