1/*M///////////////////////////////////////////////////////////////////////////////////////
2//
3//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4//
5//  By downloading, copying, installing or using the software you agree to this license.
6//  If you do not agree to this license, do not download, install,
7//  copy or use the software.
8//
9//
10//                        Intel License Agreement
11//                For Open Source Computer Vision Library
12//
13// Copyright (C) 2000, Intel Corporation, all rights reserved.
14// Third party copyrights are property of their respective owners.
15//
16// Redistribution and use in source and binary forms, with or without modification,
17// are permitted provided that the following conditions are met:
18//
19//   * Redistribution's of source code must retain the above copyright notice,
20//     this list of conditions and the following disclaimer.
21//
22//   * Redistribution's in binary form must reproduce the above copyright notice,
23//     this list of conditions and the following disclaimer in the documentation
24//     and/or other materials provided with the distribution.
25//
26//   * The name of Intel Corporation may not be used to endorse or promote products
27//     derived from this software without specific prior written permission.
28//
29// This software is provided by the copyright holders and contributors "as is" and
30// any express or implied warranties, including, but not limited to, the implied
31// warranties of merchantability and fitness for a particular purpose are disclaimed.
32// In no event shall the Intel Corporation or contributors be liable for any direct,
33// indirect, incidental, special, exemplary, or consequential damages
34// (including, but not limited to, procurement of substitute goods or services;
35// loss of use, data, or profits; or business interruption) however caused
36// and on any theory of liability, whether in contract, strict liability,
37// or tort (including negligence or otherwise) arising in any way out of
38// the use of this software, even if advised of the possibility of such damage.
39//
40//M*/
41
42#include "_cv.h"
43
44/****************************************************************************************/
45
46/* lightweight convolution with 3x3 kernel */
47void icvSepConvSmall3_32f( float* src, int src_step, float* dst, int dst_step,
48            CvSize src_size, const float* kx, const float* ky, float* buffer )
49{
50    int  dst_width, buffer_step = 0;
51    int  x, y;
52
53    assert( src && dst && src_size.width > 2 && src_size.height > 2 &&
54            (src_step & 3) == 0 && (dst_step & 3) == 0 &&
55            (kx || ky) && (buffer || !kx || !ky));
56
57    src_step /= sizeof(src[0]);
58    dst_step /= sizeof(dst[0]);
59
60    dst_width = src_size.width - 2;
61
62    if( !kx )
63    {
64        /* set vars, so that vertical convolution
65           will write results into destination ROI and
66           horizontal convolution won't run */
67        src_size.width = dst_width;
68        buffer_step = dst_step;
69        buffer = dst;
70        dst_width = 0;
71    }
72
73    assert( src_step >= src_size.width && dst_step >= dst_width );
74
75    src_size.height -= 3;
76    if( !ky )
77    {
78        /* set vars, so that vertical convolution won't run and
79           horizontal convolution will write results into destination ROI */
80        src_size.height += 3;
81        buffer_step = src_step;
82        buffer = src;
83        src_size.width = 0;
84    }
85
86    for( y = 0; y <= src_size.height; y++, src += src_step,
87                                           dst += dst_step,
88                                           buffer += buffer_step )
89    {
90        float* src2 = src + src_step;
91        float* src3 = src + src_step*2;
92        for( x = 0; x < src_size.width; x++ )
93        {
94            buffer[x] = (float)(ky[0]*src[x] + ky[1]*src2[x] + ky[2]*src3[x]);
95        }
96
97        for( x = 0; x < dst_width; x++ )
98        {
99            dst[x] = (float)(kx[0]*buffer[x] + kx[1]*buffer[x+1] + kx[2]*buffer[x+2]);
100        }
101    }
102}
103
104
105/****************************************************************************************\
106                             Sobel & Scharr Derivative Filters
107\****************************************************************************************/
108
109/////////////////////////////// Old IPP derivative filters ///////////////////////////////
110// still used in corner detectors (see cvcorner.cpp)
111
112icvFilterSobelVert_8u16s_C1R_t icvFilterSobelVert_8u16s_C1R_p = 0;
113icvFilterSobelHoriz_8u16s_C1R_t icvFilterSobelHoriz_8u16s_C1R_p = 0;
114icvFilterSobelVertSecond_8u16s_C1R_t icvFilterSobelVertSecond_8u16s_C1R_p = 0;
115icvFilterSobelHorizSecond_8u16s_C1R_t icvFilterSobelHorizSecond_8u16s_C1R_p = 0;
116icvFilterSobelCross_8u16s_C1R_t icvFilterSobelCross_8u16s_C1R_p = 0;
117
118icvFilterSobelVert_32f_C1R_t icvFilterSobelVert_32f_C1R_p = 0;
119icvFilterSobelHoriz_32f_C1R_t icvFilterSobelHoriz_32f_C1R_p = 0;
120icvFilterSobelVertSecond_32f_C1R_t icvFilterSobelVertSecond_32f_C1R_p = 0;
121icvFilterSobelHorizSecond_32f_C1R_t icvFilterSobelHorizSecond_32f_C1R_p = 0;
122icvFilterSobelCross_32f_C1R_t icvFilterSobelCross_32f_C1R_p = 0;
123
124icvFilterScharrVert_8u16s_C1R_t icvFilterScharrVert_8u16s_C1R_p = 0;
125icvFilterScharrHoriz_8u16s_C1R_t icvFilterScharrHoriz_8u16s_C1R_p = 0;
126icvFilterScharrVert_32f_C1R_t icvFilterScharrVert_32f_C1R_p = 0;
127icvFilterScharrHoriz_32f_C1R_t icvFilterScharrHoriz_32f_C1R_p = 0;
128
129///////////////////////////////// New IPP derivative filters /////////////////////////////
130
131#define IPCV_FILTER_PTRS( name )                    \
132icvFilter##name##GetBufSize_8u16s_C1R_t             \
133    icvFilter##name##GetBufSize_8u16s_C1R_p = 0;    \
134icvFilter##name##Border_8u16s_C1R_t                 \
135    icvFilter##name##Border_8u16s_C1R_p = 0;        \
136icvFilter##name##GetBufSize_32f_C1R_t               \
137    icvFilter##name##GetBufSize_32f_C1R_p = 0;      \
138icvFilter##name##Border_32f_C1R_t                   \
139    icvFilter##name##Border_32f_C1R_p = 0;
140
141IPCV_FILTER_PTRS( ScharrHoriz )
142IPCV_FILTER_PTRS( ScharrVert )
143IPCV_FILTER_PTRS( SobelHoriz )
144IPCV_FILTER_PTRS( SobelNegVert )
145IPCV_FILTER_PTRS( SobelHorizSecond )
146IPCV_FILTER_PTRS( SobelVertSecond )
147IPCV_FILTER_PTRS( SobelCross )
148IPCV_FILTER_PTRS( Laplacian )
149
150typedef CvStatus (CV_STDCALL * CvDeriv3x3GetBufSizeIPPFunc)
151    ( CvSize roi, int* bufsize );
152
153typedef CvStatus (CV_STDCALL * CvDerivGetBufSizeIPPFunc)
154    ( CvSize roi, int masksize, int* bufsize );
155
156typedef CvStatus (CV_STDCALL * CvDeriv3x3IPPFunc_8u )
157    ( const void* src, int srcstep, void* dst, int dststep,
158      CvSize size, int bordertype, uchar bordervalue, void* buffer );
159
160typedef CvStatus (CV_STDCALL * CvDeriv3x3IPPFunc_32f )
161    ( const void* src, int srcstep, void* dst, int dststep,
162      CvSize size, int bordertype, float bordervalue, void* buffer );
163
164typedef CvStatus (CV_STDCALL * CvDerivIPPFunc_8u )
165    ( const void* src, int srcstep, void* dst, int dststep,
166      CvSize size, int masksize, int bordertype,
167      uchar bordervalue, void* buffer );
168
169typedef CvStatus (CV_STDCALL * CvDerivIPPFunc_32f )
170    ( const void* src, int srcstep, void* dst, int dststep,
171      CvSize size, int masksize, int bordertype,
172      float bordervalue, void* buffer );
173
174//////////////////////////////////////////////////////////////////////////////////////////
175
176CV_IMPL void
177cvSobel( const void* srcarr, void* dstarr, int dx, int dy, int aperture_size )
178{
179    CvSepFilter filter;
180    void* buffer = 0;
181    int local_alloc = 0;
182
183    CV_FUNCNAME( "cvSobel" );
184
185    __BEGIN__;
186
187    int origin = 0;
188    int src_type, dst_type;
189    CvMat srcstub, *src = (CvMat*)srcarr;
190    CvMat dststub, *dst = (CvMat*)dstarr;
191
192    if( !CV_IS_MAT(src) )
193        CV_CALL( src = cvGetMat( src, &srcstub ));
194    if( !CV_IS_MAT(dst) )
195        CV_CALL( dst = cvGetMat( dst, &dststub ));
196
197    if( CV_IS_IMAGE_HDR( srcarr ))
198        origin = ((IplImage*)srcarr)->origin;
199
200    src_type = CV_MAT_TYPE( src->type );
201    dst_type = CV_MAT_TYPE( dst->type );
202
203    if( !CV_ARE_SIZES_EQ( src, dst ))
204        CV_ERROR( CV_StsBadArg, "src and dst have different sizes" );
205
206    if( ((aperture_size == CV_SCHARR || aperture_size == 3 || aperture_size == 5) &&
207        dx <= 2 && dy <= 2 && dx + dy <= 2 && icvFilterSobelNegVertBorder_8u16s_C1R_p) &&
208        (src_type == CV_8UC1 && dst_type == CV_16SC1/* ||
209        src_type == CV_32FC1 && dst_type == CV_32FC1*/) )
210    {
211        CvDerivGetBufSizeIPPFunc ipp_sobel_getbufsize_func = 0;
212        CvDerivIPPFunc_8u ipp_sobel_func_8u = 0;
213        CvDerivIPPFunc_32f ipp_sobel_func_32f = 0;
214
215        CvDeriv3x3GetBufSizeIPPFunc ipp_scharr_getbufsize_func = 0;
216        CvDeriv3x3IPPFunc_8u ipp_scharr_func_8u = 0;
217        CvDeriv3x3IPPFunc_32f ipp_scharr_func_32f = 0;
218
219        if( aperture_size == CV_SCHARR )
220        {
221            if( dx == 1 && dy == 0 )
222            {
223                if( src_type == CV_8U )
224                    ipp_scharr_func_8u = icvFilterScharrVertBorder_8u16s_C1R_p,
225                    ipp_scharr_getbufsize_func = icvFilterScharrVertGetBufSize_8u16s_C1R_p;
226                else
227                    ipp_scharr_func_32f = icvFilterScharrVertBorder_32f_C1R_p,
228                    ipp_scharr_getbufsize_func = icvFilterScharrVertGetBufSize_32f_C1R_p;
229            }
230            else if( dx == 0 && dy == 1 )
231            {
232                if( src_type == CV_8U )
233                    ipp_scharr_func_8u = icvFilterScharrHorizBorder_8u16s_C1R_p,
234                    ipp_scharr_getbufsize_func = icvFilterScharrHorizGetBufSize_8u16s_C1R_p;
235                else
236                    ipp_scharr_func_32f = icvFilterScharrHorizBorder_32f_C1R_p,
237                    ipp_scharr_getbufsize_func = icvFilterScharrHorizGetBufSize_32f_C1R_p;
238            }
239            else
240                CV_ERROR( CV_StsBadArg, "Scharr filter can only be used to compute 1st image derivatives" );
241        }
242        else
243        {
244            if( dx == 1 && dy == 0 )
245            {
246                if( src_type == CV_8U )
247                    ipp_sobel_func_8u = icvFilterSobelNegVertBorder_8u16s_C1R_p,
248                    ipp_sobel_getbufsize_func = icvFilterSobelNegVertGetBufSize_8u16s_C1R_p;
249                else
250                    ipp_sobel_func_32f = icvFilterSobelNegVertBorder_32f_C1R_p,
251                    ipp_sobel_getbufsize_func = icvFilterSobelNegVertGetBufSize_32f_C1R_p;
252            }
253            else if( dx == 0 && dy == 1 )
254            {
255                if( src_type == CV_8U )
256                    ipp_sobel_func_8u = icvFilterSobelHorizBorder_8u16s_C1R_p,
257                    ipp_sobel_getbufsize_func = icvFilterSobelHorizGetBufSize_8u16s_C1R_p;
258                else
259                    ipp_sobel_func_32f = icvFilterSobelHorizBorder_32f_C1R_p,
260                    ipp_sobel_getbufsize_func = icvFilterSobelHorizGetBufSize_32f_C1R_p;
261            }
262            else if( dx == 2 && dy == 0 )
263            {
264                if( src_type == CV_8U )
265                    ipp_sobel_func_8u = icvFilterSobelVertSecondBorder_8u16s_C1R_p,
266                    ipp_sobel_getbufsize_func = icvFilterSobelVertSecondGetBufSize_8u16s_C1R_p;
267                else
268                    ipp_sobel_func_32f = icvFilterSobelVertSecondBorder_32f_C1R_p,
269                    ipp_sobel_getbufsize_func = icvFilterSobelVertSecondGetBufSize_32f_C1R_p;
270            }
271            else if( dx == 0 && dy == 2 )
272            {
273                if( src_type == CV_8U )
274                    ipp_sobel_func_8u = icvFilterSobelHorizSecondBorder_8u16s_C1R_p,
275                    ipp_sobel_getbufsize_func = icvFilterSobelHorizSecondGetBufSize_8u16s_C1R_p;
276                else
277                    ipp_sobel_func_32f = icvFilterSobelHorizSecondBorder_32f_C1R_p,
278                    ipp_sobel_getbufsize_func = icvFilterSobelHorizSecondGetBufSize_32f_C1R_p;
279            }
280            else if( dx == 1 && dy == 1 )
281            {
282                if( src_type == CV_8U )
283                    ipp_sobel_func_8u = icvFilterSobelCrossBorder_8u16s_C1R_p,
284                    ipp_sobel_getbufsize_func = icvFilterSobelCrossGetBufSize_8u16s_C1R_p;
285                else
286                    ipp_sobel_func_32f = icvFilterSobelCrossBorder_32f_C1R_p,
287                    ipp_sobel_getbufsize_func = icvFilterSobelCrossGetBufSize_32f_C1R_p;
288            }
289        }
290
291        if( ((ipp_sobel_func_8u || ipp_sobel_func_32f) && ipp_sobel_getbufsize_func) ||
292            ((ipp_scharr_func_8u || ipp_scharr_func_32f) && ipp_scharr_getbufsize_func) )
293        {
294            int bufsize = 0, masksize = aperture_size == 3 ? 33 : 55;
295            CvSize size = cvGetMatSize( src );
296            uchar* src_ptr = src->data.ptr;
297            uchar* dst_ptr = dst->data.ptr;
298            int src_step = src->step ? src->step : CV_STUB_STEP;
299            int dst_step = dst->step ? dst->step : CV_STUB_STEP;
300            const int bordertype = 1; // replication border
301            CvStatus status;
302
303            status = ipp_sobel_getbufsize_func ?
304                ipp_sobel_getbufsize_func( size, masksize, &bufsize ) :
305                ipp_scharr_getbufsize_func( size, &bufsize );
306
307            if( status >= 0 )
308            {
309                if( bufsize <= CV_MAX_LOCAL_SIZE )
310                {
311                    buffer = cvStackAlloc( bufsize );
312                    local_alloc = 1;
313                }
314                else
315                    CV_CALL( buffer = cvAlloc( bufsize ));
316
317                status =
318                    ipp_sobel_func_8u ? ipp_sobel_func_8u( src_ptr, src_step, dst_ptr, dst_step,
319                                                           size, masksize, bordertype, 0, buffer ) :
320                    ipp_sobel_func_32f ? ipp_sobel_func_32f( src_ptr, src_step, dst_ptr, dst_step,
321                                                             size, masksize, bordertype, 0, buffer ) :
322                    ipp_scharr_func_8u ? ipp_scharr_func_8u( src_ptr, src_step, dst_ptr, dst_step,
323                                                             size, bordertype, 0, buffer ) :
324                    ipp_scharr_func_32f ? ipp_scharr_func_32f( src_ptr, src_step, dst_ptr, dst_step,
325                                                               size, bordertype, 0, buffer ) :
326                        CV_NOTDEFINED_ERR;
327            }
328
329            if( status >= 0 &&
330                ((dx == 0 && dy == 1 && origin) || (dx == 1 && dy == 1 && !origin))) // negate the output
331                cvSubRS( dst, cvScalarAll(0), dst );
332
333            if( status >= 0 )
334                EXIT;
335        }
336    }
337
338    CV_CALL( filter.init_deriv( src->cols, src_type, dst_type, dx, dy,
339                aperture_size, origin ? CvSepFilter::FLIP_KERNEL : 0));
340    CV_CALL( filter.process( src, dst ));
341
342    __END__;
343
344    if( buffer && !local_alloc )
345        cvFree( &buffer );
346}
347
348
349/****************************************************************************************\
350                                     Laplacian Filter
351\****************************************************************************************/
352
353static void icvLaplaceRow_8u32s( const uchar* src, int* dst, void* params );
354static void icvLaplaceRow_8u32f( const uchar* src, float* dst, void* params );
355static void icvLaplaceRow_32f( const float* src, float* dst, void* params );
356static void icvLaplaceCol_32s16s( const int** src, short* dst, int dst_step,
357                                  int count, void* params );
358static void icvLaplaceCol_32f( const float** src, float* dst, int dst_step,
359                               int count, void* params );
360
361CvLaplaceFilter::CvLaplaceFilter()
362{
363    normalized = basic_laplacian = false;
364}
365
366
367CvLaplaceFilter::CvLaplaceFilter( int _max_width, int _src_type, int _dst_type, bool _normalized,
368                                  int _ksize, int _border_mode, CvScalar _border_value )
369{
370    normalized = basic_laplacian = false;
371    init( _max_width, _src_type, _dst_type, _normalized, _ksize, _border_mode, _border_value );
372}
373
374
375CvLaplaceFilter::~CvLaplaceFilter()
376{
377    clear();
378}
379
380
381void CvLaplaceFilter::get_work_params()
382{
383    int min_rows = max_ky*2 + 3, rows = MAX(min_rows,10), row_sz;
384    int width = max_width, trow_sz = 0;
385    int dst_depth = CV_MAT_DEPTH(dst_type);
386    int work_depth = dst_depth < CV_32F ? CV_32S : CV_32F;
387    work_type = CV_MAKETYPE( work_depth, CV_MAT_CN(dst_type)*2 );
388    trow_sz = cvAlign( (max_width + ksize.width - 1)*CV_ELEM_SIZE(src_type), ALIGN );
389    row_sz = cvAlign( width*CV_ELEM_SIZE(work_type), ALIGN );
390    buf_size = rows*row_sz;
391    buf_size = MIN( buf_size, 1 << 16 );
392    buf_size = MAX( buf_size, min_rows*row_sz );
393    max_rows = (buf_size/row_sz)*3 + max_ky*2 + 8;
394    buf_size += trow_sz;
395}
396
397
398void CvLaplaceFilter::init( int _max_width, int _src_type, int _dst_type, bool _normalized,
399                            int _ksize0, int _border_mode, CvScalar _border_value )
400{
401    CvMat *kx = 0, *ky = 0;
402
403    CV_FUNCNAME( "CvLaplaceFilter::init" );
404
405    __BEGIN__;
406
407    int src_depth = CV_MAT_DEPTH(_src_type), dst_depth = CV_MAT_DEPTH(_dst_type);
408    int _ksize = MAX( _ksize0, 3 );
409
410    normalized = _normalized;
411    basic_laplacian = _ksize0 == 1;
412
413    if( ((src_depth != CV_8U || (dst_depth != CV_16S && dst_depth != CV_32F)) &&
414        (src_depth != CV_32F || dst_depth != CV_32F)) ||
415        CV_MAT_CN(_src_type) != CV_MAT_CN(_dst_type) )
416        CV_ERROR( CV_StsUnmatchedFormats,
417        "Laplacian can either transform 8u->16s, or 8u->32f, or 32f->32f.\n"
418        "The number of channels must be the same." );
419
420    if( _ksize < 1 || _ksize > CV_MAX_SOBEL_KSIZE || _ksize % 2 == 0 )
421        CV_ERROR( CV_StsOutOfRange, "kernel size must be within 1..7 and odd" );
422
423    CV_CALL( kx = cvCreateMat( 1, _ksize, CV_32F ));
424    CV_CALL( ky = cvCreateMat( 1, _ksize, CV_32F ));
425
426    CvSepFilter::init_sobel_kernel( kx, ky, 2, 0, 0 );
427    CvSepFilter::init( _max_width, _src_type, _dst_type, kx, ky,
428                       cvPoint(-1,-1), _border_mode, _border_value );
429
430    x_func = 0;
431    y_func = 0;
432
433    if( src_depth == CV_8U )
434    {
435        if( dst_depth == CV_16S )
436        {
437            x_func = (CvRowFilterFunc)icvLaplaceRow_8u32s;
438            y_func = (CvColumnFilterFunc)icvLaplaceCol_32s16s;
439        }
440        else if( dst_depth == CV_32F )
441        {
442            x_func = (CvRowFilterFunc)icvLaplaceRow_8u32f;
443            y_func = (CvColumnFilterFunc)icvLaplaceCol_32f;
444        }
445    }
446    else if( src_depth == CV_32F )
447    {
448        if( dst_depth == CV_32F )
449        {
450            x_func = (CvRowFilterFunc)icvLaplaceRow_32f;
451            y_func = (CvColumnFilterFunc)icvLaplaceCol_32f;
452        }
453    }
454
455    if( !x_func || !y_func )
456        CV_ERROR( CV_StsUnsupportedFormat, "" );
457
458    __END__;
459
460    cvReleaseMat( &kx );
461    cvReleaseMat( &ky );
462}
463
464
465void CvLaplaceFilter::init( int _max_width, int _src_type, int _dst_type,
466                            bool _is_separable, CvSize _ksize,
467                            CvPoint _anchor, int _border_mode,
468                            CvScalar _border_value )
469{
470    CvSepFilter::init( _max_width, _src_type, _dst_type, _is_separable,
471                       _ksize, _anchor, _border_mode, _border_value );
472}
473
474
475void CvLaplaceFilter::init( int _max_width, int _src_type, int _dst_type,
476                            const CvMat* _kx, const CvMat* _ky,
477                            CvPoint _anchor, int _border_mode,
478                            CvScalar _border_value )
479{
480    CvSepFilter::init( _max_width, _src_type, _dst_type, _kx, _ky,
481                       _anchor, _border_mode, _border_value );
482}
483
484
485#define ICV_LAPLACE_ROW( flavor, srctype, dsttype, load_macro )         \
486static void                                                             \
487icvLaplaceRow_##flavor( const srctype* src, dsttype* dst, void* params )\
488{                                                                       \
489    const CvLaplaceFilter* state = (const CvLaplaceFilter*)params;      \
490    const CvMat* _kx = state->get_x_kernel();                           \
491    const CvMat* _ky = state->get_y_kernel();                           \
492    const dsttype* kx = (dsttype*)_kx->data.ptr;                        \
493    const dsttype* ky = (dsttype*)_ky->data.ptr;                        \
494    int ksize = _kx->cols + _kx->rows - 1;                              \
495    int i = 0, j, k, width = state->get_width();                        \
496    int cn = CV_MAT_CN(state->get_src_type());                          \
497    int ksize2 = ksize/2, ksize2n = ksize2*cn;                          \
498    const srctype* s = src + ksize2n;                                   \
499    bool basic_laplacian = state->is_basic_laplacian();                 \
500                                                                        \
501    kx += ksize2;                                                       \
502    ky += ksize2;                                                       \
503    width *= cn;                                                        \
504                                                                        \
505    if( basic_laplacian )                                               \
506        for( i = 0; i < width; i++ )                                    \
507        {                                                               \
508            dsttype s0 = load_macro(s[i]);                              \
509            dsttype s1 = (dsttype)(s[i-cn] - s0*2 + s[i+cn]);           \
510            dst[i] = s0; dst[i+width] = s1;                             \
511        }                                                               \
512    else if( ksize == 3 )                                               \
513        for( i = 0; i < width; i++ )                                    \
514        {                                                               \
515            dsttype s0 = (dsttype)(s[i-cn] + s[i]*2 + s[i+cn]);         \
516            dsttype s1 = (dsttype)(s[i-cn] - s[i]*2 + s[i+cn]);         \
517            dst[i] = s0; dst[i+width] = s1;                             \
518        }                                                               \
519    else if( ksize == 5 )                                               \
520        for( i = 0; i < width; i++ )                                    \
521        {                                                               \
522            dsttype s0 = (dsttype)(s[i-2*cn]+(s[i-cn]+s[i+cn])*4+s[i]*6+s[i+2*cn]);\
523            dsttype s1 = (dsttype)(s[i-2*cn]-s[i]*2+s[i+2*cn]);         \
524            dst[i] = s0; dst[i+width] = s1;                             \
525        }                                                               \
526    else                                                                \
527        for( i = 0; i < width; i++, s++ )                               \
528        {                                                               \
529            dsttype s0 = ky[0]*load_macro(s[0]), s1 = kx[0]*load_macro(s[0]);\
530            for( k = 1, j = cn; k <= ksize2; k++, j += cn )             \
531            {                                                           \
532                dsttype t = load_macro(s[j] + s[-j]);                   \
533                s0 += ky[k]*t; s1 += kx[k]*t;                           \
534            }                                                           \
535            dst[i] = s0; dst[i+width] = s1;                             \
536        }                                                               \
537}
538
539ICV_LAPLACE_ROW( 8u32s, uchar, int, CV_NOP )
540ICV_LAPLACE_ROW( 8u32f, uchar, float, CV_8TO32F )
541ICV_LAPLACE_ROW( 32f, float, float, CV_NOP )
542
543static void
544icvLaplaceCol_32s16s( const int** src, short* dst,
545                      int dst_step, int count, void* params )
546{
547    const CvLaplaceFilter* state = (const CvLaplaceFilter*)params;
548    const CvMat* _kx = state->get_x_kernel();
549    const CvMat* _ky = state->get_y_kernel();
550    const int* kx = (const int*)_kx->data.ptr;
551    const int* ky = (const int*)_ky->data.ptr;
552    int ksize = _kx->cols + _kx->rows - 1, ksize2 = ksize/2;
553    int i = 0, k, width = state->get_width();
554    int cn = CV_MAT_CN(state->get_src_type());
555    bool basic_laplacian = state->is_basic_laplacian();
556    bool normalized = state->is_normalized();
557    int shift = ksize - 1, delta = (1 << shift) >> 1;
558
559    width *= cn;
560    src += ksize2;
561    kx += ksize2;
562    ky += ksize2;
563    dst_step /= sizeof(dst[0]);
564
565    if( basic_laplacian || !normalized )
566    {
567        normalized = false;
568        shift = delta = 0;
569    }
570
571    for( ; count--; dst += dst_step, src++ )
572    {
573        if( ksize == 3 )
574        {
575            const int *src0 = src[-1], *src1 = src[0], *src2 = src[1];
576            if( basic_laplacian )
577            {
578                for( i = 0; i <= width - 2; i += 2 )
579                {
580                    int s0 = src0[i] - src1[i]*2 + src2[i] + src1[i+width];
581                    int s1 = src0[i+1] - src1[i+1]*2 + src2[i+1] + src1[i+width+1];
582                    dst[i] = (short)s0; dst[i+1] = (short)s1;
583                }
584
585                for( ; i < width; i++ )
586                    dst[i] = (short)(src0[i] - src1[i]*2 + src2[i] + src1[i+width]);
587            }
588            else if( !normalized )
589                for( i = 0; i <= width - 2; i += 2 )
590                {
591                    int s0 = src0[i] - src1[i]*2 + src2[i] +
592                             src0[i+width] + src1[i+width]*2 + src2[i+width];
593                    int s1 = src0[i+1] - src1[i+1]*2 + src2[i+1] +
594                             src0[i+width+1] + src1[i+width+1]*2 + src2[i+width+1];
595                    dst[i] = (short)s0; dst[i+1] = (short)s1;
596                }
597            else
598                for( i = 0; i <= width - 2; i += 2 )
599                {
600                    int s0 = CV_DESCALE(src0[i] - src1[i]*2 + src2[i] +
601                             src0[i+width] + src1[i+width]*2 + src2[i+width], 2);
602                    int s1 = CV_DESCALE(src0[i+1] - src1[i+1]*2 + src2[i+1] +
603                             src0[i+width+1] + src1[i+width+1]*2 + src2[i+width+1],2);
604                    dst[i] = (short)s0; dst[i+1] = (short)s1;
605                }
606        }
607        else if( ksize == 5 )
608        {
609            const int *src0 = src[-2], *src1 = src[-1], *src2 = src[0], *src3 = src[1], *src4 = src[2];
610
611            if( !normalized )
612                for( i = 0; i <= width - 2; i += 2 )
613                {
614                    int s0 = src0[i] - src2[i]*2 + src4[i] + src0[i+width] + src4[i+width] +
615                             (src1[i+width] + src3[i+width])*4 + src2[i+width]*6;
616                    int s1 = src0[i+1] - src2[i+1]*2 + src4[i+1] + src0[i+width+1] +
617                             src4[i+width+1] + (src1[i+width+1] + src3[i+width+1])*4 +
618                             src2[i+width+1]*6;
619                    dst[i] = (short)s0; dst[i+1] = (short)s1;
620                }
621            else
622                for( i = 0; i <= width - 2; i += 2 )
623                {
624                    int s0 = CV_DESCALE(src0[i] - src2[i]*2 + src4[i] +
625                             src0[i+width] + src4[i+width] +
626                             (src1[i+width] + src3[i+width])*4 + src2[i+width]*6, 4);
627                    int s1 = CV_DESCALE(src0[i+1] - src2[i+1]*2 + src4[i+1] +
628                             src0[i+width+1] + src4[i+width+1] +
629                             (src1[i+width+1] + src3[i+width+1])*4 + src2[i+width+1]*6, 4);
630                    dst[i] = (short)s0; dst[i+1] = (short)s1;
631                }
632        }
633        else
634        {
635            if( !normalized )
636                for( i = 0; i <= width - 2; i += 2 )
637                {
638                    int s0 = kx[0]*src[0][i] + ky[0]*src[0][i+width];
639                    int s1 = kx[0]*src[0][i+1] + ky[0]*src[0][i+width+1];
640
641                    for( k = 1; k <= ksize2; k++ )
642                    {
643                        const int* src1 = src[k] + i, *src2 = src[-k] + i;
644                        int fx = kx[k], fy = ky[k];
645                        s0 += fx*(src1[0] + src2[0]) + fy*(src1[width] + src2[width]);
646                        s1 += fx*(src1[1] + src2[1]) + fy*(src1[width+1] + src2[width+1]);
647                    }
648
649                    dst[i] = CV_CAST_16S(s0); dst[i+1] = CV_CAST_16S(s1);
650                }
651            else
652                for( i = 0; i <= width - 2; i += 2 )
653                {
654                    int s0 = kx[0]*src[0][i] + ky[0]*src[0][i+width];
655                    int s1 = kx[0]*src[0][i+1] + ky[0]*src[0][i+width+1];
656
657                    for( k = 1; k <= ksize2; k++ )
658                    {
659                        const int* src1 = src[k] + i, *src2 = src[-k] + i;
660                        int fx = kx[k], fy = ky[k];
661                        s0 += fx*(src1[0] + src2[0]) + fy*(src1[width] + src2[width]);
662                        s1 += fx*(src1[1] + src2[1]) + fy*(src1[width+1] + src2[width+1]);
663                    }
664
665                    s0 = CV_DESCALE( s0, shift ); s1 = CV_DESCALE( s1, shift );
666                    dst[i] = (short)s0; dst[i+1] = (short)s1;
667                }
668        }
669
670        for( ; i < width; i++ )
671        {
672            int s0 = kx[0]*src[0][i] + ky[0]*src[0][i+width];
673            for( k = 1; k <= ksize2; k++ )
674            {
675                const int* src1 = src[k] + i, *src2 = src[-k] + i;
676                s0 += kx[k]*(src1[0] + src2[0]) + ky[k]*(src1[width] + src2[width]);
677            }
678            s0 = (s0 + delta) >> shift;
679            dst[i] = CV_CAST_16S(s0);
680        }
681    }
682}
683
684
685static void
686icvLaplaceCol_32f( const float** src, float* dst,
687                   int dst_step, int count, void* params )
688{
689    const CvLaplaceFilter* state = (const CvLaplaceFilter*)params;
690    const CvMat* _kx = state->get_x_kernel();
691    const CvMat* _ky = state->get_y_kernel();
692    const float* kx = (const float*)_kx->data.ptr;
693    const float* ky = (const float*)_ky->data.ptr;
694    int ksize = _kx->cols + _kx->rows - 1, ksize2 = ksize/2;
695    int i = 0, k, width = state->get_width();
696    int cn = CV_MAT_CN(state->get_src_type());
697    bool basic_laplacian = state->is_basic_laplacian();
698    bool normalized = state->is_normalized();
699    float scale = 1.f/(1 << (ksize - 1));
700
701    width *= cn;
702    src += ksize2;
703    kx += ksize2;
704    ky += ksize2;
705    dst_step /= sizeof(dst[0]);
706
707    if( basic_laplacian || !normalized )
708    {
709        normalized = false;
710        scale = 1.f;
711    }
712
713    for( ; count--; dst += dst_step, src++ )
714    {
715        if( ksize == 3 )
716        {
717            const float *src0 = src[-1], *src1 = src[0], *src2 = src[1];
718            if( basic_laplacian )
719            {
720                for( i = 0; i <= width - 2; i += 2 )
721                {
722                    float s0 = src0[i] - src1[i]*2 + src2[i] + src1[i+width];
723                    float s1 = src0[i+1] - src1[i+1]*2 + src2[i+1] + src1[i+width+1];
724                    dst[i] = s0; dst[i+1] = s1;
725                }
726
727                for( ; i < width; i++ )
728                    dst[i] = src0[i] - src1[i]*2 + src2[i] + src1[i+width];
729            }
730            else if( !normalized )
731                for( i = 0; i <= width - 2; i += 2 )
732                {
733                    float s0 = src0[i] - src1[i]*2 + src2[i] +
734                             src0[i+width] + src1[i+width]*2 + src2[i+width];
735                    float s1 = src0[i+1] - src1[i+1]*2 + src2[i+1] +
736                             src0[i+width+1] + src1[i+width+1]*2 + src2[i+width+1];
737                    dst[i] = s0; dst[i+1] = s1;
738                }
739            else
740                for( i = 0; i <= width - 2; i += 2 )
741                {
742                    float s0 = (src0[i] - src1[i]*2 + src2[i] +
743                             src0[i+width] + src1[i+width]*2 + src2[i+width])*scale;
744                    float s1 = (src0[i+1] - src1[i+1]*2 + src2[i+1] +
745                             src0[i+width+1] + src1[i+width+1]*2 + src2[i+width+1])*scale;
746                    dst[i] = s0; dst[i+1] = s1;
747                }
748        }
749        else if( ksize == 5 )
750        {
751            const float *src0 = src[-2], *src1 = src[-1], *src2 = src[0], *src3 = src[1], *src4 = src[2];
752            for( i = 0; i <= width - 2; i += 2 )
753            {
754                float s0 = (src0[i] - src2[i]*2 + src4[i] +
755                         src0[i+width] + src4[i+width] +
756                         (src1[i+width] + src3[i+width])*4 + src2[i+width]*6)*scale;
757                float s1 = (src0[i+1] - src2[i+1]*2 + src4[i+1] +
758                         src0[i+width+1] + src4[i+width+1] +
759                         (src1[i+width+1] + src3[i+width+1])*4 + src2[i+width+1]*6)*scale;
760                dst[i] = s0; dst[i+1] = s1;
761            }
762        }
763        else
764        {
765            for( i = 0; i <= width - 2; i += 2 )
766            {
767                float s0 = kx[0]*src[0][i] + ky[0]*src[0][i+width];
768                float s1 = kx[0]*src[0][i+1] + ky[0]*src[0][i+width+1];
769
770                for( k = 1; k <= ksize2; k++ )
771                {
772                    const float* src1 = src[k] + i, *src2 = src[-k] + i;
773                    float fx = kx[k], fy = ky[k];
774                    s0 += fx*(src1[0] + src2[0]) + fy*(src1[width] + src2[width]);
775                    s1 += fx*(src1[1] + src2[1]) + fy*(src1[width+1] + src2[width+1]);
776                }
777
778                s0 *= scale; s1 *= scale;
779                dst[i] = s0; dst[i+1] = s1;
780            }
781        }
782
783        for( ; i < width; i++ )
784        {
785            float s0 = kx[0]*src[0][i] + ky[0]*src[0][i+width];
786            for( k = 1; k <= ksize2; k++ )
787            {
788                const float* src1 = src[k] + i, *src2 = src[-k] + i;
789                s0 += kx[k]*(src1[0] + src2[0]) + ky[k]*(src1[width] + src2[width]);
790            }
791            dst[i] = s0*scale;
792        }
793    }
794}
795
796
797CV_IMPL void
798cvLaplace( const void* srcarr, void* dstarr, int aperture_size )
799{
800    CvLaplaceFilter laplacian;
801    void* buffer = 0;
802    int local_alloc = 0;
803
804    CV_FUNCNAME( "cvLaplace" );
805
806    __BEGIN__;
807
808    CvMat srcstub, *src = (CvMat*)srcarr;
809    CvMat dststub, *dst = (CvMat*)dstarr;
810    int src_type, dst_type;
811
812    CV_CALL( src = cvGetMat( src, &srcstub ));
813    CV_CALL( dst = cvGetMat( dst, &dststub ));
814
815    src_type = CV_MAT_TYPE(src->type);
816    dst_type = CV_MAT_TYPE(dst->type);
817
818    if( (aperture_size == 3 || aperture_size == 5) &&
819        (src_type == CV_8UC1 && dst_type == CV_16SC1/* ||
820        src_type == CV_32FC1 && dst_type == CV_32FC1*/) )
821    {
822        CvDerivGetBufSizeIPPFunc ipp_laplace_getbufsize_func = 0;
823        CvDerivIPPFunc_8u ipp_laplace_func_8u = 0;
824        CvDerivIPPFunc_32f ipp_laplace_func_32f = 0;
825
826        if( src_type == CV_8U )
827            ipp_laplace_func_8u = icvFilterLaplacianBorder_8u16s_C1R_p,
828            ipp_laplace_getbufsize_func = icvFilterLaplacianGetBufSize_8u16s_C1R_p;
829        else
830            ipp_laplace_func_32f = icvFilterLaplacianBorder_32f_C1R_p,
831            ipp_laplace_getbufsize_func = icvFilterLaplacianGetBufSize_32f_C1R_p;
832
833        if( (ipp_laplace_func_8u || ipp_laplace_func_32f) && ipp_laplace_getbufsize_func )
834        {
835            int bufsize = 0, masksize = aperture_size == 3 ? 33 : 55;
836            CvSize size = cvGetMatSize( src );
837            uchar* src_ptr = src->data.ptr;
838            uchar* dst_ptr = dst->data.ptr;
839            int src_step = src->step ? src->step : CV_STUB_STEP;
840            int dst_step = dst->step ? dst->step : CV_STUB_STEP;
841            const int bordertype = 1; // replication border
842            CvStatus status;
843
844            status = ipp_laplace_getbufsize_func( size, masksize, &bufsize );
845
846            if( status >= 0 )
847            {
848                if( bufsize <= CV_MAX_LOCAL_SIZE )
849                {
850                    buffer = cvStackAlloc( bufsize );
851                    local_alloc = 1;
852                }
853                else
854                    CV_CALL( buffer = cvAlloc( bufsize ));
855
856                status =
857                    ipp_laplace_func_8u ? ipp_laplace_func_8u( src_ptr, src_step, dst_ptr, dst_step,
858                                                               size, masksize, bordertype, 0, buffer ) :
859                    ipp_laplace_func_32f ? ipp_laplace_func_32f( src_ptr, src_step, dst_ptr, dst_step,
860                                                                 size, masksize, bordertype, 0, buffer ) :
861                        CV_NOTDEFINED_ERR;
862            }
863
864            if( status >= 0 )
865                EXIT;
866        }
867    }
868
869    CV_CALL( laplacian.init( src->cols, src_type, dst_type,
870                             false, aperture_size ));
871    CV_CALL( laplacian.process( src, dst ));
872
873    __END__;
874
875    if( buffer && !local_alloc )
876        cvFree( &buffer );
877}
878
879/* End of file. */
880