deriv.cpp 33.0 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
{
192 193 194
#if (IPP_VERSION_X100 >= 801)
static bool IPPDerivScharr(InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, double scale, double delta, int borderType)
{
195
#if defined(HAVE_IPP_ICV_ONLY)
V
vbystricky 已提交
196 197
    _src; _dst; ddepth; dx; dy; scale; delta; borderType;
    return false;
198
#else
199 200
    if ((0 > dx) || (0 > dy) || (1 != dx + dy))
        return false;
V
vbystricky 已提交
201
    if (fabs(delta) > FLT_EPSILON)
202 203
        return false;

V
vbystricky 已提交
204
    IppiBorderType ippiBorderType = ippiGetBorderType(borderType & (~BORDER_ISOLATED));
205
    if ((int)ippiBorderType < 0)
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
        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};

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

305
        if (FLT_EPSILON < fabs(scale - 1.0))
V
vbystricky 已提交
306
            sts = ippiMulC_32f_C1R((Ipp32f *)dst.data, (int)dst.step, (Ipp32f)scale, (Ipp32f *)dst.data, (int)dst.step, roiSize);
307
    }
V
vbystricky 已提交
308
    return (0 <= sts);
309
#endif
310 311 312
}
#elif (IPP_VERSION_MAJOR >= 7)
static bool IPPDerivScharr(InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, double scale, double delta, int borderType)
313
{
V
vbystricky 已提交
314
    if (BORDER_REPLICATE != borderType)
315 316 317
        return false;
    if ((0 > dx) || (0 > dy) || (1 != dx + dy))
        return false;
V
vbystricky 已提交
318
    if (fabs(delta) > FLT_EPSILON)
319 320 321 322
        return false;

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

323 324 325
    int bufSize = 0;
    cv::AutoBuffer<char> buffer;
    IppiSize roi = ippiSize(src.cols, src.rows);
326

327 328
    if( ddepth < 0 )
        ddepth = src.depth();
329

330
    dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) );
331

332 333
    switch(src.type())
    {
I
Ilya Lavrenov 已提交
334
    case CV_8UC1:
335
        {
336 337 338 339 340
            if(scale != 1)
                return false;

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

380
                        if (0 > ippiFilterScharrVertBorder_32f_C1R((const Ipp32f*)src.data, (int)src.step,
381 382 383 384 385 386 387 388
                                        (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.*/
389 390
                            //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));
391 392 393 394
                        return true;
                    }
                    if ((dx == 0) && (dy == 1))
                    {
395
                        if (0 > ippiFilterScharrHorizGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows),&bufSize))
396 397 398
                            return false;
                        buffer.allocate(bufSize);

399
                        if (0 > ippiFilterScharrHorizBorder_32f_C1R((const Ipp32f*)src.data, (int)src.step,
400 401 402 403 404
                                        (Ipp32f*)dst.data, (int)dst.step, ippiSize(src.cols, src.rows),
                                        ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                            return false;

                        if (scale != 1)
405
                            ippiMulC_32f_C1R((Ipp32f *)dst.data, (int)dst.step, (Ipp32f)scale, (Ipp32f *)dst.data, (int)dst.step, ippiSize(dst.cols*dst.channels(), dst.rows));
406 407 408 409 410 411 412
                        return true;
                    }
                }
            default:
                return false;
            }
        }
413
#endif
414 415 416 417
    default:
        return false;
    }
}
418
#endif
419

V
vbystricky 已提交
420
static bool IPPDerivSobel(InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType)
421
{
V
vbystricky 已提交
422
    if ((borderType != BORDER_REPLICATE) || (3 != ksize) || (5 != ksize))
423
        return false;
424
    if (fabs(delta) > FLT_EPSILON)
425
        return false;
V
vbystricky 已提交
426 427
    if (1 != _src.channels())
        return false;
428 429

    int bufSize = 0;
430
    cv::AutoBuffer<char> buffer;
431 432 433 434 435
    Mat src = _src.getMat(), dst = _dst.getMat();
    if ( ddepth < 0 )
        ddepth = src.depth();

    if (src.type() == CV_8U && dst.type() == CV_16S && scale == 1)
436
    {
437
        if ((dx == 1) && (dy == 0))
438
        {
439
            if (0 > ippiFilterSobelNegVertGetBufferSize_8u16s_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize))
V
vbystricky 已提交
440
                IPP_RETURN_ERROR
441
            buffer.allocate(bufSize);
442

V
vbystricky 已提交
443
            if (0 > ippiFilterSobelNegVertBorder_8u16s_C1R((const Ipp8u*)src.data, (int)src.step,
444
                                (Ipp16s*)dst.data, (int)dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),
V
vbystricky 已提交
445 446 447
                                ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                IPP_RETURN_ERROR
            return true;
448
        }
449

450 451 452
        if ((dx == 0) && (dy == 1))
        {
            if (0 > ippiFilterSobelHorizGetBufferSize_8u16s_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize))
V
vbystricky 已提交
453
                IPP_RETURN_ERROR
454
            buffer.allocate(bufSize);
455

V
vbystricky 已提交
456
            if (0 > ippiFilterSobelHorizBorder_8u16s_C1R((const Ipp8u*)src.data, (int)src.step,
457
                                (Ipp16s*)dst.data, (int)dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),
V
vbystricky 已提交
458 459 460
                                ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                IPP_RETURN_ERROR
            return true;
461
        }
462

463 464 465
        if ((dx == 2) && (dy == 0))
        {
            if (0 > ippiFilterSobelVertSecondGetBufferSize_8u16s_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize))
V
vbystricky 已提交
466
                IPP_RETURN_ERROR
467
            buffer.allocate(bufSize);
468

V
vbystricky 已提交
469
            if (0 > ippiFilterSobelVertSecondBorder_8u16s_C1R((const Ipp8u*)src.data, (int)src.step,
470
                                (Ipp16s*)dst.data, (int)dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),
V
vbystricky 已提交
471 472 473
                                ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                IPP_RETURN_ERROR
            return true;
474
        }
475

476 477 478
        if ((dx == 0) && (dy == 2))
        {
            if (0 > ippiFilterSobelHorizSecondGetBufferSize_8u16s_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize))
V
vbystricky 已提交
479
                IPP_RETURN_ERROR
480
            buffer.allocate(bufSize);
481

V
vbystricky 已提交
482
            if (0 > ippiFilterSobelHorizSecondBorder_8u16s_C1R((const Ipp8u*)src.data, (int)src.step,
483
                                (Ipp16s*)dst.data, (int)dst.step, ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),
V
vbystricky 已提交
484 485 486
                                ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                IPP_RETURN_ERROR
            return true;
487
        }
488
    }
489

490 491
    if (src.type() == CV_32F && dst.type() == CV_32F)
    {
492
#if defined(HAVE_IPP_ICV_ONLY) // N/A: ippiMulC_32f_C1R
493
        return false;
494
#else
I
Ilya Lavrenov 已提交
495
#if 0
496 497 498
        if ((dx == 1) && (dy == 0))
        {
            if (0 > ippiFilterSobelNegVertGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize), &bufSize))
V
vbystricky 已提交
499
                IPP_RETURN_ERROR
500
            buffer.allocate(bufSize);
501

502 503 504
            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 已提交
505
                IPP_RETURN_ERROR
506 507 508 509
            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;
        }
510

511 512 513
        if ((dx == 0) && (dy == 1))
        {
            if (0 > ippiFilterSobelHorizGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize))
V
vbystricky 已提交
514
                IPP_RETURN_ERROR
515 516 517 518
            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 已提交
519
                IPP_RETURN_ERROR
520 521 522 523
            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 已提交
524
#endif
525 526 527
        if((dx == 2) && (dy == 0))
        {
            if (0 > ippiFilterSobelVertSecondGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize))
V
vbystricky 已提交
528
                IPP_RETURN_ERROR
529
            buffer.allocate(bufSize);
530

531 532 533
            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 已提交
534
                IPP_RETURN_ERROR
535 536 537 538
            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;
        }
539

540 541 542
        if((dx == 0) && (dy == 2))
        {
            if (0 > ippiFilterSobelHorizSecondGetBufferSize_32f_C1R(ippiSize(src.cols, src.rows), (IppiMaskSize)(ksize*10+ksize),&bufSize))
V
vbystricky 已提交
543
                IPP_RETURN_ERROR
544
            buffer.allocate(bufSize);
545

546 547 548
            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 已提交
549
                IPP_RETURN_ERROR
550 551 552 553

            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;
554
        }
555
#endif
556 557
    }
    return false;
558 559
}

560
}
561

562 563
#endif

564
void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
565
                int ksize, double scale, double delta, int borderType )
566
{
567
    int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
568
    if (ddepth < 0)
569
        ddepth = sdepth;
I
Ilya Lavrenov 已提交
570 571
    int dtype = CV_MAKE_TYPE(ddepth, cn);
    _dst.create( _src.size(), dtype );
572 573 574 575

#ifdef HAVE_TEGRA_OPTIMIZATION
    if (scale == 1.0 && delta == 0)
    {
576
        Mat src = _src.getMat(), dst = _dst.getMat();
577 578 579 580 581 582
        if (ksize == 3 && tegra::sobel3x3(src, dst, dx, dy, borderType))
            return;
        if (ksize == -1 && tegra::scharr(src, dst, dx, dy, borderType))
            return;
    }
#endif
583

584
#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7)
585
    if (ksize < 0)
586
    {
587 588 589
        if (IPPDerivScharr(_src, _dst, ddepth, dx, dy, scale, delta, borderType))
            return;
    }
V
vbystricky 已提交
590
    else if (0 < ksize)
591
    {
V
vbystricky 已提交
592
        if (IPPDerivSobel(_src, _dst, ddepth, dx, dy, ksize, scale, delta, borderType))
593 594
            return;
    }
595
#endif
596
    int ktype = std::max(CV_32F, std::max(ddepth, sdepth));
597 598 599 600 601 602 603 604 605 606 607 608

    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;
    }
609
    sepFilter2D( _src, _dst, ddepth, kx, ky, Point(-1, -1), delta, borderType );
610 611 612
}


613
void cv::Scharr( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
614
                 double scale, double delta, int borderType )
615
{
616
    int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
617
    if (ddepth < 0)
618
        ddepth = sdepth;
I
Ilya Lavrenov 已提交
619 620
    int dtype = CV_MAKETYPE(ddepth, cn);
    _dst.create( _src.size(), dtype );
621 622 623

#ifdef HAVE_TEGRA_OPTIMIZATION
    if (scale == 1.0 && delta == 0)
624 625
    {
        Mat src = _src.getMat(), dst = _dst.getMat();
626 627
        if (tegra::scharr(src, dst, dx, dy, borderType))
            return;
628
    }
629
#endif
630

631
#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7)
632 633
    if (IPPDerivScharr(_src, _dst, ddepth, dx, dy, scale, delta, borderType))
        return;
634
#endif
635
    int ktype = std::max(CV_32F, std::max(ddepth, sdepth));
636 637 638 639 640 641 642 643 644 645 646 647

    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;
    }
648
    sepFilter2D( _src, _dst, ddepth, kx, ky, Point(-1, -1), delta, borderType );
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 694 695 696 697 698 699 700 701 702
#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
703

704
void cv::Laplacian( InputArray _src, OutputArray _dst, int ddepth, int ksize,
705
                    double scale, double delta, int borderType )
706
{
707
    int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
708
    if (ddepth < 0)
709 710
        ddepth = sdepth;
    _dst.create( _src.size(), CV_MAKETYPE(ddepth, cn) );
711

I
Ilya Lavrenov 已提交
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
#if defined HAVE_IPP && !defined HAVE_IPP_ICV_ONLY
    if ((ksize == 3 || ksize == 5) && ((borderType & BORDER_ISOLATED) != 0 || !_src.isSubmatrix()) &&
        ((stype == CV_8UC1 && ddepth == CV_16S) || (ddepth == CV_32F && stype == CV_32FC1)))
    {
        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 已提交
742
            CV_SUPPRESS_DEPRECATED_START
I
Ilya Lavrenov 已提交
743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
            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 已提交
761
            CV_SUPPRESS_DEPRECATED_END
I
Ilya Lavrenov 已提交
762 763 764

            if (status >= 0)
                return;
I
Ilya Lavrenov 已提交
765
            setIppErrorStatus();
I
Ilya Lavrenov 已提交
766 767 768 769 770
        }
    }
#undef IPP_FILTER_LAPLACIAN
#endif

771 772 773
#ifdef HAVE_TEGRA_OPTIMIZATION
    if (scale == 1.0 && delta == 0)
    {
774
        Mat src = _src.getMat(), dst = _dst.getMat();
775
        if (ksize == 1 && tegra::laplace1(src, dst, borderType))
776
            return;
777
        if (ksize == 3 && tegra::laplace3(src, dst, borderType))
778
            return;
779
        if (ksize == 5 && tegra::laplace5(src, dst, borderType))
780 781 782
            return;
    }
#endif
783

784 785 786
    if( ksize == 1 || ksize == 3 )
    {
        float K[2][9] =
787 788 789 790
        {
            { 0, 1, 0, 1, -4, 1, 0, 1, 0 },
            { 2, 0, 2, 0, -8, 0, 2, 0, 2 }
        };
791 792 793
        Mat kernel(3, 3, CV_32F, K[ksize == 3]);
        if( scale != 1 )
            kernel *= scale;
794
        filter2D( _src, _dst, ddepth, kernel, Point(-1, -1), delta, borderType );
795 796 797
    }
    else
    {
798 799 800
        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);
801 802 803
        Mat kd, ks;
        getSobelKernels( kd, ks, 2, 0, ksize, false, ktype );

804 805 806 807 808 809
        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,
810
            wtype, kd, ks, Point(-1,-1), 0, borderType, borderType, Scalar() );
811
        Ptr<FilterEngine> fy = createSeparableLinearFilter(stype,
812 813
            wtype, ks, kd, Point(-1,-1), 0, borderType, borderType, Scalar() );

814
        Mat src = _src.getMat(), dst = _dst.getMat();
815 816 817 818
        int y = fx->start(src), dsty = 0, dy = 0;
        fy->start(src);
        const uchar* sptr = src.data + y*src.step;

819
        int dy0 = std::min(std::max((int)(STRIPE_SIZE/(CV_ELEM_SIZE(stype)*src.cols)), 1), src.rows);
820 821 822 823 824 825 826 827 828 829 830 831
        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;
832
                d2x.convertTo( dstripe, ddepth, scale, delta );
833 834 835 836 837 838 839 840 841 842 843 844
            }
        }
    }
}

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

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);

845
    CV_Assert( src.size() == dst.size() && src.channels() == dst.channels() );
846 847 848 849 850 851 852 853 854 855 856 857

    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);

858
    CV_Assert( src.size() == dst.size() && src.channels() == dst.channels() );
859 860 861 862 863

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

/* End of file. */