www.pudn.com > OpenCV-Intel.zip > cvsmooth.cpp
/*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"
/****************************************************************************************\
Initialization
\****************************************************************************************/
CvFilterState* icvFilterInitAlloc(
int roiWidth, CvDataType dataType, int channels,
CvSize elSize, CvPoint elAnchor,
const void* elData, int elementType )
{
CvFilterState *state = 0;
const int align = sizeof(size_t);
int ker_size = 0;
int buffer_step = 0;
int buffer_size;
int bt_pix, bt_pix_n;
int aligned_hdr_size = cvAlign((int)sizeof(*state),align);
int temp_lines = 2;
int binaryElement = ICV_KERNEL_TYPE(elementType) == ICV_BINARY_KERNEL;
int separableElement = ICV_KERNEL_TYPE(elementType) == ICV_SEPARABLE_KERNEL;
char *ptr;
CV_FUNCNAME( "icvFilterInitAlloc" );
__BEGIN__;
if( roiWidth <= 0 )
CV_ERROR( CV_StsOutOfRange, "image width <= 0" );
if( dataType != cv8u && dataType != cv32s && dataType != cv32f )
CV_ERROR( CV_StsUnsupportedFormat, "dataType is not CV_8U, CV_32S or CV_32F" );
if( channels < 1 || channels > 4 )
CV_ERROR( CV_StsUnsupportedFormat, "number of channels is not within 1..4" );
if( elSize.width <= 0 || elSize.height <= 0 )
CV_ERROR( CV_StsBadSize, "aperture width <= 0 or aperture height <= 0" );
if( (unsigned) elAnchor.x >= (unsigned) elSize.width ||
(unsigned) elAnchor.y >= (unsigned) elSize.height )
CV_ERROR( CV_StsOutOfRange, "anchor point is outside the aperture" );
bt_pix = dataType == cv8u ? 1 : dataType == cv32s ? sizeof(int) : sizeof(float);
bt_pix_n = bt_pix * channels;
if( elData )
ker_size = binaryElement ? (elSize.width + 1) * elSize.height * 2 :
separableElement ? (elSize.width + elSize.height)*bt_pix :
elSize.width * elSize.height * bt_pix;
buffer_step = cvAlign((roiWidth + elSize.width+1 + CV_MORPH_ALIGN*4)*bt_pix_n, align);
buffer_size = (elSize.height + temp_lines) * (buffer_step + sizeof(void*)) +
ker_size + aligned_hdr_size + elSize.width * bt_pix_n + align*4;
buffer_size = cvAlign(buffer_size + align, align);
CV_CALL( state = (CvFilterState*)cvAlloc( buffer_size ));
ptr = (char*)state;
state->buffer_step = buffer_step;
state->crows = 0;
state->ker_x = elAnchor.x;
state->ker_y = elAnchor.y;
state->ker_height = elSize.height;
state->ker_width = elSize.width;
state->kerType = elementType;
state->divisor = 1;
state->max_width = roiWidth;
state->dataType = dataType;
state->channels = channels;
state->origin = 0;
ptr += aligned_hdr_size + align;
state->buffer = ptr;
ptr += buffer_step * elSize.height;
state->tbuf = ptr;
ptr += buffer_step * temp_lines;
state->rows = (char**)ptr;
ptr += sizeof(state->rows[0])*elSize.height;
state->ker0 = state->ker1 = 0;
if( elData )
{
state->ker0 = (uchar*)ptr;
if( binaryElement )
{
int i, mask_size = elSize.width * elSize.height;
state->ker1 = 0;
for( i = 0; i < mask_size; i++ )
{
int t = ((int*)elData)[i] ? -1 : 0;
state->ker0[i] = (uchar)t;
}
}
else
{
memcpy( state->ker0, elData, ker_size );
state->ker1 = (uchar*)(separableElement ? ptr + elSize.width*bt_pix : 0);
}
}
__END__;
if( cvGetErrStatus() < 0 )
icvFilterFree( &state );
return state;
}
void icvFilterFree( CvFilterState** filterState )
{
cvFree( (void**)filterState );
}
#define SMALL_GAUSSIAN_SIZE 7
static void
icvCalcGaussianKernel( int n, double sigma, float* kernel )
{
static const float small_gaussian_tab[][SMALL_GAUSSIAN_SIZE] =
{
{1.f},
{0.25f, 0.5f, 0.25f},
{0.0625f, 0.25f, 0.375f, 0.25f, 0.0625f},
{0.03125, 0.109375, 0.21875, 0.28125, 0.21875, 0.109375, 0.03125}
};
if( n <= SMALL_GAUSSIAN_SIZE && sigma <= 0 )
{
assert( n%2 == 1 );
memcpy( kernel, small_gaussian_tab[n>>1], n*sizeof(kernel[0]));
}
else
{
double sigmaX = sigma > 0 ? sigma : (n/2 - 1)*0.3 + 0.8;
double scale2X = -0.5/(sigmaX*sigmaX);
double sum = 1.;
int i;
sum = kernel[n/2] = 1.f;
for( i = 1; i <= n/2; i++ )
{
kernel[n/2+i] = kernel[n/2-i] = (float)exp(scale2X*i*i);
sum += kernel[n/2+i]*2;
}
sum = 1./sum;
for( i = 0; i <= n/2; i++ )
kernel[n/2+i] = kernel[n/2-i] = (float)(kernel[n/2+i]*sum);
}
}
static CvFilterState*
icvSmoothInitAlloc( int width, CvDataType /*dataType*/, int channels,
CvSize el_size, int smoothtype, double sigma )
{
CvFilterState* filterState = 0;
CvPoint el_anchor = { el_size.width/2, el_size.height/2 };
float* kx = 0;
if( smoothtype == CV_GAUSSIAN )
{
kx = (float*)cvStackAlloc( (el_size.width + el_size.height)*sizeof(kx[0]));
float* ky = kx + el_size.width;
icvCalcGaussianKernel( el_size.width, sigma, kx );
if( el_size.width == el_size.height )
memcpy( ky, kx, el_size.width*sizeof(kx[0]) );
else
icvCalcGaussianKernel( el_size.height, sigma, ky );
}
filterState = icvFilterInitAlloc( width, cv32f, channels, el_size, el_anchor,
kx, ICV_SEPARABLE_KERNEL );
if( filterState )
{
if( smoothtype == CV_BLUR )
filterState->divisor = el_size.width * el_size.height;
else if( smoothtype == CV_GAUSSIAN )
{
filterState->divisor = (double)(1 << el_size.width) * (1 << el_size.height);
filterState->kerType = (filterState->kerType & ~255) |
(sigma > 0 ? ICV_CUSTOM_GAUSSIAN_KERNEL : ICV_DEFAULT_GAUSSIAN_KERNEL);
}
}
return filterState;
}
static void
icvSmoothFree( CvFilterState ** filterState )
{
icvFilterFree( filterState );
}
/****************************************************************************************\
Simple Blur
\****************************************************************************************/
static CvStatus CV_STDCALL
icvBlur_8u_CnR( uchar* src, int srcStep,
uchar* dst, int dstStep, CvSize * roiSize,
CvFilterState* state, int stage )
{
int width = roiSize->width;
int src_height = roiSize->height;
int dst_height = src_height;
int x, y = 0, i;
int ker_x = state->ker_x;
int ker_y = state->ker_y;
int ker_width = state->ker_width;
int ker_height = state->ker_height;
int ker_right = ker_width - ker_x;
int crows = state->crows;
int **rows = (int**)(state->rows);
uchar *tbuf = (uchar*)(state->tbuf);
int *sumbuf = (int*)((char*)state->tbuf + state->buffer_step);
int *trow, *trow2;
int channels = state->channels;
int ker_x_n = ker_x * channels;
int ker_width_n = ker_width * channels;
int ker_right_n = ker_right * channels;
int width_n = width * channels;
int is_small_width = width <= ker_width;
int starting_flag = 0;
int width_rest = width_n & (CV_MORPH_ALIGN - 1);
int divisor = cvRound(state->divisor);
double inv_divisor = divisor ? 1./divisor : 0.;
if( stage == CV_START + CV_END )
stage = CV_WHOLE;
/* initialize cyclic buffer when starting */
if( stage == CV_WHOLE || stage == CV_START )
{
for( i = 0; i < ker_height; i++ )
rows[i] = (int*)(state->buffer + state->buffer_step * i);
crows = ker_y;
if( stage != CV_WHOLE )
dst_height -= ker_height - ker_y - 1;
starting_flag = 1;
}
if( stage == CV_END )
dst_height += ker_height - ker_y - 1;
do
{
int need_copy = is_small_width | (y == 0);
uchar *tsrc;
int *tdst;
uchar *tdst2;
int *saved_row = rows[ker_y];
/* fill cyclic buffer - horizontal filtering */
for( ; crows < ker_height; crows++ )
{
tsrc = src - ker_x_n;
tdst = rows[crows];
if( src_height-- <= 0 )
{
if( stage != CV_WHOLE && stage != CV_END )
break;
/* duplicate last row */
trow = rows[crows - 1];
CV_COPY( tdst, trow, width_n, x );
continue;
}
need_copy |= src_height == 0;
if( ker_width > 1 )
{
if( need_copy )
{
tsrc = tbuf - ker_x_n;
CV_COPY( tbuf, src, width_n, x );
}
else
{
CV_COPY( tbuf - ker_x_n, src - ker_x_n, ker_x_n, x );
CV_COPY( tbuf, src + width_n, ker_right_n, x );
}
/* make replication borders */
for( i = ker_x_n - 1; i >= 0; i-- )
tsrc[i] = tsrc[i + channels];
for( i = width_n + ker_x_n; i < width_n + ker_width_n; i++ )
tsrc[i] = tsrc[i - channels];
if( channels == 1 )
{
int t0 = 0;
for( i = 0; i < ker_width_n - 1; i++ )
t0 += tsrc[i];
/* horizontal blurring */
for( i = ker_width_n; i < width_n + ker_width_n; i++ )
{
t0 += tsrc[i-1];
tdst[i-ker_width_n] = t0;
t0 -= tsrc[i - ker_width_n];
}
}
else if( channels == 3 )
{
int t0 = 0, t1 = 0, t2 = 0;
for( i = 0; i < ker_width_n - 3; i += 3 )
{
t0 += tsrc[i];
t1 += tsrc[i+1];
t2 += tsrc[i+2];
}
/* horizontal blurring */
for( i = ker_width_n; i < width_n + ker_width_n; i += 3 )
{
t0 += tsrc[i-3];
t1 += tsrc[i-2];
t2 += tsrc[i-1];
tdst[i-ker_width_n] = t0;
tdst[i-ker_width_n+1] = t1;
tdst[i-ker_width_n+2] = t2;
t0 -= tsrc[i - ker_width_n];
t1 -= tsrc[i - ker_width_n + 1];
t2 -= tsrc[i - ker_width_n + 2];
}
}
else /* channels == 4 */
{
int t0 = 0, t1 = 0, t2 = 0, t3 = 0;
for( i = 0; i < ker_width_n - 4; i += 4 )
{
t0 += tsrc[i];
t1 += tsrc[i+1];
t2 += tsrc[i+2];
t3 += tsrc[i+3];
}
/* horizontal blurring */
for( i = ker_width_n; i < width_n + ker_width_n; i += 4 )
{
t0 += tsrc[i-4];
t1 += tsrc[i-3];
t2 += tsrc[i-2];
t3 += tsrc[i-1];
tdst[i-ker_width_n] = t0;
tdst[i-ker_width_n+1] = t1;
tdst[i-ker_width_n+2] = t2;
tdst[i-ker_width_n+3] = t3;
t0 -= tsrc[i - ker_width_n];
t1 -= tsrc[i - ker_width_n + 1];
t2 -= tsrc[i - ker_width_n + 2];
t3 -= tsrc[i - ker_width_n + 3];
}
}
if( !need_copy )
{
/* restore borders */
CV_COPY( src - ker_x_n, tbuf - ker_x_n, ker_x_n, x );
CV_COPY( src + width_n, tbuf, ker_right_n, x );
}
}
else
{
CV_COPY( tdst, tsrc + ker_x_n, width_n, x );
}
if( crows < ker_height )
src += srcStep;
}
if( starting_flag )
{
starting_flag = 0;
for( x = 0; x < width_n; x++ )
{
int t = rows[ker_y][x];
for( i = 0; i < ker_y; i++ ) // copy border
rows[i][x] = t;
t *= ker_y;
for( i = ker_y; i < ker_height - 1; i++ ) // accumulate initial sum
t += rows[i][x];
sumbuf[x] = t;
}
}
/* vertical convolution */
if( crows != ker_height )
break;
tdst2 = dst;
if( width_rest )
{
need_copy = width_n < CV_MORPH_ALIGN || y == dst_height - 1;
if( need_copy )
tdst2 = tbuf;
else
CV_COPY( tbuf + width_n, dst + width_n, CV_MORPH_ALIGN, x );
}
trow = rows[0];
trow2 = rows[ker_height-1];
for( x = 0; x < width_n; x += 4 )
{
int val0, val1, t0, t1;
val0 = sumbuf[x];
val1 = sumbuf[x+1];
val0 += trow2[x];
val1 += trow2[x+1];
t0 = cvRound(val0*inv_divisor);
t1 = cvRound(val1*inv_divisor);
tdst2[x] = (uchar)t0;
tdst2[x+1] = (uchar)t1;
sumbuf[x] = val0 - trow[x];
sumbuf[x+1] = val1 - trow[x+1];
val0 = sumbuf[x+2];
val1 = sumbuf[x+3];
val0 += trow2[x+2];
val1 += trow2[x+3];
t0 = cvRound(val0*inv_divisor);
t1 = cvRound(val1*inv_divisor);
tdst2[x+2] = (uchar)t0;
tdst2[x+3] = (uchar)t1;
sumbuf[x+2] = val0 - trow[x+2];
sumbuf[x+3] = val1 - trow[x+3];
}
if( width_rest )
{
if( need_copy )
CV_COPY( dst, tbuf, width_n, x );
else
CV_COPY( dst + width_n, tbuf + width_n, CV_MORPH_ALIGN, x );
}
rows[ker_y] = saved_row;
/* rotate buffer */
{
int *t = rows[0];
CV_COPY( rows, rows + 1, ker_height - 1, i );
rows[i] = t;
crows--;
dst += dstStep;
}
}
while( ++y < dst_height );
roiSize->height = y;
state->crows = crows;
return CV_OK;
}
CvStatus CV_STDCALL
icvBlur_8u16s_C1R( const uchar* pSrc, int srcStep,
short* dst, int dstStep, CvSize * roiSize,
CvFilterState* state, int stage )
{
uchar* src = (uchar*)pSrc;
int width = roiSize->width;
int src_height = roiSize->height;
int dst_height = src_height;
int x, y = 0, i;
int ker_x = state->ker_x;
int ker_y = state->ker_y;
int ker_width = state->ker_width;
int ker_height = state->ker_height;
int ker_right = ker_width - ker_x;
int crows = state->crows;
int **rows = (int**)(state->rows);
short *tbufw = (short*)(state->tbuf);
int *sumbuf = (int*)((char*)state->tbuf + state->buffer_step);
int *trow, *trow2;
int channels = state->channels;
int ker_x_n = ker_x * channels;
int ker_width_n = ker_width * channels;
int ker_right_n = ker_right * channels;
int width_n = width * channels;
int is_small_width = width <= ker_width;
int starting_flag = 0;
int width_rest = width_n & (CV_MORPH_ALIGN - 1);
/*if( stage == CV_START + CV_END )
stage = CV_WHOLE;*/
/* initialize cyclic buffer when starting */
if( stage == CV_WHOLE || stage == CV_START )
{
for( i = 0; i < ker_height; i++ )
rows[i] = (int*)(state->buffer + state->buffer_step * i);
crows = ker_y;
if( stage != CV_WHOLE )
dst_height -= ker_height - ker_y - 1;
starting_flag = 1;
}
if( stage == CV_END )
dst_height += ker_height - ker_y - 1;
dstStep /= sizeof(dst[0]);
do
{
int need_copy = is_small_width | (y == 0);
uchar *tsrc;
int *tdst;
short *tdst2;
int *saved_row = rows[ker_y];
/* fill cyclic buffer - horizontal filtering */
for( ; crows < ker_height; crows++ )
{
tsrc = src - ker_x_n;
tdst = rows[crows];
if( src_height-- <= 0 )
{
if( stage != CV_WHOLE && stage != CV_END )
break;
/* duplicate last row */
trow = rows[crows - 1];
CV_COPY( tdst, trow, width_n, x );
continue;
}
need_copy |= src_height == 0;
if( ker_width > 1 )
{
uchar* tbuf = (uchar*)tbufw;
if( need_copy )
{
tsrc = tbuf - ker_x_n;
CV_COPY( tbuf, src, width_n, x );
}
else
{
CV_COPY( tbuf - ker_x_n, src - ker_x_n, ker_x_n, x );
CV_COPY( tbuf, src + width_n, ker_right_n, x );
}
{
/* make replication borders */
uchar pix = tsrc[ker_x];
int t0 = 0;
CV_SET( tsrc, pix, ker_x, x );
pix = tsrc[width + ker_x - 1];
CV_SET( tsrc + width + ker_x, pix, ker_right, x );
for( i = 0; i < ker_width_n - 1; i++ )
t0 += tsrc[i];
/* horizontal blurring */
for( i = ker_width_n; i < width_n + ker_width_n; i++ )
{
t0 += tsrc[i-1];
tdst[i-ker_width_n] = t0;
t0 -= tsrc[i - ker_width_n];
}
}
if( !need_copy )
{
/* restore borders */
CV_COPY( src - ker_x_n, tbuf - ker_x_n, ker_x_n, x );
CV_COPY( src + width_n, tbuf, ker_right_n, x );
}
}
else
{
CV_COPY( tdst, tsrc + ker_x_n, width_n, x );
}
if( crows < ker_height )
src += srcStep;
}
if( starting_flag )
{
starting_flag = 0;
for( x = 0; x < width_n; x++ )
{
int t = rows[ker_y][x];
for( i = 0; i < ker_y; i++ ) // copy border
rows[i][x] = t;
t *= ker_y;
for( i = ker_y; i < ker_height - 1; i++ ) // accumulate initial sum
t += rows[i][x];
sumbuf[x] = t;
}
}
/* vertical convolution */
if( crows != ker_height )
break;
tdst2 = dst;
if( width_rest )
{
need_copy = width_n < CV_MORPH_ALIGN || y == dst_height - 1;
if( need_copy )
tdst2 = tbufw;
else
CV_COPY( tbufw + width_n, dst + width_n, CV_MORPH_ALIGN, x );
}
trow = rows[0];
trow2 = rows[ker_height-1];
for( x = 0; x < width_n; x += 4 )
{
int val0, val1;
val0 = sumbuf[x];
val1 = sumbuf[x+1];
val0 += trow2[x];
val1 += trow2[x+1];
tdst2[x] = CV_CAST_16S(val0);
tdst2[x+1] = CV_CAST_16S(val1);
sumbuf[x] = val0 - trow[x];
sumbuf[x+1] = val1 - trow[x+1];
val0 = sumbuf[x+2];
val1 = sumbuf[x+3];
val0 += trow2[x+2];
val1 += trow2[x+3];
tdst2[x+2] = CV_CAST_16S(val0);
tdst2[x+3] = CV_CAST_16S(val1);
sumbuf[x+2] = val0 - trow[x+2];
sumbuf[x+3] = val1 - trow[x+3];
}
if( width_rest )
{
if( need_copy )
CV_COPY( dst, tbufw, width_n, x );
else
CV_COPY( dst + width_n, tbufw + width_n, CV_MORPH_ALIGN, x );
}
rows[ker_y] = saved_row;
/* rotate buffer */
{
int *t = rows[0];
CV_COPY( rows, rows + 1, ker_height - 1, i );
rows[i] = t;
crows--;
dst += dstStep;
}
}
while( ++y < dst_height );
roiSize->height = y;
state->crows = crows;
return CV_OK;
}
CvStatus CV_STDCALL
icvBlur_32f_CnR( const float* pSrc, int srcStep,
float* dst, int dstStep, CvSize * roiSize,
CvFilterState* state, int stage )
{
float* src = (float*)pSrc;
int width = roiSize->width;
int src_height = roiSize->height;
int dst_height = src_height;
int x, y = 0, i;
int ker_x = state->ker_x;
int ker_y = state->ker_y;
int ker_width = state->ker_width;
int ker_height = state->ker_height;
int ker_right = ker_width - ker_x;
int crows = state->crows;
float **rows = (float**)(state->rows);
float *tbuf = (float*)(state->tbuf);
float *sumbuf = (float*)((char*)state->tbuf + state->buffer_step);
float *trow, *trow2;
int channels = state->channels;
int ker_x_n = ker_x * channels;
int ker_width_n = ker_width * channels;
int ker_right_n = ker_right * channels;
int width_n = width * channels;
int is_small_width = width <= ker_width;
int starting_flag = 0;
int width_rest = width_n & (CV_MORPH_ALIGN - 1);
float scale = (float)(1./state->divisor);
int no_scale = fabs(state->divisor - 1) < DBL_EPSILON;
srcStep /= sizeof(float);
dstStep /= sizeof(float);
if( stage == CV_START + CV_END )
stage = CV_WHOLE;
/* initialize cyclic buffer when starting */
if( stage == CV_WHOLE || stage == CV_START )
{
for( i = 0; i < ker_height; i++ )
{
rows[i] = (float*)(state->buffer + state->buffer_step * i);
for( x = width_n; (x&3) != 0; x++ )
rows[i][x] = 0.f;
}
for( x = width_n; (x&3) != 0; x++ )
sumbuf[x] = 0.f;
crows = ker_y;
if( stage != CV_WHOLE )
dst_height -= ker_height - ker_y - 1;
starting_flag = 1;
}
if( stage == CV_END )
dst_height += ker_height - ker_y - 1;
do
{
int need_copy = is_small_width | (y == 0);
float *tsrc;
float *tdst;
float *tdst2;
float *saved_row = rows[ker_y];
/* fill cyclic buffer - horizontal filtering */
for( ; crows < ker_height; crows++ )
{
tsrc = src - ker_x_n;
tdst = rows[crows];
if( src_height-- <= 0 )
{
if( stage != CV_WHOLE && stage != CV_END )
break;
/* duplicate last row */
trow = rows[crows - 1];
CV_COPY( tdst, trow, width_n, x );
continue;
}
need_copy |= src_height == 0;
if( ker_width > 1 )
{
if( need_copy )
{
tsrc = tbuf - ker_x_n;
CV_COPY( tbuf, src, width_n, x );
}
else
{
CV_COPY( tbuf - ker_x_n, src - ker_x_n, ker_x_n, x );
CV_COPY( tbuf, src + width_n, ker_right_n, x );
}
/* make replication borders */
for( i = ker_x_n - 1; i >= 0; i-- )
tsrc[i] = tsrc[i + channels];
for( i = width_n + ker_x_n; i < width_n + ker_width_n; i++ )
tsrc[i] = tsrc[i - channels];
/* horizontal blurring */
if( channels == 1 )
{
float t0 = 0;
for( i = 0; i < ker_width_n - 1; i++ )
t0 += tsrc[i];
for( i = ker_width_n; i < width_n + ker_width_n; i++ )
{
t0 += tsrc[i-1];
tdst[i-ker_width_n] = t0;
t0 -= tsrc[i - ker_width_n];
}
}
else if( channels == 3 )
{
float t0 = 0, t1 = 0, t2 = 0;
for( i = 0; i < ker_width_n - 3; i += 3 )
{
t0 += tsrc[i];
t1 += tsrc[i+1];
t2 += tsrc[i+2];
}
for( i = ker_width_n; i < width_n + ker_width_n; i += 3 )
{
t0 += tsrc[i-3];
t1 += tsrc[i-2];
t2 += tsrc[i-1];
tdst[i-ker_width_n] = t0;
tdst[i-ker_width_n+1] = t1;
tdst[i-ker_width_n+2] = t2;
t0 -= tsrc[i - ker_width_n];
t1 -= tsrc[i - ker_width_n + 1];
t2 -= tsrc[i - ker_width_n + 2];
}
}
else /* channels == 4 */
{
float t0 = 0, t1 = 0, t2 = 0, t3 = 0;
for( i = 0; i < ker_width_n - 4; i += 4 )
{
t0 += tsrc[i];
t1 += tsrc[i+1];
t2 += tsrc[i+2];
t3 += tsrc[i+3];
}
/* horizontal blurring */
for( i = ker_width_n; i < width_n + ker_width_n; i += 4 )
{
t0 += tsrc[i-4];
t1 += tsrc[i-3];
t2 += tsrc[i-2];
t3 += tsrc[i-1];
tdst[i-ker_width_n] = t0;
tdst[i-ker_width_n+1] = t1;
tdst[i-ker_width_n+2] = t2;
tdst[i-ker_width_n+3] = t3;
t0 -= tsrc[i - ker_width_n];
t1 -= tsrc[i - ker_width_n + 1];
t2 -= tsrc[i - ker_width_n + 2];
t3 -= tsrc[i - ker_width_n + 3];
}
}
if( !need_copy )
{
/* restore borders */
CV_COPY( src - ker_x_n, tbuf - ker_x_n, ker_x_n, x );
CV_COPY( src + width_n, tbuf, ker_right_n, x );
}
}
else
{
CV_COPY( tdst, tsrc + ker_x_n, width_n, x );
}
if( crows < ker_height )
src += srcStep;
}
if( starting_flag )
{
starting_flag = 0;
for( x = 0; x < width_n; x++ )
{
float t = rows[ker_y][x];
for( i = 0; i < ker_y; i++ ) // copy border
rows[i][x] = t;
t *= ker_y;
for( i = ker_y; i < ker_height - 1; i++ ) // accumulate initial sum
t += rows[i][x];
sumbuf[x] = t;
}
}
/* vertical convolution */
if( crows != ker_height )
break;
tdst2 = dst;
if( width_rest )
{
need_copy = width_n < CV_MORPH_ALIGN || y == dst_height - 1;
if( need_copy )
tdst2 = tbuf;
else
CV_COPY( tbuf + width_n, dst + width_n, CV_MORPH_ALIGN, x );
}
trow = rows[0];
trow2 = rows[ker_height-1];
if( no_scale )
{
for( x = 0; x < width_n; x += 4 )
{
float val0, val1;
val0 = sumbuf[x];
val1 = sumbuf[x+1];
val0 += trow2[x];
val1 += trow2[x+1];
tdst2[x] = (float)val0;
tdst2[x+1] = (float)val1;
sumbuf[x] = val0 - trow[x];
sumbuf[x+1] = val1 - trow[x+1];
val0 = sumbuf[x+2];
val1 = sumbuf[x+3];
val0 += trow2[x+2];
val1 += trow2[x+3];
tdst2[x+2] = (float)val0;
tdst2[x+3] = (float)val1;
sumbuf[x+2] = val0 - trow[x+2];
sumbuf[x+3] = val1 - trow[x+3];
}
}
else
{
for( x = 0; x < width_n; x += 4 )
{
float val0, val1, t0, t1;
val0 = sumbuf[x];
val1 = sumbuf[x+1];
val0 += trow2[x];
val1 += trow2[x+1];
t0 = val0 * scale;
t1 = val1 * scale;
tdst2[x] = (float)t0;
tdst2[x+1] = (float)t1;
sumbuf[x] = val0 - trow[x];
sumbuf[x+1] = val1 - trow[x+1];
val0 = sumbuf[x+2];
val1 = sumbuf[x+3];
val0 += trow2[x+2];
val1 += trow2[x+3];
t0 = val0 * scale;
t1 = val1 * scale;
tdst2[x+2] = (float)t0;
tdst2[x+3] = (float)t1;
sumbuf[x+2] = val0 - trow[x+2];
sumbuf[x+3] = val1 - trow[x+3];
}
}
if( width_rest )
{
if( need_copy )
CV_COPY( dst, tbuf, width_n, x );
else
CV_COPY( dst + width_n, tbuf + width_n, CV_MORPH_ALIGN, x );
}
rows[ker_y] = saved_row;
/* rotate buffer */
{
float *t = rows[0];
CV_COPY( rows, rows + 1, ker_height - 1, i );
rows[i] = t;
crows--;
dst += dstStep;
}
}
while( ++y < dst_height );
roiSize->height = y;
state->crows = crows;
return CV_OK;
}
CvFilterState* icvBlurInitAlloc( int roiWidth, int depth, int channels, int size )
{
return icvSmoothInitAlloc( roiWidth, (CvDataType)depth, channels,
cvSize(size,size), CV_BLUR_NO_SCALE, 0 );
}
/****************************************************************************************\
Gaussian Blur
\****************************************************************************************/
static CvStatus CV_STDCALL
icvGaussianBlur_small_8u_CnR( uchar* src, int srcStep,
uchar* dst, int dstStep, CvSize * roiSize,
CvFilterState* state, int stage )
{
int width = roiSize->width;
int src_height = roiSize->height;
int dst_height = src_height;
int x, y = 0, i;
int ker_width = state->ker_width;
int ker_height = state->ker_height;
int ker_x = ker_width/2;
int ker_y = ker_height/2;
int ker_right = ker_width - ker_x;
int crows = state->crows;
int **rows = (int**)(state->rows);
uchar *tbuf = (uchar*)(state->tbuf);
int *trow = 0;
int channels = state->channels;
int ker_x_n = ker_x * channels;
int ker_right_n = ker_right * channels;
int ker_width_n = ker_width * channels;
int width_n = width * channels;
int is_small_width = width <= ker_width;
int starting_flag = 0;
int width_rest = width_n & (CV_MORPH_ALIGN - 1);
int rshift = ker_width + ker_height - 2;
int delta = 1 << (rshift - 1);
assert( ker_width <= SMALL_GAUSSIAN_SIZE &&
ker_height <= SMALL_GAUSSIAN_SIZE );
if( stage == CV_START + CV_END )
stage = CV_WHOLE;
/* initialize cyclic buffer when starting */
if( stage == CV_WHOLE || stage == CV_START )
{
for( i = 0; i < ker_height; i++ )
rows[i] = (int*)(state->buffer + state->buffer_step * i);
crows = ker_y;
if( stage != CV_WHOLE )
dst_height -= ker_height - ker_y - 1;
starting_flag = 1;
}
if( stage == CV_END )
dst_height += ker_height - ker_y - 1;
do
{
int need_copy = is_small_width | (y == 0);
uchar *tsrc;
int *tdst;
uchar *tdst2;
int *saved_row = rows[ker_y];
/* fill cyclic buffer - horizontal filtering */
for( ; crows < ker_height; crows++ )
{
tsrc = src - ker_x_n;
tdst = rows[crows];
if( src_height-- <= 0 )
{
if( stage != CV_WHOLE && stage != CV_END )
break;
/* duplicate last row */
trow = rows[crows - 1];
CV_COPY( tdst, trow, width_n, x );
continue;
}
need_copy |= src_height == 0;
if( ker_width > 1 )
{
if( need_copy )
{
tsrc = tbuf - ker_x_n;
CV_COPY( tbuf, src, width_n, x );
}
else
{
CV_COPY( tbuf - ker_x_n, src - ker_x_n, ker_x_n, x );
CV_COPY( tbuf, src + width_n, ker_right_n, x );
}
/* make replication borders */
for( i = ker_x_n - 1; i >= 0; i-- )
tsrc[i] = tsrc[i + channels];
for( i = width_n + ker_x_n; i < width_n + ker_width_n; i++ )
tsrc[i] = tsrc[i - channels];
if( channels == 1 )
{
/* horizontal blurring */
if( ker_width == 3 )
{
for( i = 0; i < width_n; i++ )
tdst[i] = tsrc[i+1]*2 + tsrc[i] + tsrc[i + 2];
}
else if( ker_width == 5 )
{
for( i = 0; i < width_n; i++ )
tdst[i] = tsrc[i+2]*6 + (tsrc[i+1] + tsrc[i+3])*4 +
tsrc[i] + tsrc[i+4];
}
else if( ker_width == 7 )
{
for( i = 0; i < width_n; i++ )
tdst[i] = tsrc[i+3]*18 + (tsrc[i+2] + tsrc[i+4])*14 +
(tsrc[i+1] + tsrc[i+5])*7 + (tsrc[i] + tsrc[i+6])*2;
}
}
else if( channels == 3 )
{
/* horizontal blurring */
if( ker_width == 3 )
{
for( i = 0; i < width_n; i += 3 )
{
int t0 = tsrc[i + 3]*2 + tsrc[i] + tsrc[i+6];
int t1 = tsrc[i + 4]*2 + tsrc[i+1] + tsrc[i+7];
int t2 = tsrc[i + 5]*2 + tsrc[i+2] + tsrc[i+8];
tdst[i] = t0;
tdst[i+1] = t1;
tdst[i+2] = t2;
}
}
else if( ker_width == 5 )
{
for( i = 0; i < width_n; i += 3 )
{
int t0 = tsrc[i+6]*6 + (tsrc[i+3] + tsrc[i+9])*4 +
tsrc[i]+tsrc[i+12];
int t1 = tsrc[i+7]*6 + (tsrc[i+4] + tsrc[i+10])*4 +
tsrc[i+1]+tsrc[i+13];
int t2 = tsrc[i+8]*6 + (tsrc[i+5] + tsrc[i+11])*4 +
tsrc[i+2]+tsrc[i+14];
tdst[i] = t0;
tdst[i+1] = t1;
tdst[i+2] = t2;
}
}
else
{
assert( ker_width == 7 );
for( i = 0; i < width_n; i += 3 )
{
int t0 = tsrc[i+9]*18 + (tsrc[i+6] + tsrc[i+12])*14 +
(tsrc[i+3]+tsrc[i+15])*7 + (tsrc[i] + tsrc[i+18])*2;
int t1 = tsrc[i+10]*18 + (tsrc[i+7] + tsrc[i+13])*14 +
(tsrc[i+4]+tsrc[i+16])*7 + (tsrc[i+1] + tsrc[i+19])*2;
int t2 = tsrc[i+11]*18 + (tsrc[i+8] + tsrc[i+14])*14 +
(tsrc[i+5]+tsrc[i+17])*7 + (tsrc[i+2] + tsrc[i+20])*2;
tdst[i] = t0;
tdst[i+1] = t1;
tdst[i+2] = t2;
}
}
}
else /* channels == 4 */
{
/* horizontal blurring */
if( ker_width == 3 )
{
for( i = 0; i < width_n; i += 4 )
{
int t0 = tsrc[i + 4]*2 + tsrc[i] + tsrc[i+8];
int t1 = tsrc[i + 5]*2 + tsrc[i+1] + tsrc[i+9];
int t2 = tsrc[i + 6]*2 + tsrc[i+2] + tsrc[i+10];
int t3 = tsrc[i + 7]*2 + tsrc[i+3] + tsrc[i+11];
tdst[i] = t0;
tdst[i+1] = t1;
tdst[i+2] = t2;
tdst[i+3] = t3;
}
}
else if( ker_width == 5 )
{
for( i = 0; i < width_n; i += 4 )
{
int t0 = tsrc[i+8]*6 + (tsrc[i+4] + tsrc[i+12])*4 +
tsrc[i]+tsrc[i+16];
int t1 = tsrc[i+9]*6 + (tsrc[i+5] + tsrc[i+13])*4 +
tsrc[i+1]+tsrc[i+17];
int t2 = tsrc[i+10]*6 + (tsrc[i+6] + tsrc[i+14])*4 +
tsrc[i+2]+tsrc[i+18];
int t3 = tsrc[i+11]*6 + (tsrc[i+7] + tsrc[i+15])*4 +
tsrc[i+2]+tsrc[i+19];
tdst[i] = t0;
tdst[i+1] = t1;
tdst[i+2] = t2;
tdst[i+3] = t3;
}
}
else
{
assert( ker_width == 7 );
for( i = 0; i < width_n; i += 4 )
{
int t0 = tsrc[i+12]*18 + (tsrc[i+8] + tsrc[i+16])*14 +
(tsrc[i+4]+tsrc[i+20])*7 + (tsrc[i] + tsrc[i+24])*2;
int t1 = tsrc[i+13]*18 + (tsrc[i+9] + tsrc[i+17])*14 +
(tsrc[i+5]+tsrc[i+21])*7 + (tsrc[i+1] + tsrc[i+25])*2;
int t2 = tsrc[i+14]*18 + (tsrc[i+10] + tsrc[i+18])*14 +
(tsrc[i+6]+tsrc[i+22])*7 + (tsrc[i+2] + tsrc[i+26])*2;
int t3 = tsrc[i+15]*18 + (tsrc[i+11] + tsrc[i+19])*14 +
(tsrc[i+7]+tsrc[i+23])*7 + (tsrc[i+3] + tsrc[i+27])*2;
tdst[i] = t0;
tdst[i+1] = t1;
tdst[i+2] = t2;
tdst[i+3] = t3;
}
}
}
if( !need_copy )
{
/* restore borders */
CV_COPY( src - ker_x_n, tbuf - ker_x_n, ker_x_n, x );
CV_COPY( src + width_n, tbuf, ker_right_n, x );
}
}
else
{
CV_COPY( tdst, tsrc + ker_x_n, width_n, x );
}
if( crows < ker_height )
src += srcStep;
}
if( starting_flag )
{
starting_flag = 0;
trow = rows[ker_y];
for( i = 0; i < ker_y; i++ )
{
tdst = rows[i];
CV_COPY( tdst, trow, width_n, x );
}
}
/* vertical convolution */
if( crows != ker_height )
break;
tdst2 = dst;
if( width_rest )
{
need_copy = width_n < CV_MORPH_ALIGN || y == dst_height - 1;
if( need_copy )
tdst2 = tbuf;
else
CV_COPY( tbuf + width_n, dst + width_n, CV_MORPH_ALIGN, x );
}
trow = rows[ker_y];
if( ker_height == 1 )
{
for( x = 0; x < width_n; x += 4 )
{
int val0, val1, val2, val3;
val0 = trow[x];
val1 = trow[x + 1];
val2 = trow[x + 2];
val3 = trow[x + 3];
tdst2[x + 0] = (uchar)((val0 + delta) >> rshift);
tdst2[x + 1] = (uchar)((val1 + delta) >> rshift);
tdst2[x + 2] = (uchar)((val2 + delta) >> rshift);
tdst2[x + 3] = (uchar)((val3 + delta) >> rshift);
}
}
else if( ker_height == 3 )
{
int *trow1 = rows[0], *trow2 = rows[2];
for( x = 0; x < width_n; x += 4 )
{
int val0, val1;
val0 = (trow[x]*2 + trow1[x] + trow2[x] + delta) >> rshift;
val1 = (trow[x + 1]*2 + trow1[x+1] + trow2[x+1] + delta) >> rshift;
tdst2[x + 0] = (uchar)val0;
tdst2[x + 1] = (uchar)val1;
val0 = (trow[x + 2]*2 + trow1[x+2] + trow2[x+2] + delta) >> rshift;
val1 = (trow[x + 3]*2 + trow1[x+3] + trow2[x+3] + delta) >> rshift;
tdst2[x + 2] = (uchar)val0;
tdst2[x + 3] = (uchar)val1;
}
}
else if( ker_height == 5 )
{
int *trow1 = rows[0], *trow2 = rows[1],
*trow3 = rows[3], *trow4 = rows[4];
for( x = 0; x < width_n; x++ )
{
int val0 = (trow[x]*6 + (trow2[x] + trow3[x])*4 +
trow1[x] + trow4[x] + delta) >> rshift;
tdst2[x] = (uchar)val0;
}
}
else
{
int *trow1 = rows[0], *trow2 = rows[1],
*trow3 = rows[2], *trow4 = rows[4],
*trow5 = rows[5], *trow6 = rows[6];
for( x = 0; x < width_n; x++ )
{
int val0 = (trow[x]*18 + (trow3[x] + trow4[x])*14 +
(trow2[x] + trow5[x])*7 + (trow1[x] + trow6[x])*2 + delta) >> rshift;
tdst2[x] = (uchar)val0;
}
}
if( width_rest )
{
if( need_copy )
CV_COPY( dst, tbuf, width_n, x );
else
CV_COPY( dst + width_n, tbuf + width_n, CV_MORPH_ALIGN, x );
}
rows[ker_y] = saved_row;
/* rotate buffer */
{
int *t = rows[0];
CV_COPY( rows, rows + 1, ker_height - 1, i );
rows[i] = t;
crows--;
dst += dstStep;
}
}
while( ++y < dst_height );
roiSize->height = y;
state->crows = crows;
return CV_OK;
}
static CvStatus CV_STDCALL
icvGaussianBlur_8u_CnR( uchar* src, int srcStep,
uchar* dst, int dstStep, CvSize * roiSize,
CvFilterState* state, int stage )
{
if( state->ker_width <= SMALL_GAUSSIAN_SIZE &&
state->ker_height <= SMALL_GAUSSIAN_SIZE &&
ICV_X_KERNEL_TYPE(state->kerType) == ICV_DEFAULT_GAUSSIAN_KERNEL )
{
return icvGaussianBlur_small_8u_CnR( src, srcStep, dst, dstStep,
roiSize, state, stage );
}
else
{
int width = roiSize->width;
int src_height = roiSize->height;
int dst_height = src_height;
int x, y = 0, i;
int ker_width = state->ker_width;
int ker_height = state->ker_height;
int ker_x = ker_width/2;
int ker_y = ker_height/2;
int ker_right = ker_width - ker_x;
int crows = state->crows;
float **rows = (float**)(state->rows);
uchar *tbuf = (uchar*)(state->tbuf);
float *trow = 0;
int channels = state->channels;
int ker_x_n = ker_x * channels;
int ker_right_n = ker_right * channels;
int width_n = width * channels;
int ker_width_n = ker_width * channels;
float* fmaskX = (float*)(state->ker0) + ker_x;
float* fmaskY = (float*)(state->ker1) + ker_y;
double fmX0 = fmaskX[0], fmY0 = fmaskY[0];
int is_small_width = width <= ker_width;
int starting_flag = 0;
int width_rest = width_n & (CV_MORPH_ALIGN - 1);
if( stage == CV_START + CV_END )
stage = CV_WHOLE;
/* initialize cyclic buffer when starting */
if( stage == CV_WHOLE || stage == CV_START )
{
for( i = 0; i < ker_height; i++ )
{
rows[i] = (float*)(state->buffer + state->buffer_step * i);
for( x = width_n; (x&3) != 0; x++ )
rows[i][x] = 0.f;
}
crows = ker_y;
if( stage != CV_WHOLE )
dst_height -= ker_height - ker_y - 1;
starting_flag = 1;
}
if( stage == CV_END )
dst_height += ker_height - ker_y - 1;
do
{
int need_copy = is_small_width | (y == 0);
uchar *tsrc;
float *tdst;
uchar *tdst2;
float *saved_row = rows[ker_y];
/* fill cyclic buffer - horizontal filtering */
for( ; crows < ker_height; crows++ )
{
tsrc = src - ker_x_n;
tdst = rows[crows];
if( src_height-- <= 0 )
{
if( stage != CV_WHOLE && stage != CV_END )
break;
/* duplicate last row */
trow = rows[crows - 1];
CV_COPY( tdst, trow, width_n, x );
continue;
}
need_copy |= src_height == 0;
if( ker_width > 1 )
{
if( need_copy )
{
tsrc = tbuf - ker_x_n;
CV_COPY( tbuf, src, width_n, x );
}
else
{
CV_COPY( tbuf - ker_x_n, src - ker_x_n, ker_x_n, x );
CV_COPY( tbuf, src + width_n, ker_right_n, x );
}
/* make replication borders */
for( i = ker_x_n - 1; i >= 0; i-- )
tsrc[i] = tsrc[i + channels];
for( i = width_n + ker_x_n; i < width_n + ker_width_n; i++ )
tsrc[i] = tsrc[i - channels];
/* horizontal blurring */
if( channels == 1 )
{
for( i = 0; i < width_n; i++ )
{
int j;
double t0 = CV_8TO32F(tsrc[i + ker_x_n])*fmX0;
for( j = 1; j <= ker_x; j++ )
t0 += (CV_8TO32F(tsrc[i+ker_x_n+j]) +
CV_8TO32F(tsrc[i+ker_x_n-j]))*(double)fmaskX[j];
((float*)tdst)[i] = (float)t0;
}
}
else if( channels == 3 )
{
for( i = 0; i < width_n; i += 3 )
{
int j;
double t0 = CV_8TO32F(tsrc[i + ker_x_n])*fmX0;
double t1 = CV_8TO32F(tsrc[i + ker_x_n + 1])*fmX0;
double t2 = CV_8TO32F(tsrc[i + ker_x_n + 2])*fmX0;
for( j = 1; j <= ker_x; j++ )
{
int j3 = j*3;
double m = fmaskX[j];
t0 += (CV_8TO32F(tsrc[i+ker_x_n+j3]) +
CV_8TO32F(tsrc[i+ker_x_n-j3]))*m;
t1 += (CV_8TO32F(tsrc[i+ker_x_n+j3+1]) +
CV_8TO32F(tsrc[i+ker_x_n-j3+1]))*m;
t2 += (CV_8TO32F(tsrc[i+ker_x_n+j3+2]) +
CV_8TO32F(tsrc[i+ker_x_n-j3+2]))*m;
}
tdst[i] = (float)t0;
tdst[i+1] = (float)t1;
tdst[i+2] = (float)t2;
}
}
else /* channels == 4 */
{
for( i = 0; i < width_n; i += 4 )
{
int j;
double t0 = CV_8TO32F(tsrc[i + ker_x_n])*fmX0;
double t1 = CV_8TO32F(tsrc[i + ker_x_n + 1])*fmX0;
double t2 = CV_8TO32F(tsrc[i + ker_x_n + 2])*fmX0;
double t3 = CV_8TO32F(tsrc[i + ker_x_n + 3])*fmX0;
for( j = 1; j <= ker_x; j++ )
{
int j4 = j*4;
double m = fmaskX[j];
t0 += (CV_8TO32F(tsrc[i+ker_x_n+j4]) +
CV_8TO32F(tsrc[i+ker_x_n-j4]))*m;
t1 += (CV_8TO32F(tsrc[i+ker_x_n+j4+1]) +
CV_8TO32F(tsrc[i+ker_x_n-j4+1]))*m;
t2 += (CV_8TO32F(tsrc[i+ker_x_n+j4+2]) +
CV_8TO32F(tsrc[i+ker_x_n-j4+2]))*m;
t3 += (CV_8TO32F(tsrc[i+ker_x_n+j4+3]) +
CV_8TO32F(tsrc[i+ker_x_n-j4+3]))*m;
}
tdst[i] = (float)t0;
tdst[i+1] = (float)t1;
tdst[i+2] = (float)t2;
tdst[i+3] = (float)t3;
}
}
if( !need_copy )
{
/* restore borders */
CV_COPY( src - ker_x_n, tbuf - ker_x_n, ker_x_n, x );
CV_COPY( src + width_n, tbuf, ker_right_n, x );
}
}
else
{
CV_COPY( tdst, tsrc + ker_x_n, width_n, x );
}
if( crows < ker_height )
src += srcStep;
}
if( starting_flag )
{
starting_flag = 0;
trow = rows[ker_y];
for( i = 0; i < ker_y; i++ )
{
tdst = rows[i];
CV_COPY( tdst, trow, width_n, x );
}
}
/* vertical convolution */
if( crows != ker_height )
break;
tdst2 = dst;
if( width_rest )
{
need_copy = width_n < CV_MORPH_ALIGN || y == dst_height - 1;
if( need_copy )
tdst2 = tbuf;
else
CV_COPY( tbuf + width_n, dst + width_n, CV_MORPH_ALIGN, x );
}
trow = rows[ker_y];
for( x = 0; x < width_n; x += 4 )
{
double val0, val1, val2, val3;
val0 = trow[x]*fmY0;
val1 = trow[x + 1]*fmY0;
val2 = trow[x + 2]*fmY0;
val3 = trow[x + 3]*fmY0;
for( i = 1; i <= ker_y; i++ )
{
float *trow1, *trow2;
double m = fmaskY[i];
trow1 = rows[ker_y - i];
trow2 = rows[ker_y + i];
val0 += (trow1[x] + trow2[x])*m;
val1 += (trow1[x+1] + trow2[x+1])*m;
val2 += (trow1[x+2] + trow2[x+2])*m;
val3 += (trow1[x+3] + trow2[x+3])*m;
}
tdst2[x + 0] = (uchar)cvRound(val0);
tdst2[x + 1] = (uchar)cvRound(val1);
tdst2[x + 2] = (uchar)cvRound(val2);
tdst2[x + 3] = (uchar)cvRound(val3);
}
if( width_rest )
{
if( need_copy )
CV_COPY( dst, tbuf, width_n, x );
else
CV_COPY( dst + width_n, tbuf + width_n, CV_MORPH_ALIGN, x );
}
rows[ker_y] = saved_row;
/* rotate buffer */
{
float *t = rows[0];
CV_COPY( rows, rows + 1, ker_height - 1, i );
rows[i] = t;
crows--;
dst += dstStep;
}
}
while( ++y < dst_height );
roiSize->height = y;
state->crows = crows;
return CV_OK;
}
}
static CvStatus CV_STDCALL
icvGaussianBlur_32f_CnR( float* src, int srcStep,
float* dst, int dstStep, CvSize * roiSize,
CvFilterState* state, int stage )
{
int width = roiSize->width;
int src_height = roiSize->height;
int dst_height = src_height;
int x, y = 0, i;
int ker_width = state->ker_width;
int ker_height = state->ker_height;
int ker_x = ker_width/2;
int ker_y = ker_height/2;
int ker_right = ker_width - ker_x;
int crows = state->crows;
float **rows = (float**)(state->rows);
float *tbuf = (float*)(state->tbuf);
float *trow = 0;
int channels = state->channels;
int ker_x_n = ker_x * channels;
int ker_right_n = ker_right * channels;
int width_n = width * channels;
int ker_width_n = ker_width * channels;
float* fmaskX = (float*)(state->ker0) + ker_x;
float* fmaskY = (float*)(state->ker1) + ker_y;
double fmX0 = fmaskX[0], fmY0 = fmaskY[0];
int is_small_width = width <= ker_width;
int starting_flag = 0;
int width_rest = width_n & (CV_MORPH_ALIGN - 1);
srcStep /= sizeof(src[0]);
dstStep /= sizeof(dst[0]);
if( stage == CV_START + CV_END )
stage = CV_WHOLE;
/* initialize cyclic buffer when starting */
if( stage == CV_WHOLE || stage == CV_START )
{
for( i = 0; i < ker_height; i++ )
{
rows[i] = (float*)(state->buffer + state->buffer_step * i);
for( x = width_n; (x&3) != 0; x++ )
rows[i][x] = 0.f;
}
crows = ker_y;
if( stage != CV_WHOLE )
dst_height -= ker_height - ker_y - 1;
starting_flag = 1;
}
if( stage == CV_END )
dst_height += ker_height - ker_y - 1;
do
{
int need_copy = is_small_width | (y == 0);
float *tsrc;
float *tdst;
float *tdst2;
float *saved_row = rows[ker_y];
/* fill cyclic buffer - horizontal filtering */
for( ; crows < ker_height; crows++ )
{
tsrc = src - ker_x_n;
tdst = rows[crows];
if( src_height-- <= 0 )
{
if( stage != CV_WHOLE && stage != CV_END )
break;
/* duplicate last row */
trow = rows[crows - 1];
CV_COPY( tdst, trow, width_n, x );
continue;
}
need_copy |= src_height == 0;
if( ker_width > 1 )
{
if( need_copy )
{
tsrc = tbuf - ker_x_n;
CV_COPY( tbuf, src, width_n, x );
}
else
{
CV_COPY( tbuf - ker_x_n, src - ker_x_n, ker_x_n, x );
CV_COPY( tbuf, src + width_n, ker_right_n, x );
}
/* make replication borders */
for( i = ker_x_n - 1; i >= 0; i-- )
tsrc[i] = tsrc[i + channels];
for( i = width_n + ker_x_n; i < width_n + ker_width_n; i++ )
tsrc[i] = tsrc[i - channels];
/* horizontal blurring */
if( channels == 1 )
{
for( i = 0; i < width_n; i++ )
{
int j;
double t0 = (tsrc[i + ker_x_n])*fmX0;
for( j = 1; j <= ker_x; j++ )
t0 += ((tsrc[i+ker_x_n+j]) +
(tsrc[i+ker_x_n-j]))*(double)fmaskX[j];
((float*)tdst)[i] = (float)t0;
}
}
else if( channels == 3 )
{
for( i = 0; i < width_n; i += 3 )
{
int j;
double t0 = (tsrc[i + ker_x_n])*fmX0;
double t1 = (tsrc[i + ker_x_n + 1])*fmX0;
double t2 = (tsrc[i + ker_x_n + 2])*fmX0;
for( j = 1; j <= ker_x; j++ )
{
int j3 = j*3;
double m = fmaskX[j];
t0 += ((tsrc[i+ker_x_n+j3]) +
(tsrc[i+ker_x_n-j3]))*m;
t1 += ((tsrc[i+ker_x_n+j3+1]) +
(tsrc[i+ker_x_n-j3+1]))*m;
t2 += ((tsrc[i+ker_x_n+j3+2]) +
(tsrc[i+ker_x_n-j3+2]))*m;
}
tdst[i] = (float)t0;
tdst[i+1] = (float)t1;
tdst[i+2] = (float)t2;
}
}
else /* channels == 4 */
{
for( i = 0; i < width_n; i += 4 )
{
int j;
double t0 = (tsrc[i + ker_x_n])*fmX0;
double t1 = (tsrc[i + ker_x_n + 1])*fmX0;
double t2 = (tsrc[i + ker_x_n + 2])*fmX0;
double t3 = (tsrc[i + ker_x_n + 3])*fmX0;
for( j = 1; j <= ker_x; j++ )
{
int j4 = j*4;
double m = fmaskX[j];
t0 += ((tsrc[i+ker_x_n+j4]) +
(tsrc[i+ker_x_n-j4]))*m;
t1 += ((tsrc[i+ker_x_n+j4+1]) +
(tsrc[i+ker_x_n-j4+1]))*m;
t2 += ((tsrc[i+ker_x_n+j4+2]) +
(tsrc[i+ker_x_n-j4+2]))*m;
t3 += ((tsrc[i+ker_x_n+j4+3]) +
(tsrc[i+ker_x_n-j4+3]))*m;
}
tdst[i] = (float)t0;
tdst[i+1] = (float)t1;
tdst[i+2] = (float)t2;
tdst[i+3] = (float)t3;
}
}
if( !need_copy )
{
/* restore borders */
CV_COPY( src - ker_x_n, tbuf - ker_x_n, ker_x_n, x );
CV_COPY( src + width_n, tbuf, ker_right_n, x );
}
}
else
{
CV_COPY( tdst, tsrc + ker_x_n, width_n, x );
}
if( crows < ker_height )
src += srcStep;
}
if( starting_flag )
{
starting_flag = 0;
trow = rows[ker_y];
for( i = 0; i < ker_y; i++ )
{
tdst = rows[i];
CV_COPY( tdst, trow, width_n, x );
}
}
/* vertical convolution */
if( crows != ker_height )
break;
tdst2 = dst;
if( width_rest )
{
need_copy = width_n < CV_MORPH_ALIGN || y == dst_height - 1;
if( need_copy )
tdst2 = tbuf;
else
CV_COPY( tbuf + width_n, dst + width_n, CV_MORPH_ALIGN, x );
}
trow = rows[ker_y];
for( x = 0; x < width_n; x += 4 )
{
double val0, val1, val2, val3;
val0 = trow[x]*fmY0;
val1 = trow[x + 1]*fmY0;
val2 = trow[x + 2]*fmY0;
val3 = trow[x + 3]*fmY0;
for( i = 1; i <= ker_y; i++ )
{
float *trow1, *trow2;
double m = fmaskY[i];
trow1 = rows[ker_y - i];
trow2 = rows[ker_y + i];
val0 += (trow1[x] + trow2[x])*m;
val1 += (trow1[x+1] + trow2[x+1])*m;
val2 += (trow1[x+2] + trow2[x+2])*m;
val3 += (trow1[x+3] + trow2[x+3])*m;
}
tdst2[x + 0] = (float)val0;
tdst2[x + 1] = (float)val1;
tdst2[x + 2] = (float)val2;
tdst2[x + 3] = (float)val3;
}
if( width_rest )
{
if( need_copy )
CV_COPY( dst, tbuf, width_n, x );
else
CV_COPY( dst + width_n, tbuf + width_n, CV_MORPH_ALIGN, x );
}
rows[ker_y] = saved_row;
/* rotate buffer */
{
float *t = rows[0];
CV_COPY( rows, rows + 1, ker_height - 1, i );
rows[i] = t;
crows--;
dst += dstStep;
}
}
while( ++y < dst_height );
roiSize->height = y;
state->crows = crows;
return CV_OK;
}
/****************************************************************************************\
Median Filter
\****************************************************************************************/
#define CV_MINMAX_8U(a,b) \
(t = CV_FAST_CAST_8U((a) - (b)), (b) += t, a -= t)
static CvStatus CV_STDCALL
icvMedianBlur_8u_CnR( uchar* src, int src_step, uchar* dst, int dst_step,
CvSize* roiSize, int* param, int /*stub */ )
{
#define N 16
int zone0[4][N];
int zone1[4][N*N];
int x, y;
int cn = param[0];
int m = param[1], n2 = m*m/2;
int nx = (m + 1)/2 - 1;
CvSize size = *roiSize;
uchar* src_max = src + size.height*src_step;
uchar* src_right = src + size.width*cn;
#define UPDATE_ACC01( pix, cn, op ) \
{ \
int p = (pix); \
zone1[cn][p] op; \
zone0[cn][p >> 4] op; \
}
if( size.height < nx || size.width < nx )
return CV_BADSIZE_ERR;
if( m == 3 )
{
size.width *= cn;
for( y = 0; y < size.height; y++, dst += dst_step )
{
const uchar* src0 = src + src_step*(y-1);
const uchar* src1 = src0 + src_step;
const uchar* src2 = src1 + src_step;
if( y == 0 )
src0 = src1;
else if( y == size.height - 1 )
src2 = src1;
for( x = 0; x < 2*cn; x++ )
{
int x0 = x < cn ? x : size.width - 3*cn + x;
int x2 = x < cn ? x + cn : size.width - 2*cn + x;
int x1 = x < cn ? x0 : x2, t;
int p0 = src0[x0], p1 = src0[x1], p2 = src0[x2];
int p3 = src1[x0], p4 = src1[x1], p5 = src1[x2];
int p6 = src2[x0], p7 = src2[x1], p8 = src2[x2];
CV_MINMAX_8U(p1, p2);
CV_MINMAX_8U(p4, p5);
CV_MINMAX_8U(p7, p8);
CV_MINMAX_8U(p0, p1);
CV_MINMAX_8U(p3, p4);
CV_MINMAX_8U(p6, p7);
CV_MINMAX_8U(p1, p2);
CV_MINMAX_8U(p4, p5);
CV_MINMAX_8U(p7, p8);
CV_MINMAX_8U(p0, p3);
CV_MINMAX_8U(p5, p8);
CV_MINMAX_8U(p4, p7);
CV_MINMAX_8U(p3, p6);
CV_MINMAX_8U(p1, p4);
CV_MINMAX_8U(p2, p5);
CV_MINMAX_8U(p4, p7);
CV_MINMAX_8U(p4, p2);
CV_MINMAX_8U(p6, p4);
CV_MINMAX_8U(p4, p2);
dst[x1] = (uchar)p4;
}
for( x = cn; x < size.width - cn; x++ )
{
int p0 = src0[x-cn], p1 = src0[x], p2 = src0[x+cn];
int p3 = src1[x-cn], p4 = src1[x], p5 = src1[x+cn];
int p6 = src2[x-cn], p7 = src2[x], p8 = src2[x+cn];
int t;
CV_MINMAX_8U(p1, p2);
CV_MINMAX_8U(p4, p5);
CV_MINMAX_8U(p7, p8);
CV_MINMAX_8U(p0, p1);
CV_MINMAX_8U(p3, p4);
CV_MINMAX_8U(p6, p7);
CV_MINMAX_8U(p1, p2);
CV_MINMAX_8U(p4, p5);
CV_MINMAX_8U(p7, p8);
CV_MINMAX_8U(p0, p3);
CV_MINMAX_8U(p5, p8);
CV_MINMAX_8U(p4, p7);
CV_MINMAX_8U(p3, p6);
CV_MINMAX_8U(p1, p4);
CV_MINMAX_8U(p2, p5);
CV_MINMAX_8U(p4, p7);
CV_MINMAX_8U(p4, p2);
CV_MINMAX_8U(p6, p4);
CV_MINMAX_8U(p4, p2);
dst[x] = (uchar)p4;
}
}
return CV_OK;
}
for( x = 0; x < size.width; x++, dst += cn )
{
uchar* dst_cur = dst;
uchar* src_top = src;
uchar* src_bottom = src;
int k, c;
int x0 = -1;
if( x <= m/2 )
nx++;
if( nx < m )
x0 = x < m/2 ? 0 : (nx-1)*cn;
// init accumulator
memset( zone0, 0, sizeof(zone0[0])*cn );
memset( zone1, 0, sizeof(zone1[0])*cn );
for( y = -m/2; y < m/2; y++ )
{
for( c = 0; c < cn; c++ )
{
if( x0 >= 0 )
UPDATE_ACC01( src_bottom[x0+c], c, += (m - nx) );
for( k = 0; k < nx*cn; k += cn )
UPDATE_ACC01( src_bottom[k+c], c, ++ );
}
if( (unsigned)y < (unsigned)(size.height-1) )
src_bottom += src_step;
}
for( y = 0; y < size.height; y++, dst_cur += dst_step )
{
if( cn == 1 )
{
for( k = 0; k < nx; k++ )
UPDATE_ACC01( src_bottom[k], 0, ++ );
}
else if( cn == 3 )
{
for( k = 0; k < nx*3; k += 3 )
{
UPDATE_ACC01( src_bottom[k], 0, ++ );
UPDATE_ACC01( src_bottom[k+1], 1, ++ );
UPDATE_ACC01( src_bottom[k+2], 2, ++ );
}
}
else
{
assert( cn == 4 );
for( k = 0; k < nx*4; k += 4 )
{
UPDATE_ACC01( src_bottom[k], 0, ++ );
UPDATE_ACC01( src_bottom[k+1], 1, ++ );
UPDATE_ACC01( src_bottom[k+2], 2, ++ );
UPDATE_ACC01( src_bottom[k+3], 3, ++ );
}
}
if( x0 >= 0 )
{
for( c = 0; c < cn; c++ )
UPDATE_ACC01( src_bottom[x0+c], c, += (m - nx) );
}
if( src_bottom + src_step < src_max )
src_bottom += src_step;
// find median
for( c = 0; c < cn; c++ )
{
int s = 0;
for( k = 0; ; k++ )
{
int t = s + zone0[c][k];
if( t > n2 ) break;
s = t;
}
for( k *= N; ;k++ )
{
s += zone1[c][k];
if( s > n2 ) break;
}
dst_cur[c] = (uchar)k;
}
if( cn == 1 )
{
for( k = 0; k < nx; k++ )
UPDATE_ACC01( src_top[k], 0, -- );
}
else if( cn == 3 )
{
for( k = 0; k < nx*3; k += 3 )
{
UPDATE_ACC01( src_top[k], 0, -- );
UPDATE_ACC01( src_top[k+1], 1, -- );
UPDATE_ACC01( src_top[k+2], 2, -- );
}
}
else
{
assert( cn == 4 );
for( k = 0; k < nx*4; k += 4 )
{
UPDATE_ACC01( src_top[k], 0, -- );
UPDATE_ACC01( src_top[k+1], 1, -- );
UPDATE_ACC01( src_top[k+2], 2, -- );
UPDATE_ACC01( src_top[k+3], 3, -- );
}
}
if( x0 >= 0 )
{
for( c = 0; c < cn; c++ )
UPDATE_ACC01( src_top[x0+c], c, -= (m - nx) );
}
if( y >= m/2 )
src_top += src_step;
}
if( x >= m/2 )
src += cn;
if( src + nx*cn > src_right ) nx--;
}
#undef N
#undef UPDATE_ACC
return CV_OK;
}
/****************************************************************************************\
Bilateral Filtering
\****************************************************************************************/
static CvStatus CV_STDCALL
icvBilateralFiltering_8u_CnR( uchar* src, int srcStep,
uchar* dst, int dstStep,
CvSize* roiSize, int* param, int /*stub*/ )
{
CvSize size = *roiSize;
int channels = param[0];
double sigma_color = param[1];
double sigma_space = param[2];
double i2sigma_color = 1./(sigma_color*sigma_color);
double i2sigma_space = 1./(sigma_space*sigma_space);
double mean1[3];
double mean0;
double w;
int deltas[8];
double weight_tab[8];
int i, j;
#define INIT_C1\
color = src[0]; \
mean0 = 1; mean1[0] = color;
#define COLOR_DISTANCE_C1(c1, c2)\
(c1 - c2)*(c1 - c2)
#define KERNEL_ELEMENT_C1(k)\
temp_color = src[deltas[k]];\
w = weight_tab[k] + COLOR_DISTANCE_C1(color, temp_color)*i2sigma_color;\
w = 1./(w*w + 1); \
mean0 += w;\
mean1[0] += temp_color*w;
#define INIT_C3\
mean0 = 1; mean1[0] = src[0];mean1[1] = src[1];mean1[2] = src[2];
#define UPDATE_OUTPUT_C1 \
dst[i] = (uchar)cvRound(mean1[0]/mean0);
#define COLOR_DISTANCE_C3(c1, c2)\
((c1[0] - c2[0])*(c1[0] - c2[0]) + \
(c1[1] - c2[1])*(c1[1] - c2[1]) + \
(c1[2] - c2[2])*(c1[2] - c2[2]))
#define KERNEL_ELEMENT_C3(k)\
temp_color = src + deltas[k];\
w = weight_tab[k] + COLOR_DISTANCE_C3(src, temp_color)*i2sigma_color;\
w = 1./(w*w + 1); \
mean0 += w;\
mean1[0] += temp_color[0]*w; \
mean1[1] += temp_color[1]*w; \
mean1[2] += temp_color[2]*w;
#define UPDATE_OUTPUT_C3\
mean0 = 1./mean0;\
dst[i*3 + 0] = (uchar)cvRound(mean1[0]*mean0); \
dst[i*3 + 1] = (uchar)cvRound(mean1[1]*mean0); \
dst[i*3 + 2] = (uchar)cvRound(mean1[2]*mean0);
CV_INIT_3X3_DELTAS( deltas, srcStep, channels );
weight_tab[0] = weight_tab[2] = weight_tab[4] = weight_tab[6] = i2sigma_space;
weight_tab[1] = weight_tab[3] = weight_tab[5] = weight_tab[7] = i2sigma_space*2;
if( channels == 1 )
{
int color, temp_color;
for( i = 0; i < size.width; i++, src++ )
{
INIT_C1;
KERNEL_ELEMENT_C1(6);
if( i > 0 )
{
KERNEL_ELEMENT_C1(5);
KERNEL_ELEMENT_C1(4);
}
if( i < size.width - 1 )
{
KERNEL_ELEMENT_C1(7);
KERNEL_ELEMENT_C1(0);
}
UPDATE_OUTPUT_C1;
}
src += srcStep - size.width;
dst += dstStep;
for( j = 1; j < size.height - 1; j++, dst += dstStep )
{
i = 0;
INIT_C1;
KERNEL_ELEMENT_C1(0);
KERNEL_ELEMENT_C1(1);
KERNEL_ELEMENT_C1(2);
KERNEL_ELEMENT_C1(6);
KERNEL_ELEMENT_C1(7);
UPDATE_OUTPUT_C1;
for( i = 1, src++; i < size.width - 1; i++, src++ )
{
INIT_C1;
KERNEL_ELEMENT_C1(0);
KERNEL_ELEMENT_C1(1);
KERNEL_ELEMENT_C1(2);
KERNEL_ELEMENT_C1(3);
KERNEL_ELEMENT_C1(4);
KERNEL_ELEMENT_C1(5);
KERNEL_ELEMENT_C1(6);
KERNEL_ELEMENT_C1(7);
UPDATE_OUTPUT_C1;
}
INIT_C1;
KERNEL_ELEMENT_C1(2);
KERNEL_ELEMENT_C1(3);
KERNEL_ELEMENT_C1(4);
KERNEL_ELEMENT_C1(5);
KERNEL_ELEMENT_C1(6);
UPDATE_OUTPUT_C1;
src += srcStep + 1 - size.width;
}
for( i = 0; i < size.width; i++, src++ )
{
INIT_C1;
KERNEL_ELEMENT_C1(2);
if( i > 0 )
{
KERNEL_ELEMENT_C1(3);
KERNEL_ELEMENT_C1(4);
}
if( i < size.width - 1 )
{
KERNEL_ELEMENT_C1(1);
KERNEL_ELEMENT_C1(0);
}
UPDATE_OUTPUT_C1;
}
}
else
{
uchar* temp_color;
if( channels != 3 )
return CV_UNSUPPORTED_CHANNELS_ERR;
for( i = 0; i < size.width; i++, src += 3 )
{
INIT_C3;
KERNEL_ELEMENT_C3(6);
if( i > 0 )
{
KERNEL_ELEMENT_C3(5);
KERNEL_ELEMENT_C3(4);
}
if( i < size.width - 1 )
{
KERNEL_ELEMENT_C3(7);
KERNEL_ELEMENT_C3(0);
}
UPDATE_OUTPUT_C3;
}
src += srcStep - size.width*3;
dst += dstStep;
for( j = 1; j < size.height - 1; j++, dst += dstStep )
{
i = 0;
INIT_C3;
KERNEL_ELEMENT_C3(0);
KERNEL_ELEMENT_C3(1);
KERNEL_ELEMENT_C3(2);
KERNEL_ELEMENT_C3(6);
KERNEL_ELEMENT_C3(7);
UPDATE_OUTPUT_C3;
for( i = 1, src += 3; i < size.width - 1; i++, src += 3 )
{
INIT_C3;
KERNEL_ELEMENT_C3(0);
KERNEL_ELEMENT_C3(1);
KERNEL_ELEMENT_C3(2);
KERNEL_ELEMENT_C3(3);
KERNEL_ELEMENT_C3(4);
KERNEL_ELEMENT_C3(5);
KERNEL_ELEMENT_C3(6);
KERNEL_ELEMENT_C3(7);
UPDATE_OUTPUT_C3;
}
INIT_C3;
KERNEL_ELEMENT_C3(2);
KERNEL_ELEMENT_C3(3);
KERNEL_ELEMENT_C3(4);
KERNEL_ELEMENT_C3(5);
KERNEL_ELEMENT_C3(6);
UPDATE_OUTPUT_C3;
src += srcStep + 3 - size.width*3;
}
for( i = 0; i < size.width; i++, src += 3 )
{
INIT_C3;
KERNEL_ELEMENT_C3(2);
if( i > 0 )
{
KERNEL_ELEMENT_C3(3);
KERNEL_ELEMENT_C3(4);
}
if( i < size.width - 1 )
{
KERNEL_ELEMENT_C3(1);
KERNEL_ELEMENT_C3(0);
}
UPDATE_OUTPUT_C3;
}
}
return CV_OK;
#undef INIT_C1
#undef KERNEL_ELEMENT_C1
#undef UPDATE_OUTPUT_C1
#undef INIT_C3
#undef KERNEL_ELEMENT_C3
#undef UPDATE_OUTPUT_C3
#undef COLOR_DISTANCE_C3
}
static void icvInitSmoothTab( CvFuncTable* blur_no_scale_tab,
CvFuncTable* blur_tab, CvFuncTable* gaussian_tab,
CvFuncTable* median_tab, CvFuncTable* bilateral_tab )
{
blur_no_scale_tab->fn_2d[CV_8U] = (void*)icvBlur_8u16s_C1R;
blur_no_scale_tab->fn_2d[CV_32F] = (void*)icvBlur_32f_CnR;
blur_tab->fn_2d[CV_8U] = (void*)icvBlur_8u_CnR;
blur_tab->fn_2d[CV_32F] = (void*)icvBlur_32f_CnR;
gaussian_tab->fn_2d[CV_8U] = (void*)icvGaussianBlur_8u_CnR;
gaussian_tab->fn_2d[CV_32F] = (void*)icvGaussianBlur_32f_CnR;
median_tab->fn_2d[CV_8U] = (void*)icvMedianBlur_8u_CnR;
bilateral_tab->fn_2d[CV_8U] = (void*)icvBilateralFiltering_8u_CnR;
}
//////////////////////////////// IPP smoothing functions /////////////////////////////////
icvFilterMedian_8u_C1R_t icvFilterMedian_8u_C1R_p = 0;
icvFilterMedian_8u_C3R_t icvFilterMedian_8u_C3R_p = 0;
icvFilterMedian_8u_C4R_t icvFilterMedian_8u_C4R_p = 0;
icvFilterBox_8u_C1R_t icvFilterBox_8u_C1R_p = 0;
icvFilterBox_8u_C3R_t icvFilterBox_8u_C3R_p = 0;
icvFilterBox_8u_C4R_t icvFilterBox_8u_C4R_p = 0;
icvFilterBox_32f_C1R_t icvFilterBox_32f_C1R_p = 0;
icvFilterBox_32f_C3R_t icvFilterBox_32f_C3R_p = 0;
icvFilterBox_32f_C4R_t icvFilterBox_32f_C4R_p = 0;
typedef CvStatus (CV_STDCALL * CvSmoothFixedIPPFunc)
( const void* src, int srcstep, void* dst, int dststep,
CvSize size, CvSize ksize, CvPoint anchor );
//////////////////////////////////////////////////////////////////////////////////////////
CV_IMPL void
cvSmooth( const void* srcarr, void* dstarr, int smoothtype,
int param1, int param2, double param3 )
{
static CvFuncTable smooth_tab[5];
static int inittab = 0;
CvFilterState *state = 0;
CvMat* temp = 0;
CV_FUNCNAME( "cvSmooth" );
__BEGIN__;
CvFilterFunc func = 0;
int coi1 = 0, coi2 = 0;
CvMat srcstub, *src = (CvMat*)srcarr;
CvMat dststub, *dst = (CvMat*)dstarr;
CvSize size;
int type, depth, dsttype;
int src_step, dst_step;
int nonlin_param[] = { 0, param1, param2 };
void* ptr = nonlin_param;
double sigma = 0;
if( !inittab )
{
icvInitSmoothTab( smooth_tab + CV_BLUR_NO_SCALE, smooth_tab + CV_BLUR,
smooth_tab + CV_GAUSSIAN, smooth_tab + CV_MEDIAN,
smooth_tab + CV_BILATERAL );
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, "" );
type = CV_MAT_TYPE( src->type );
dsttype = CV_MAT_TYPE( dst->type );
if( smoothtype > 0 && !CV_ARE_TYPES_EQ( src, dst ) ||
smoothtype == 0 &&
!(type == CV_8UC1 && dsttype == CV_16SC1 ||
type == CV_32FC1 && dsttype == CV_32FC1 ))
CV_ERROR( CV_StsUnmatchedFormats, "" );
if( !CV_ARE_SIZES_EQ( src, dst ))
CV_ERROR( CV_StsUnmatchedSizes, "" );
size = cvGetMatSize( src );
depth = CV_MAT_DEPTH(type);
nonlin_param[0] = CV_MAT_CN(type);
if( (unsigned)smoothtype > CV_BILATERAL )
CV_ERROR( CV_StsBadArg, "Unsupported smoothing type" );
if( (smoothtype == CV_MEDIAN || smoothtype == CV_BILATERAL) &&
src->data.ptr == dst->data.ptr )
CV_ERROR( CV_StsBadArg,
"Inplace operation is not supported for that type of smoothing" );
if( smoothtype == CV_BILATERAL )
{
if( param1 < 0 || param2 < 0 )
CV_ERROR( CV_StsOutOfRange,
"Thresholds in bilaral filtering should not bee negative" );
param1 += param1 == 0;
param2 += param2 == 0;
}
else /* simple blurring, gaussian, median */
{
sigma = param3;
// automatic detection of kernel size from sigma
if( smoothtype == CV_GAUSSIAN && param1 == 0 && sigma > 0 )
param1 = cvRound(sigma*(depth == CV_8U ? 3 : 4)*2 + 1)|1;
if( param2 == 0 )
param2 = size.height == 1 ? 1 : param1;
if( param1 < 1 || (param1 & 1) == 0 || param2 < 1 || (param2 & 1) == 0 )
CV_ERROR( CV_StsOutOfRange,
"One of aperture dimensions is incorrect (should be >=1 and odd)" );
if( param1 == 1 && param2 == 1 && CV_ARE_TYPES_EQ(src,dst) )
{
cvCopy( src, dst );
EXIT;
}
}
src_step = src->step;
dst_step = dst->step;
if( size.height == 1 )
src_step = dst_step = CV_STUB_STEP;
if( CV_MAT_CN(type) == 2 )
CV_ERROR( CV_BadNumChannels, "Unsupported number of channels" );
if( (smoothtype == CV_BLUR || smoothtype == CV_MEDIAN) && icvFilterBox_8u_C1R_p &&
size.width >= param1 && size.height >= param2 && param1 > 1 && param2 > 1 )
{
CvSmoothFixedIPPFunc ipp_median_box_func = 0;
if( smoothtype == CV_BLUR )
{
ipp_median_box_func =
type == CV_8UC1 ? icvFilterBox_8u_C1R_p :
type == CV_8UC3 ? icvFilterBox_8u_C3R_p :
type == CV_8UC4 ? icvFilterBox_8u_C4R_p :
type == CV_32FC1 ? icvFilterBox_32f_C1R_p :
type == CV_32FC3 ? icvFilterBox_32f_C3R_p :
type == CV_32FC4 ? icvFilterBox_32f_C4R_p : 0;
}
else if( smoothtype == CV_MEDIAN )
{
ipp_median_box_func =
type == CV_8UC1 ? icvFilterMedian_8u_C1R_p :
type == CV_8UC3 ? icvFilterMedian_8u_C3R_p :
type == CV_8UC4 ? icvFilterMedian_8u_C4R_p : 0;
}
if( ipp_median_box_func )
{
CvSize el_size = { param1, param2 };
CvPoint el_anchor = { param1/2, param2/2 };
int stripe_size = 1 << 14; // the optimal value may depend on CPU cache,
// overhead of current IPP code etc.
const uchar* shifted_ptr;
int y, dy = 0;
int temp_step;
CV_CALL( temp = icvIPPFilterInit( src, stripe_size, el_size ));
shifted_ptr = temp->data.ptr +
el_anchor.y*temp->step + el_anchor.x*CV_ELEM_SIZE(type);
temp_step = temp->step ? temp->step : CV_STUB_STEP;
for( y = 0; y < src->rows; y += dy )
{
dy = icvIPPFilterNextStripe( src, temp, y, el_size, el_anchor );
IPPI_CALL( ipp_median_box_func( shifted_ptr, temp_step,
dst->data.ptr + y*dst_step, dst_step, cvSize(src->cols, dy),
el_size, el_anchor ));
}
EXIT;
}
}
else if( smoothtype == CV_GAUSSIAN &&
icvFilterBox_8u_C1R_p /* this is to check that IPP is loaded */ &&
size.width >= param1*3 && size.height >= param2 && param1 > 1 && param2 > 1 )
{
CvSize ksize = { param1, param2 };
float* kx = (float*)cvStackAlloc( ksize.width*sizeof(kx[0]) );
float* ky = (float*)cvStackAlloc( ksize.height*sizeof(ky[0]) );
CvMat KX = cvMat( 1, ksize.width, CV_32F, kx );
CvMat KY = cvMat( 1, ksize.height, CV_32F, ky );
int done = 0;
icvCalcGaussianKernel( ksize.width, sigma, kx );
if( ksize.width != ksize.height )
icvCalcGaussianKernel( ksize.height, sigma, ky );
else
KY.data.fl = kx;
CV_CALL( done = icvIPPSepFilter( src, dst, &KX, &KY,
cvPoint(ksize.width/2,ksize.height/2)));
if( done )
EXIT;
}
if( smoothtype <= CV_GAUSSIAN )
{
CV_CALL( state = icvSmoothInitAlloc( src->width, depth < CV_32F ? cv32s : cv32f,
CV_MAT_CN(type), cvSize(param1, smoothtype <= CV_GAUSSIAN ? param2 : param1),
smoothtype, sigma ));
ptr = state;
}
func = (CvFilterFunc)(smooth_tab[smoothtype].fn_2d[depth]);
if( !func )
CV_ERROR( CV_StsUnsupportedFormat, "" );
IPPI_CALL( func( src->data.ptr, src_step, dst->data.ptr,
dst_step, &size, (CvFilterState*)ptr, 0 ));
__END__;
cvReleaseMat( &temp );
icvSmoothFree( &state );
}
/* End of file. */