deriv.cpp 32.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/*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.
14
// Copyright (C) 2014, Itseez, Inc, all rights reserved.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
// 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 "precomp.hpp"
44 45
#include "opencl_kernels.hpp"

46
#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7)
47
static IppStatus sts = ippInit();
48
#endif
49 50 51 52 53 54 55 56

/****************************************************************************************\
                             Sobel & Scharr Derivative Filters
\****************************************************************************************/

namespace cv
{

57 58
static void getScharrKernels( OutputArray _kx, OutputArray _ky,
                              int dx, int dy, bool normalize, int ktype )
59 60 61 62
{
    const int ksize = 3;

    CV_Assert( ktype == CV_32F || ktype == CV_64F );
63 64 65 66
    _kx.create(ksize, 1, ktype, -1, true);
    _ky.create(ksize, 1, ktype, -1, true);
    Mat kx = _kx.getMat();
    Mat ky = _ky.getMat();
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87

    CV_Assert( dx >= 0 && dy >= 0 && dx+dy == 1 );

    for( int k = 0; k < 2; k++ )
    {
        Mat* kernel = k == 0 ? &kx : &ky;
        int order = k == 0 ? dx : dy;
        int kerI[3];

        if( order == 0 )
            kerI[0] = 3, kerI[1] = 10, kerI[2] = 3;
        else if( order == 1 )
            kerI[0] = -1, kerI[1] = 0, kerI[2] = 1;

        Mat temp(kernel->rows, kernel->cols, CV_32S, &kerI[0]);
        double scale = !normalize || order == 1 ? 1. : 1./32;
        temp.convertTo(*kernel, ktype, scale);
    }
}


88 89
static void getSobelKernels( OutputArray _kx, OutputArray _ky,
                             int dx, int dy, int _ksize, bool normalize, int ktype )
90 91 92 93 94 95 96 97 98
{
    int i, j, ksizeX = _ksize, ksizeY = _ksize;
    if( ksizeX == 1 && dx > 0 )
        ksizeX = 3;
    if( ksizeY == 1 && dy > 0 )
        ksizeY = 3;

    CV_Assert( ktype == CV_32F || ktype == CV_64F );

99 100 101
    _kx.create(ksizeX, 1, ktype, -1, true);
    _ky.create(ksizeY, 1, ktype, -1, true);
    Mat kx = _kx.getMat();
102
    Mat ky = _ky.getMat();
103 104 105

    if( _ksize % 2 == 0 || _ksize > 31 )
        CV_Error( CV_StsOutOfRange, "The kernel size must be odd and not larger than 31" );
106
    std::vector<int> kerI(std::max(ksizeX, ksizeY) + 1);
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164

    CV_Assert( dx >= 0 && dy >= 0 && dx+dy > 0 );

    for( int k = 0; k < 2; k++ )
    {
        Mat* kernel = k == 0 ? &kx : &ky;
        int order = k == 0 ? dx : dy;
        int ksize = k == 0 ? ksizeX : ksizeY;

        CV_Assert( ksize > order );

        if( ksize == 1 )
            kerI[0] = 1;
        else if( ksize == 3 )
        {
            if( order == 0 )
                kerI[0] = 1, kerI[1] = 2, kerI[2] = 1;
            else if( order == 1 )
                kerI[0] = -1, kerI[1] = 0, kerI[2] = 1;
            else
                kerI[0] = 1, kerI[1] = -2, kerI[2] = 1;
        }
        else
        {
            int oldval, newval;
            kerI[0] = 1;
            for( i = 0; i < ksize; i++ )
                kerI[i+1] = 0;

            for( i = 0; i < ksize - order - 1; i++ )
            {
                oldval = kerI[0];
                for( j = 1; j <= ksize; j++ )
                {
                    newval = kerI[j]+kerI[j-1];
                    kerI[j-1] = oldval;
                    oldval = newval;
                }
            }

            for( i = 0; i < order; i++ )
            {
                oldval = -kerI[0];
                for( j = 1; j <= ksize; j++ )
                {
                    newval = kerI[j-1] - kerI[j];
                    kerI[j-1] = oldval;
                    oldval = newval;
                }
            }
        }

        Mat temp(kernel->rows, kernel->cols, CV_32S, &kerI[0]);
        double scale = !normalize ? 1. : 1./(1 << (ksize-order-1));
        temp.convertTo(*kernel, ktype, scale);
    }
}

165
}
166

167 168
void cv::getDerivKernels( OutputArray kx, OutputArray ky, int dx, int dy,
                          int ksize, bool normalize, int ktype )
169 170 171 172 173 174 175 176
{
    if( ksize <= 0 )
        getScharrKernels( kx, ky, dx, dy, normalize, ktype );
    else
        getSobelKernels( kx, ky, dx, dy, ksize, normalize, ktype );
}


177 178
cv::Ptr<cv::FilterEngine> cv::createDerivFilter(int srcType, int dstType,
                                                int dx, int dy, int ksize, int borderType )
179 180 181 182 183 184 185
{
    Mat kx, ky;
    getDerivKernels( kx, ky, dx, dy, ksize, false, CV_32F );
    return createSeparableLinearFilter(srcType, dstType,
        kx, ky, Point(-1,-1), 0, borderType );
}

186 187
#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7)

V
vbystricky 已提交
188 189
#define IPP_RETURN_ERROR    {setIppErrorStatus(); return false;}

190 191
namespace cv
{
A
Alexander Alekhin 已提交
192
#if IPP_VERSION_X100 >= 801
193 194 195 196
static bool IPPDerivScharr(InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, double scale, double delta, int borderType)
{
    if ((0 > dx) || (0 > dy) || (1 != dx + dy))
        return false;
V
vbystricky 已提交
197
    if (fabs(delta) > FLT_EPSILON)
198 199
        return false;

V
vbystricky 已提交
200
    IppiBorderType ippiBorderType = ippiGetBorderType(borderType & (~BORDER_ISOLATED));
201
    if ((int)ippiBorderType < 0)
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
        return false;

    int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
    if (ddepth < 0)
        ddepth = sdepth;
    int dtype = CV_MAKETYPE(ddepth, cn);

    Mat src = _src.getMat();
    if (0 == (BORDER_ISOLATED & borderType))
    {
        Size size; Point offset;
        src.locateROI(size, offset);
        if (0 < offset.x)
            ippiBorderType = (IppiBorderType)(ippiBorderType | ippBorderInMemLeft);
        if (0 < offset.y)
            ippiBorderType = (IppiBorderType)(ippiBorderType | ippBorderInMemTop);
        if (offset.x + src.cols < size.width)
            ippiBorderType = (IppiBorderType)(ippiBorderType | ippBorderInMemRight);
        if (offset.y + src.rows < size.height)
            ippiBorderType = (IppiBorderType)(ippiBorderType | ippBorderInMemBottom);
    }

    bool horz = (0 == dx) && (1 == dy);
    IppiSize roiSize = {src.cols, src.rows};

227 228
    _dst.create( _src.size(), dtype);
    Mat dst = _dst.getMat();
V
vbystricky 已提交
229
    IppStatus sts = ippStsErr;
230 231
    if ((CV_8U == stype) && (CV_16S == dtype))
    {
V
vbystricky 已提交
232
        int bufferSize = 0; Ipp8u *pBuffer;
233 234
        if (horz)
        {
235
            if (0 > ippiFilterScharrHorizMaskBorderGetBufferSize(roiSize, ippMskSize3x3, ipp8u, ipp16s, 1, &bufferSize))
V
vbystricky 已提交
236
                IPP_RETURN_ERROR
237 238
            pBuffer = ippsMalloc_8u(bufferSize);
            if (NULL == pBuffer)
V
vbystricky 已提交
239
                IPP_RETURN_ERROR
240
            sts = ippiFilterScharrHorizMaskBorder_8u16s_C1R(src.data, (int)src.step, (Ipp16s *)dst.data, (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
241 242 243
        }
        else
        {
244
            if (0 > ippiFilterScharrVertMaskBorderGetBufferSize(roiSize, ippMskSize3x3, ipp8u, ipp16s, 1, &bufferSize))
V
vbystricky 已提交
245
                IPP_RETURN_ERROR
246 247
            pBuffer = ippsMalloc_8u(bufferSize);
            if (NULL == pBuffer)
V
vbystricky 已提交
248
                IPP_RETURN_ERROR
249
            sts = ippiFilterScharrVertMaskBorder_8u16s_C1R(src.data, (int)src.step, (Ipp16s *)dst.data, (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
250
        }
251
        ippsFree(pBuffer);
252 253 254
    }
    else if ((CV_16S == stype) && (CV_16S == dtype))
    {
V
vbystricky 已提交
255
        int bufferSize = 0; Ipp8u *pBuffer;
256 257
        if (horz)
        {
258
            if (0 > ippiFilterScharrHorizMaskBorderGetBufferSize(roiSize, ippMskSize3x3, ipp16s, ipp16s, 1, &bufferSize))
V
vbystricky 已提交
259
                IPP_RETURN_ERROR
260 261
            pBuffer = ippsMalloc_8u(bufferSize);
            if (NULL == pBuffer)
V
vbystricky 已提交
262
                IPP_RETURN_ERROR
263
            sts = ippiFilterScharrHorizMaskBorder_16s_C1R((Ipp16s *)src.data, (int)src.step, (Ipp16s *)dst.data, (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
264 265 266
        }
        else
        {
267
            if (0 > ippiFilterScharrVertMaskBorderGetBufferSize(roiSize, ippMskSize3x3, ipp16s, ipp16s, 1, &bufferSize))
V
vbystricky 已提交
268
                IPP_RETURN_ERROR
269 270
            pBuffer = ippsMalloc_8u(bufferSize);
            if (NULL == pBuffer)
V
vbystricky 已提交
271
                IPP_RETURN_ERROR
272
            sts = ippiFilterScharrVertMaskBorder_16s_C1R((Ipp16s *)src.data, (int)src.step, (Ipp16s *)dst.data, (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
273
        }
274
        ippsFree(pBuffer);
275 276 277
    }
    else if ((CV_32F == stype) && (CV_32F == dtype))
    {
V
vbystricky 已提交
278
        int bufferSize = 0; Ipp8u *pBuffer;
279 280
        if (horz)
        {
281
            if (0 > ippiFilterScharrHorizMaskBorderGetBufferSize(roiSize, ippMskSize3x3, ipp32f, ipp32f, 1, &bufferSize))
V
vbystricky 已提交
282
                IPP_RETURN_ERROR
283 284
            pBuffer = ippsMalloc_8u(bufferSize);
            if (NULL == pBuffer)
V
vbystricky 已提交
285
                IPP_RETURN_ERROR
286
            sts = ippiFilterScharrHorizMaskBorder_32f_C1R((Ipp32f *)src.data, (int)src.step, (Ipp32f *)dst.data, (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
287 288 289
        }
        else
        {
290
            if (0 > ippiFilterScharrVertMaskBorderGetBufferSize(roiSize, ippMskSize3x3, ipp32f, ipp32f, 1, &bufferSize))
V
vbystricky 已提交
291
                IPP_RETURN_ERROR
292 293
            pBuffer = ippsMalloc_8u(bufferSize);
            if (NULL == pBuffer)
V
vbystricky 已提交
294
                IPP_RETURN_ERROR
295
            sts = ippiFilterScharrVertMaskBorder_32f_C1R((Ipp32f *)src.data, (int)src.step, (Ipp32f *)dst.data, (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
296
        }
297 298
        ippsFree(pBuffer);
        if (sts < 0)
V
vbystricky 已提交
299
            IPP_RETURN_ERROR;
300

301
        if (FLT_EPSILON < fabs(scale - 1.0))
V
vbystricky 已提交
302
            sts = ippiMulC_32f_C1R((Ipp32f *)dst.data, (int)dst.step, (Ipp32f)scale, (Ipp32f *)dst.data, (int)dst.step, roiSize);
303
    }
V
vbystricky 已提交
304
    return (0 <= sts);
305
}
A
Alexander Alekhin 已提交
306
#elif IPP_VERSION_X100 >= 700
307
static bool IPPDerivScharr(InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, double scale, double delta, int borderType)
308
{
V
vbystricky 已提交
309
    if (BORDER_REPLICATE != borderType)
310 311 312
        return false;
    if ((0 > dx) || (0 > dy) || (1 != dx + dy))
        return false;
V
vbystricky 已提交
313
    if (fabs(delta) > FLT_EPSILON)
314 315 316 317
        return false;

    Mat src = _src.getMat(), dst = _dst.getMat();

318 319 320
    int bufSize = 0;
    cv::AutoBuffer<char> buffer;
    IppiSize roi = ippiSize(src.cols, src.rows);
321

322 323
    if( ddepth < 0 )
        ddepth = src.depth();
324

325
    dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) );
326

327 328
    switch(src.type())
    {
I
Ilya Lavrenov 已提交
329
    case CV_8UC1:
330
        {
331 332 333 334 335
            if(scale != 1)
                return false;

            switch(dst.type())
            {
336 337 338 339
            case CV_16S:
                {
                    if ((dx == 1) && (dy == 0))
                    {
340
                        if (0 > ippiFilterScharrVertGetBufferSize_8u16s_C1R(roi,&bufSize))
341 342
                            return false;
                        buffer.allocate(bufSize);
343
                        return (0 <= ippiFilterScharrVertBorder_8u16s_C1R((const Ipp8u*)src.data, (int)src.step,
344 345 346 347
                                        (Ipp16s*)dst.data, (int)dst.step, roi, ippBorderRepl, 0, (Ipp8u*)(char*)buffer));
                    }
                    if ((dx == 0) && (dy == 1))
                    {
348
                        if (0 > ippiFilterScharrHorizGetBufferSize_8u16s_C1R(roi,&bufSize))
349 350
                            return false;
                        buffer.allocate(bufSize);
351
                        return (0 <= ippiFilterScharrHorizBorder_8u16s_C1R((const Ipp8u*)src.data, (int)src.step,
352 353 354 355 356 357 358 359
                                            (Ipp16s*)dst.data, (int)dst.step, roi, ippBorderRepl, 0, (Ipp8u*)(char*)buffer));
                    }
                    return false;
                }
            default:
                return false;
            }
        }
I
Ilya Lavrenov 已提交
360
    case CV_32FC1:
361 362 363
        {
            switch(dst.type())
            {
I
Ilya Lavrenov 已提交
364
            case CV_32FC1:
365 366 367
                {
                    if ((dx == 1) && (dy == 0))
                    {
368
                        if (0 > ippiFilterScharrVertGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows),&bufSize))
369 370 371
                            return false;
                        buffer.allocate(bufSize);

372
                        if (0 > ippiFilterScharrVertBorder_32f_C1R((const Ipp32f*)src.data, (int)src.step,
373 374 375 376 377 378 379 380
                                        (Ipp32f*)dst.data, (int)dst.step, ippiSize(src.cols, src.rows),
                                        ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                        {
                            return false;
                        }

                        if (scale != 1)
                            /* IPP is fast, so MulC produce very little perf degradation.*/
381 382
                            //ippiMulC_32f_C1IR((Ipp32f)scale, (Ipp32f*)dst.data, (int)dst.step, ippiSize(dst.cols*dst.channels(), dst.rows));
                            ippiMulC_32f_C1R((Ipp32f*)dst.data, (int)dst.step, (Ipp32f)scale, (Ipp32f*)dst.data, (int)dst.step, ippiSize(dst.cols*dst.channels(), dst.rows));
383 384 385 386
                        return true;
                    }
                    if ((dx == 0) && (dy == 1))
                    {
387
                        if (0 > ippiFilterScharrHorizGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows),&bufSize))
388 389 390
                            return false;
                        buffer.allocate(bufSize);

391
                        if (0 > ippiFilterScharrHorizBorder_32f_C1R((const Ipp32f*)src.data, (int)src.step,
392 393 394 395 396
                                        (Ipp32f*)dst.data, (int)dst.step, ippiSize(src.cols, src.rows),
                                        ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                            return false;

                        if (scale != 1)
397
                            ippiMulC_32f_C1R((Ipp32f *)dst.data, (int)dst.step, (Ipp32f)scale, (Ipp32f *)dst.data, (int)dst.step, ippiSize(dst.cols*dst.channels(), dst.rows));
398 399 400 401 402 403 404 405 406 407 408
                        return true;
                    }
                }
            default:
                return false;
            }
        }
    default:
        return false;
    }
}
409
#endif
410

V
vbystricky 已提交
411
static bool IPPDerivSobel(InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType)
412
{
A
Alexander Alekhin 已提交
413
    if ((borderType != BORDER_REPLICATE) || ((3 != ksize) && (5 != ksize)))
414
        return false;
415
    if (fabs(delta) > FLT_EPSILON)
416
        return false;
V
vbystricky 已提交
417 418
    if (1 != _src.channels())
        return false;
419 420

    int bufSize = 0;
421
    cv::AutoBuffer<char> buffer;
422 423 424 425 426
    Mat src = _src.getMat(), dst = _dst.getMat();
    if ( ddepth < 0 )
        ddepth = src.depth();

    if (src.type() == CV_8U && dst.type() == CV_16S && scale == 1)
427
    {
428
        if ((dx == 1) && (dy == 0))
429
        {
430
            if (0 > ippiFilterSobelNegVertGetBufferSize_8u16s_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize))
V
vbystricky 已提交
431
                IPP_RETURN_ERROR
432
            buffer.allocate(bufSize);
433

V
vbystricky 已提交
434
            if (0 > ippiFilterSobelNegVertBorder_8u16s_C1R((const Ipp8u*)src.data, (int)src.step,
435
                                (Ipp16s*)dst.data, (int)dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),
V
vbystricky 已提交
436 437 438
                                ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                IPP_RETURN_ERROR
            return true;
439
        }
440

441 442 443
        if ((dx == 0) && (dy == 1))
        {
            if (0 > ippiFilterSobelHorizGetBufferSize_8u16s_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize))
V
vbystricky 已提交
444
                IPP_RETURN_ERROR
445
            buffer.allocate(bufSize);
446

V
vbystricky 已提交
447
            if (0 > ippiFilterSobelHorizBorder_8u16s_C1R((const Ipp8u*)src.data, (int)src.step,
448
                                (Ipp16s*)dst.data, (int)dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),
V
vbystricky 已提交
449 450 451
                                ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                IPP_RETURN_ERROR
            return true;
452
        }
453

A
Alexander Alekhin 已提交
454
#if !defined(HAVE_IPP_ICV_ONLY)
455 456 457
        if ((dx == 2) && (dy == 0))
        {
            if (0 > ippiFilterSobelVertSecondGetBufferSize_8u16s_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize))
V
vbystricky 已提交
458
                IPP_RETURN_ERROR
459
            buffer.allocate(bufSize);
460

V
vbystricky 已提交
461
            if (0 > ippiFilterSobelVertSecondBorder_8u16s_C1R((const Ipp8u*)src.data, (int)src.step,
462
                                (Ipp16s*)dst.data, (int)dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),
V
vbystricky 已提交
463 464 465
                                ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                IPP_RETURN_ERROR
            return true;
466
        }
467

468 469 470
        if ((dx == 0) && (dy == 2))
        {
            if (0 > ippiFilterSobelHorizSecondGetBufferSize_8u16s_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize))
V
vbystricky 已提交
471
                IPP_RETURN_ERROR
472
            buffer.allocate(bufSize);
473

V
vbystricky 已提交
474
            if (0 > ippiFilterSobelHorizSecondBorder_8u16s_C1R((const Ipp8u*)src.data, (int)src.step,
475
                                (Ipp16s*)dst.data, (int)dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),
V
vbystricky 已提交
476 477 478
                                ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                IPP_RETURN_ERROR
            return true;
479
        }
A
Alexander Alekhin 已提交
480
#endif
481
    }
482

483 484
    if (src.type() == CV_32F && dst.type() == CV_32F)
    {
I
Ilya Lavrenov 已提交
485
#if 0
486 487 488
        if ((dx == 1) && (dy == 0))
        {
            if (0 > ippiFilterSobelNegVertGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize), &bufSize))
V
vbystricky 已提交
489
                IPP_RETURN_ERROR
490
            buffer.allocate(bufSize);
491

492 493 494
            if (0 > ippiFilterSobelNegVertBorder_32f_C1R((const Ipp32f*)src.data, (int)src.step,
                            (Ipp32f*)dst.data, (int)dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),
                            ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
V
vbystricky 已提交
495
                IPP_RETURN_ERROR
496 497 498 499
            if(scale != 1)
                ippiMulC_32f_C1R((Ipp32f *)dst.data, (int)dst.step, (Ipp32f)scale, (Ipp32f *)dst.data, (int)dst.step, ippiSize(dst.cols*dst.channels(), dst.rows));
            return true;
        }
500

501 502 503
        if ((dx == 0) && (dy == 1))
        {
            if (0 > ippiFilterSobelHorizGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize))
V
vbystricky 已提交
504
                IPP_RETURN_ERROR
505 506 507 508
            buffer.allocate(bufSize);
            if (0 > ippiFilterSobelHorizBorder_32f_C1R((const Ipp32f*)src.data, (int)src.step,
                            (Ipp32f*)dst.data, (int)dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),
                            ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
V
vbystricky 已提交
509
                IPP_RETURN_ERROR
510 511 512 513
            if(scale != 1)
                ippiMulC_32f_C1R((Ipp32f *)dst.data, (int)dst.step, (Ipp32f)scale, (Ipp32f *)dst.data, (int)dst.step, ippiSize(dst.cols*dst.channels(), dst.rows));
            return true;
        }
I
Ilya Lavrenov 已提交
514
#endif
A
Alexander Alekhin 已提交
515
#if !defined(HAVE_IPP_ICV_ONLY)
516 517 518
        if((dx == 2) && (dy == 0))
        {
            if (0 > ippiFilterSobelVertSecondGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize))
V
vbystricky 已提交
519
                IPP_RETURN_ERROR
520
            buffer.allocate(bufSize);
521

522 523 524
            if (0 > ippiFilterSobelVertSecondBorder_32f_C1R((const Ipp32f*)src.data, (int)src.step,
                            (Ipp32f*)dst.data, (int)dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),
                            ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
V
vbystricky 已提交
525
                IPP_RETURN_ERROR
526 527 528 529
            if(scale != 1)
                ippiMulC_32f_C1R((Ipp32f *)dst.data, (int)dst.step, (Ipp32f)scale, (Ipp32f *)dst.data, (int)dst.step, ippiSize(dst.cols*dst.channels(), dst.rows));
            return true;
        }
530

531 532 533
        if((dx == 0) && (dy == 2))
        {
            if (0 > ippiFilterSobelHorizSecondGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize))
V
vbystricky 已提交
534
                IPP_RETURN_ERROR
535
            buffer.allocate(bufSize);
536

537 538 539
            if (0 > ippiFilterSobelHorizSecondBorder_32f_C1R((const Ipp32f*)src.data, (int)src.step,
                            (Ipp32f*)dst.data, (int)dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),
                            ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
V
vbystricky 已提交
540
                IPP_RETURN_ERROR
541 542 543 544

            if(scale != 1)
                ippiMulC_32f_C1R((Ipp32f *)dst.data, (int)dst.step, (Ipp32f)scale, (Ipp32f *)dst.data, (int)dst.step, ippiSize(dst.cols*dst.channels(), dst.rows));
            return true;
545
        }
546
#endif
547 548
    }
    return false;
549 550
}

551
}
552

553 554
#endif

555
void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
556
                int ksize, double scale, double delta, int borderType )
557
{
558
    int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
559
    if (ddepth < 0)
560
        ddepth = sdepth;
I
Ilya Lavrenov 已提交
561 562
    int dtype = CV_MAKE_TYPE(ddepth, cn);
    _dst.create( _src.size(), dtype );
563 564 565 566

#ifdef HAVE_TEGRA_OPTIMIZATION
    if (scale == 1.0 && delta == 0)
    {
567
        Mat src = _src.getMat(), dst = _dst.getMat();
568 569 570 571 572 573
        if (ksize == 3 && tegra::sobel3x3(src, dst, dx, dy, borderType))
            return;
        if (ksize == -1 && tegra::scharr(src, dst, dx, dy, borderType))
            return;
    }
#endif
574

A
Alexander Alekhin 已提交
575
#ifdef HAVE_IPP
576
    if (ksize < 0)
577
    {
578 579 580
        if (IPPDerivScharr(_src, _dst, ddepth, dx, dy, scale, delta, borderType))
            return;
    }
V
vbystricky 已提交
581
    else if (0 < ksize)
582
    {
V
vbystricky 已提交
583
        if (IPPDerivSobel(_src, _dst, ddepth, dx, dy, ksize, scale, delta, borderType))
584 585
            return;
    }
586
#endif
587
    int ktype = std::max(CV_32F, std::max(ddepth, sdepth));
588 589 590 591 592 593 594 595 596 597 598 599

    Mat kx, ky;
    getDerivKernels( kx, ky, dx, dy, ksize, false, ktype );
    if( scale != 1 )
    {
        // usually the smoothing part is the slowest to compute,
        // so try to scale it instead of the faster differenciating part
        if( dx == 0 )
            kx *= scale;
        else
            ky *= scale;
    }
600
    sepFilter2D( _src, _dst, ddepth, kx, ky, Point(-1, -1), delta, borderType );
601 602 603
}


604
void cv::Scharr( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
605
                 double scale, double delta, int borderType )
606
{
607
    int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
608
    if (ddepth < 0)
609
        ddepth = sdepth;
I
Ilya Lavrenov 已提交
610 611
    int dtype = CV_MAKETYPE(ddepth, cn);
    _dst.create( _src.size(), dtype );
612 613 614

#ifdef HAVE_TEGRA_OPTIMIZATION
    if (scale == 1.0 && delta == 0)
615 616
    {
        Mat src = _src.getMat(), dst = _dst.getMat();
617 618
        if (tegra::scharr(src, dst, dx, dy, borderType))
            return;
619
    }
620
#endif
621

622
#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7)
623 624
    if (IPPDerivScharr(_src, _dst, ddepth, dx, dy, scale, delta, borderType))
        return;
625
#endif
626
    int ktype = std::max(CV_32F, std::max(ddepth, sdepth));
627 628 629 630 631 632 633 634 635 636 637 638

    Mat kx, ky;
    getScharrKernels( kx, ky, dx, dy, false, ktype );
    if( scale != 1 )
    {
        // usually the smoothing part is the slowest to compute,
        // so try to scale it instead of the faster differenciating part
        if( dx == 0 )
            kx *= scale;
        else
            ky *= scale;
    }
639
    sepFilter2D( _src, _dst, ddepth, kx, ky, Point(-1, -1), delta, borderType );
640 641
}

642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
#ifdef HAVE_OPENCL

namespace cv {

static bool ocl_Laplacian5(InputArray _src, OutputArray _dst,
                           const Mat & kd, const Mat & ks, double scale, double delta,
                           int borderType, int depth, int ddepth)
{
    int iscale = cvRound(scale), idelta = cvRound(delta);
    bool doubleSupport = ocl::Device::getDefault().doubleFPConfig() > 0,
            floatCoeff = std::fabs(delta - idelta) > DBL_EPSILON || std::fabs(scale - iscale) > DBL_EPSILON;
    int cn = _src.channels(), wdepth = std::max(depth, floatCoeff ? CV_32F : CV_32S), kercn = 1;

    if (!doubleSupport && wdepth == CV_64F)
        return false;

    char cvt[2][40];
    ocl::Kernel k("sumConvert", ocl::imgproc::laplacian5_oclsrc,
                  format("-D srcT=%s -D WT=%s -D dstT=%s -D coeffT=%s -D wdepth=%d "
                         "-D convertToWT=%s -D convertToDT=%s%s",
                         ocl::typeToStr(CV_MAKE_TYPE(depth, kercn)),
                         ocl::typeToStr(CV_MAKE_TYPE(wdepth, kercn)),
                         ocl::typeToStr(CV_MAKE_TYPE(ddepth, kercn)),
                         ocl::typeToStr(wdepth), wdepth,
                         ocl::convertTypeStr(depth, wdepth, kercn, cvt[0]),
                         ocl::convertTypeStr(wdepth, ddepth, kercn, cvt[1]),
                         doubleSupport ? " -D DOUBLE_SUPPORT" : ""));
    if (k.empty())
        return false;

    UMat d2x, d2y;
    sepFilter2D(_src, d2x, depth, kd, ks, Point(-1, -1), 0, borderType);
    sepFilter2D(_src, d2y, depth, ks, kd, Point(-1, -1), 0, borderType);

    UMat dst = _dst.getUMat();

    ocl::KernelArg d2xarg = ocl::KernelArg::ReadOnlyNoSize(d2x),
            d2yarg = ocl::KernelArg::ReadOnlyNoSize(d2y),
            dstarg = ocl::KernelArg::WriteOnly(dst, cn, kercn);

    if (wdepth >= CV_32F)
        k.args(d2xarg, d2yarg, dstarg, (float)scale, (float)delta);
    else
        k.args(d2xarg, d2yarg, dstarg, iscale, idelta);

    size_t globalsize[] = { dst.cols * cn / kercn, dst.rows };
    return k.run(2, globalsize, NULL, false);
}

}

#endif
694

695
void cv::Laplacian( InputArray _src, OutputArray _dst, int ddepth, int ksize,
696
                    double scale, double delta, int borderType )
697
{
698
    int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
699
    if (ddepth < 0)
700 701
        ddepth = sdepth;
    _dst.create( _src.size(), CV_MAKETYPE(ddepth, cn) );
702

A
Alexander Alekhin 已提交
703
#ifdef HAVE_IPP
I
Ilya Lavrenov 已提交
704
    if ((ksize == 3 || ksize == 5) && ((borderType & BORDER_ISOLATED) != 0 || !_src.isSubmatrix()) &&
I
Ilya Lavrenov 已提交
705
        ((stype == CV_8UC1 && ddepth == CV_16S) || (ddepth == CV_32F && stype == CV_32FC1)) && !ocl::useOpenCL())
I
Ilya Lavrenov 已提交
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
    {
        int iscale = saturate_cast<int>(scale), idelta = saturate_cast<int>(delta);
        bool floatScale = std::fabs(scale - iscale) > DBL_EPSILON, needScale = iscale != 1;
        bool floatDelta = std::fabs(delta - idelta) > DBL_EPSILON, needDelta = delta != 0;
        int borderTypeNI = borderType & ~BORDER_ISOLATED;
        Mat src = _src.getMat(), dst = _dst.getMat();

        if (src.data != dst.data)
        {
            Ipp32s bufsize;
            IppStatus status = (IppStatus)-1;
            IppiSize roisize = { src.cols, src.rows };
            IppiMaskSize masksize = ksize == 3 ? ippMskSize3x3 : ippMskSize5x5;
            IppiBorderType borderTypeIpp = ippiGetBorderType(borderTypeNI);

#define IPP_FILTER_LAPLACIAN(ippsrctype, ippdsttype, ippfavor) \
    do \
    { \
        if (borderTypeIpp >= 0 && ippiFilterLaplacianGetBufferSize_##ippfavor##_C1R(roisize, masksize, &bufsize) >= 0) \
        { \
            Ipp8u * buffer = ippsMalloc_8u(bufsize); \
            status = ippiFilterLaplacianBorder_##ippfavor##_C1R((const ippsrctype *)src.data, (int)src.step, (ippdsttype *)dst.data, \
                                                                (int)dst.step, roisize, masksize, borderTypeIpp, 0, buffer); \
            ippsFree(buffer); \
        } \
    } while ((void)0, 0)

I
Ilya Lavrenov 已提交
733
            CV_SUPPRESS_DEPRECATED_START
I
Ilya Lavrenov 已提交
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751
            if (sdepth == CV_8U && ddepth == CV_16S && !floatScale && !floatDelta)
            {
                IPP_FILTER_LAPLACIAN(Ipp8u, Ipp16s, 8u16s);

                if (needScale && status >= 0)
                    status = ippiMulC_16s_C1IRSfs((Ipp16s)iscale, (Ipp16s *)dst.data, (int)dst.step, roisize, 0);
                if (needDelta && status >= 0)
                    status = ippiAddC_16s_C1IRSfs((Ipp16s)idelta, (Ipp16s *)dst.data, (int)dst.step, roisize, 0);
            }
            else if (sdepth == CV_32F && ddepth == CV_32F)
            {
                IPP_FILTER_LAPLACIAN(Ipp32f, Ipp32f, 32f);

                if (needScale && status >= 0)
                    status = ippiMulC_32f_C1IR((Ipp32f)scale, (Ipp32f *)dst.data, (int)dst.step, roisize);
                if (needDelta && status >= 0)
                    status = ippiAddC_32f_C1IR((Ipp32f)delta, (Ipp32f *)dst.data, (int)dst.step, roisize);
            }
I
Ilya Lavrenov 已提交
752
            CV_SUPPRESS_DEPRECATED_END
I
Ilya Lavrenov 已提交
753 754 755

            if (status >= 0)
                return;
I
Ilya Lavrenov 已提交
756
            setIppErrorStatus();
I
Ilya Lavrenov 已提交
757 758 759 760 761
        }
    }
#undef IPP_FILTER_LAPLACIAN
#endif

762 763 764
#ifdef HAVE_TEGRA_OPTIMIZATION
    if (scale == 1.0 && delta == 0)
    {
765
        Mat src = _src.getMat(), dst = _dst.getMat();
766
        if (ksize == 1 && tegra::laplace1(src, dst, borderType))
767
            return;
768
        if (ksize == 3 && tegra::laplace3(src, dst, borderType))
769
            return;
770
        if (ksize == 5 && tegra::laplace5(src, dst, borderType))
771 772 773
            return;
    }
#endif
774

775 776 777
    if( ksize == 1 || ksize == 3 )
    {
        float K[2][9] =
778 779 780 781
        {
            { 0, 1, 0, 1, -4, 1, 0, 1, 0 },
            { 2, 0, 2, 0, -8, 0, 2, 0, 2 }
        };
782 783 784
        Mat kernel(3, 3, CV_32F, K[ksize == 3]);
        if( scale != 1 )
            kernel *= scale;
785
        filter2D( _src, _dst, ddepth, kernel, Point(-1, -1), delta, borderType );
786 787 788
    }
    else
    {
789 790 791
        int ktype = std::max(CV_32F, std::max(ddepth, sdepth));
        int wdepth = sdepth == CV_8U && ksize <= 5 ? CV_16S : sdepth <= CV_32F ? CV_32F : CV_64F;
        int wtype = CV_MAKETYPE(wdepth, cn);
792 793 794
        Mat kd, ks;
        getSobelKernels( kd, ks, 2, 0, ksize, false, ktype );

795 796 797 798 799 800
        CV_OCL_RUN(_dst.isUMat(),
                   ocl_Laplacian5(_src, _dst, kd, ks, scale,
                                  delta, borderType, wdepth, ddepth))

        const size_t STRIPE_SIZE = 1 << 14;
        Ptr<FilterEngine> fx = createSeparableLinearFilter(stype,
801
            wtype, kd, ks, Point(-1,-1), 0, borderType, borderType, Scalar() );
802
        Ptr<FilterEngine> fy = createSeparableLinearFilter(stype,
803 804
            wtype, ks, kd, Point(-1,-1), 0, borderType, borderType, Scalar() );

805
        Mat src = _src.getMat(), dst = _dst.getMat();
806 807 808 809
        int y = fx->start(src), dsty = 0, dy = 0;
        fy->start(src);
        const uchar* sptr = src.data + y*src.step;

810
        int dy0 = std::min(std::max((int)(STRIPE_SIZE/(CV_ELEM_SIZE(stype)*src.cols)), 1), src.rows);
811 812 813 814 815 816 817 818 819 820 821 822
        Mat d2x( dy0 + kd.rows - 1, src.cols, wtype );
        Mat d2y( dy0 + kd.rows - 1, src.cols, wtype );

        for( ; dsty < src.rows; sptr += dy0*src.step, dsty += dy )
        {
            fx->proceed( sptr, (int)src.step, dy0, d2x.data, (int)d2x.step );
            dy = fy->proceed( sptr, (int)src.step, dy0, d2y.data, (int)d2y.step );
            if( dy > 0 )
            {
                Mat dstripe = dst.rowRange(dsty, dsty + dy);
                d2x.rows = d2y.rows = dy; // modify the headers, which should work
                d2x += d2y;
823
                d2x.convertTo( dstripe, ddepth, scale, delta );
824 825 826 827 828 829 830 831 832 833 834 835
            }
        }
    }
}

/////////////////////////////////////////////////////////////////////////////////////////

CV_IMPL void
cvSobel( const void* srcarr, void* dstarr, int dx, int dy, int aperture_size )
{
    cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);

836
    CV_Assert( src.size() == dst.size() && src.channels() == dst.channels() );
837 838 839 840 841 842 843 844 845 846 847 848

    cv::Sobel( src, dst, dst.depth(), dx, dy, aperture_size, 1, 0, cv::BORDER_REPLICATE );
    if( CV_IS_IMAGE(srcarr) && ((IplImage*)srcarr)->origin && dy % 2 != 0 )
        dst *= -1;
}


CV_IMPL void
cvLaplace( const void* srcarr, void* dstarr, int aperture_size )
{
    cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);

849
    CV_Assert( src.size() == dst.size() && src.channels() == dst.channels() );
850 851 852 853 854

    cv::Laplacian( src, dst, dst.depth(), aperture_size, 1, 0, cv::BORDER_REPLICATE );
}

/* End of file. */