samplers.cpp 16.1 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*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.
//
//
10
//                           License Agreement
11 12 13
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
14
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
15 16 17 18 19 20 21 22 23 24 25 26
// 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.
//
27
//   * The name of the copyright holders may not be used to endorse or promote products
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
//     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"

45
namespace cv
46 47
{

48
static const uchar*
Andrey Kamaev's avatar
Andrey Kamaev committed
49
adjustRect( const uchar* src, size_t src_step, int pix_size,
50 51
           Size src_size, Size win_size,
           Point ip, Rect* pRect )
52
{
53
    Rect rect;
54 55 56 57 58 59 60 61 62 63 64 65 66

    if( ip.x >= 0 )
    {
        src += ip.x*pix_size;
        rect.x = 0;
    }
    else
    {
        rect.x = -ip.x;
        if( rect.x > win_size.width )
            rect.x = win_size.width;
    }

67
    if( ip.x < src_size.width - win_size.width )
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
        rect.width = win_size.width;
    else
    {
        rect.width = src_size.width - ip.x - 1;
        if( rect.width < 0 )
        {
            src += rect.width*pix_size;
            rect.width = 0;
        }
        assert( rect.width <= win_size.width );
    }

    if( ip.y >= 0 )
    {
        src += ip.y * src_step;
        rect.y = 0;
    }
    else
        rect.y = -ip.y;

88
    if( ip.y < src_size.height - win_size.height )
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
        rect.height = win_size.height;
    else
    {
        rect.height = src_size.height - ip.y - 1;
        if( rect.height < 0 )
        {
            src += rect.height*src_step;
            rect.height = 0;
        }
    }

    *pRect = rect;
    return src - rect.x*pix_size;
}


105
enum { SUBPIX_SHIFT=16 };
106

107 108 109 110
struct scale_fixpt
{
    int operator()(float a) const { return cvRound(a*(1 << SUBPIX_SHIFT)); }
};
111

112 113 114 115
struct cast_8u
{
    uchar operator()(int a) const { return (uchar)((a + (1 << (SUBPIX_SHIFT-1))) >> SUBPIX_SHIFT); }
};
116

117 118 119 120 121 122 123 124 125 126
struct cast_flt_8u
{
    uchar operator()(float a) const { return (uchar)cvRound(a); }
};

template<typename _Tp>
struct nop
{
    _Tp operator()(_Tp a) const { return a; }
};
127 128


129
template<typename _Tp, typename _DTp, typename _WTp, class ScaleOp, class CastOp>
Andrey Kamaev's avatar
Andrey Kamaev committed
130 131
void getRectSubPix_Cn_(const _Tp* src, size_t src_step, Size src_size,
                       _DTp* dst, size_t dst_step, Size win_size, Point2f center, int cn )
132
{
133 134 135 136
    ScaleOp scale_op;
    CastOp cast_op;
    Point ip;
    _WTp a11, a12, a21, a22, b1, b2;
137
    float a, b;
138
    int i, j, c;
139 140 141 142 143 144 145 146 147

    center.x -= (win_size.width-1)*0.5f;
    center.y -= (win_size.height-1)*0.5f;

    ip.x = cvFloor( center.x );
    ip.y = cvFloor( center.y );

    a = center.x - ip.x;
    b = center.y - ip.y;
148 149 150 151 152 153
    a11 = scale_op((1.f-a)*(1.f-b));
    a12 = scale_op(a*(1.f-b));
    a21 = scale_op((1.f-a)*b);
    a22 = scale_op(a*b);
    b1 = scale_op(1.f - b);
    b2 = scale_op(b);
154 155 156 157

    src_step /= sizeof(src[0]);
    dst_step /= sizeof(dst[0]);

158
    if( 0 <= ip.x && ip.x < src_size.width - win_size.width &&
159
       0 <= ip.y && ip.y < src_size.height - win_size.height)
160 161
    {
        // extracted rectangle is totally inside the image
162 163
        src += ip.y * src_step + ip.x*cn;
        win_size.width *= cn;
164

165
        for( i = 0; i < win_size.height; i++, src += src_step, dst += dst_step )
166
        {
167 168 169 170 171 172 173 174
            for( j = 0; j <= win_size.width - 2; j += 2 )
            {
                _WTp s0 = src[j]*a11 + src[j+cn]*a12 + src[j+src_step]*a21 + src[j+src_step+cn]*a22;
                _WTp s1 = src[j+1]*a11 + src[j+cn+1]*a12 + src[j+src_step+1]*a21 + src[j+src_step+cn+1]*a22;
                dst[j] = cast_op(s0);
                dst[j+1] = cast_op(s1);
            }

175
            for( ; j < win_size.width; j++ )
176
            {
177 178
                _WTp s0 = src[j]*a11 + src[j+cn]*a12 + src[j+src_step]*a21 + src[j+src_step+cn]*a22;
                dst[j] = cast_op(s0);
179 180 181 182 183
            }
        }
    }
    else
    {
184 185 186
        Rect r;
        src = (const _Tp*)adjustRect( (const uchar*)src, src_step*sizeof(*src),
                                     sizeof(*src)*cn, src_size, win_size, ip, &r);
187 188 189

        for( i = 0; i < win_size.height; i++, dst += dst_step )
        {
190 191
            const _Tp *src2 = src + src_step;
            _WTp s0;
192 193 194 195

            if( i < r.y || i >= r.height )
                src2 -= src_step;

196
            for( c = 0; c < cn; c++ )
197
            {
198 199 200 201 202 203
                s0 = src[r.x*cn + c]*b1 + src2[r.x*cn + c]*b2;
                for( j = 0; j < r.x; j++ )
                    dst[j*cn + c] = cast_op(s0);
                s0 = src[r.width*cn + c]*b1 + src2[r.width*cn + c]*b2;
                for( j = r.width; j < win_size.width; j++ )
                    dst[j*cn + c] = cast_op(s0);
204 205
            }

206
            for( j = r.x*cn; j < r.width*cn; j++ )
207
            {
208
                s0 = src[j]*a11 + src[j+cn]*a12 + src2[j]*a21 + src2[j+cn]*a22;
209
                dst[j] = cast_op(s0);
210 211 212 213 214 215 216 217 218
            }

            if( i < r.height )
                src = src2;
        }
    }
}


219
static void getRectSubPix_8u32f
Andrey Kamaev's avatar
Andrey Kamaev committed
220 221
( const uchar* src, size_t src_step, Size src_size,
 float* dst, size_t dst_step, Size win_size, Point2f center0, int cn )
222
{
223 224
    Point2f center = center0;
    Point ip;
225

226 227
    center.x -= (win_size.width-1)*0.5f;
    center.y -= (win_size.height-1)*0.5f;
228

229 230
    ip.x = cvFloor( center.x );
    ip.y = cvFloor( center.y );
231

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
    if( cn == 1 &&
       0 <= ip.x && ip.x + win_size.width < src_size.width &&
       0 <= ip.y && ip.y + win_size.height < src_size.height &&
       win_size.width > 0 && win_size.height > 0 )
    {
        float a = center.x - ip.x;
        float b = center.y - ip.y;
        a = MAX(a,0.0001f);
        float a12 = a*(1.f-b);
        float a22 = a*b;
        float b1 = 1.f - b;
        float b2 = b;
        double s = (1. - a)/a;

        src_step /= sizeof(src[0]);
        dst_step /= sizeof(dst[0]);
248

249 250
        // extracted rectangle is totally inside the image
        src += ip.y * src_step + ip.x;
251

252 253 254 255 256 257 258 259 260 261
        for( ; win_size.height--; src += src_step, dst += dst_step )
        {
            float prev = (1 - a)*(b1*src[0] + b2*src[src_step]);
            for( int j = 0; j < win_size.width; j++ )
            {
                float t = a12*src[j+1] + a22*src[j+1+src_step];
                dst[j] = prev + t;
                prev = (float)(t*s);
            }
        }
262 263 264
    }
    else
    {
265 266
        getRectSubPix_Cn_<uchar, float, float, nop<float>, nop<float> >
        (src, src_step, src_size, dst, dst_step, win_size, center0, cn );
267 268 269
    }
}

270
static void
Andrey Kamaev's avatar
Andrey Kamaev committed
271 272
getQuadrangleSubPix_8u32f_CnR( const uchar* src, size_t src_step, Size src_size,
                               float* dst, size_t dst_step, Size win_size,
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
                               const double *matrix, int cn )
{
    int x, y, k;
    double A11 = matrix[0], A12 = matrix[1], A13 = matrix[2];
    double A21 = matrix[3], A22 = matrix[4], A23 = matrix[5];

    src_step /= sizeof(src[0]);
    dst_step /= sizeof(dst[0]);

    for( y = 0; y < win_size.height; y++, dst += dst_step )
    {
        double xs = A12*y + A13;
        double ys = A22*y + A23;
        double xe = A11*(win_size.width-1) + A12*y + A13;
        double ye = A21*(win_size.width-1) + A22*y + A23;

        if( (unsigned)(cvFloor(xs)-1) < (unsigned)(src_size.width - 3) &&
            (unsigned)(cvFloor(ys)-1) < (unsigned)(src_size.height - 3) &&
            (unsigned)(cvFloor(xe)-1) < (unsigned)(src_size.width - 3) &&
            (unsigned)(cvFloor(ye)-1) < (unsigned)(src_size.height - 3))
        {
            for( x = 0; x < win_size.width; x++ )
            {
                int ixs = cvFloor( xs );
                int iys = cvFloor( ys );
                const uchar *ptr = src + src_step*iys;
                float a = (float)(xs - ixs), b = (float)(ys - iys), a1 = 1.f - a, b1 = 1.f - b;
                float w00 = a1*b1, w01 = a*b1, w10 = a1*b, w11 = a*b;
                xs += A11;
                ys += A21;

                if( cn == 1 )
                {
                    ptr += ixs;
                    dst[x] = ptr[0]*w00 + ptr[1]*w01 + ptr[src_step]*w10 + ptr[src_step+1]*w11;
                }
                else if( cn == 3 )
                {
                    ptr += ixs*3;
                    float t0 = ptr[0]*w00 + ptr[3]*w01 + ptr[src_step]*w10 + ptr[src_step+3]*w11;
                    float t1 = ptr[1]*w00 + ptr[4]*w01 + ptr[src_step+1]*w10 + ptr[src_step+4]*w11;
                    float t2 = ptr[2]*w00 + ptr[5]*w01 + ptr[src_step+2]*w10 + ptr[src_step+5]*w11;

                    dst[x*3] = t0;
                    dst[x*3+1] = t1;
                    dst[x*3+2] = t2;
                }
                else
                {
                    ptr += ixs*cn;
                    for( k = 0; k < cn; k++ )
                        dst[x*cn+k] = ptr[k]*w00 + ptr[k+cn]*w01 +
                                    ptr[src_step+k]*w10 + ptr[src_step+k+cn]*w11;
                }
            }
        }
        else
        {
            for( x = 0; x < win_size.width; x++ )
            {
                int ixs = cvFloor( xs ), iys = cvFloor( ys );
                float a = (float)(xs - ixs), b = (float)(ys - iys), a1 = 1.f - a, b1 = 1.f - b;
                float w00 = a1*b1, w01 = a*b1, w10 = a1*b, w11 = a*b;
                const uchar *ptr0, *ptr1;
                xs += A11; ys += A21;
338

339 340 341 342
                if( (unsigned)iys < (unsigned)(src_size.height-1) )
                    ptr0 = src + src_step*iys, ptr1 = ptr0 + src_step;
                else
                    ptr0 = ptr1 = src + (iys < 0 ? 0 : src_size.height-1)*src_step;
343

344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
                if( (unsigned)ixs < (unsigned)(src_size.width-1) )
                {
                    ptr0 += ixs*cn; ptr1 += ixs*cn;
                    for( k = 0; k < cn; k++ )
                        dst[x*cn + k] = ptr0[k]*w00 + ptr0[k+cn]*w01 + ptr1[k]*w10 + ptr1[k+cn]*w11;
                }
                else
                {
                    ixs = ixs < 0 ? 0 : src_size.width - 1;
                    ptr0 += ixs*cn; ptr1 += ixs*cn;
                    for( k = 0; k < cn; k++ )
                        dst[x*cn + k] = ptr0[k]*b1 + ptr1[k]*b;
                }
            }
        }
    }
}

362 363
}

364

365 366 367
void cv::getRectSubPix( InputArray _image, Size patchSize, Point2f center,
                       OutputArray _patch, int patchType )
{
368 369
    CV_INSTRUMENT_REGION()

370 371 372
    Mat image = _image.getMat();
    int depth = image.depth(), cn = image.channels();
    int ddepth = patchType < 0 ? depth : CV_MAT_DEPTH(patchType);
373

374
    CV_Assert( cn == 1 || cn == 3 );
375

376 377
    _patch.create(patchSize, CV_MAKETYPE(ddepth, cn));
    Mat patch = _patch.getMat();
378

379
#if defined (HAVE_IPP) && (IPP_VERSION_X100 >= 700)
380
    CV_IPP_CHECK()
Ilya Lavrenov's avatar
Ilya Lavrenov committed
381
    {
382 383 384 385 386 387 388 389 390 391
        typedef IppStatus (CV_STDCALL *ippiGetRectSubPixFunc)( const void* src, int src_step,
                                                                IppiSize src_size, void* dst,
                                                                int dst_step, IppiSize win_size,
                                                                IppiPoint_32f center,
                                                                IppiPoint* minpt, IppiPoint* maxpt );

        IppiPoint minpt={0,0}, maxpt={0,0};
        IppiPoint_32f icenter = {center.x, center.y};
        IppiSize src_size={image.cols, image.rows}, win_size={patch.cols, patch.rows};
        int srctype = image.type();
392
        ippiGetRectSubPixFunc ippiCopySubpixIntersect =
393 394 395 396
            srctype == CV_8UC1 && ddepth == CV_8U ? (ippiGetRectSubPixFunc)ippiCopySubpixIntersect_8u_C1R :
            srctype == CV_8UC1 && ddepth == CV_32F ? (ippiGetRectSubPixFunc)ippiCopySubpixIntersect_8u32f_C1R :
            srctype == CV_32FC1 && ddepth == CV_32F ? (ippiGetRectSubPixFunc)ippiCopySubpixIntersect_32f_C1R : 0;

397
        if( ippiCopySubpixIntersect)
398
        {
399 400
            if (CV_INSTRUMENT_FUN_IPP(ippiCopySubpixIntersect, image.ptr(), (int)image.step, src_size, patch.ptr(),
                        (int)patch.step, win_size, icenter, &minpt, &maxpt) >= 0)
401 402 403 404 405 406
            {
                CV_IMPL_ADD(CV_IMPL_IPP);
                return;
            }
            setIppErrorStatus();
        }
Ilya Lavrenov's avatar
Ilya Lavrenov committed
407
    }
408
#endif
409

410 411
    if( depth == CV_8U && ddepth == CV_8U )
        getRectSubPix_Cn_<uchar, uchar, int, scale_fixpt, cast_8u>
412
        (image.ptr(), image.step, image.size(), patch.ptr(), patch.step, patch.size(), center, cn);
413 414
    else if( depth == CV_8U && ddepth == CV_32F )
        getRectSubPix_8u32f
415
        (image.ptr(), image.step, image.size(), patch.ptr<float>(), patch.step, patch.size(), center, cn);
416 417
    else if( depth == CV_32F && ddepth == CV_32F )
        getRectSubPix_Cn_<float, float, float, nop<float>, nop<float> >
418
        (image.ptr<float>(), image.step, image.size(), patch.ptr<float>(), patch.step, patch.size(), center, cn);
419 420
    else
        CV_Error( CV_StsUnsupportedFormat, "Unsupported combination of input and output formats");
421 422 423
}


424 425 426
CV_IMPL void
cvGetRectSubPix( const void* srcarr, void* dstarr, CvPoint2D32f center )
{
427 428
    cv::Mat src = cv::cvarrToMat(srcarr);
    const cv::Mat dst = cv::cvarrToMat(dstarr);
429
    CV_Assert( src.channels() == dst.channels() );
430

431 432
    cv::getRectSubPix(src, dst.size(), center, dst, dst.type());
}
433 434 435 436 437


CV_IMPL void
cvGetQuadrangleSubPix( const void* srcarr, void* dstarr, const CvMat* mat )
{
438 439
    const cv::Mat src = cv::cvarrToMat(srcarr), m = cv::cvarrToMat(mat);
    cv::Mat dst = cv::cvarrToMat(dstarr);
440 441 442

    CV_Assert( src.channels() == dst.channels() );

443 444 445 446 447 448 449 450 451
    cv::Size win_size = dst.size();
    double matrix[6];
    cv::Mat M(2, 3, CV_64F, matrix);
    m.convertTo(M, CV_64F);
    double dx = (win_size.width - 1)*0.5;
    double dy = (win_size.height - 1)*0.5;
    matrix[2] -= matrix[0]*dx + matrix[1]*dy;
    matrix[5] -= matrix[3]*dx + matrix[4]*dy;

452
    if( src.depth() == CV_8U && dst.depth() == CV_32F )
453 454
        cv::getQuadrangleSubPix_8u32f_CnR( src.ptr(), src.step, src.size(),
                                           dst.ptr<float>(), dst.step, dst.size(),
455 456 457 458 459 460 461 462
                                           matrix, src.channels());
    else
    {
        CV_Assert( src.depth() == dst.depth() );
        cv::warpAffine(src, dst, M, dst.size(),
                       cv::INTER_LINEAR + cv::WARP_INVERSE_MAP,
                       cv::BORDER_REPLICATE);
    }
463
}
464 465


466 467 468 469 470 471 472 473
CV_IMPL int
cvSampleLine( const void* _img, CvPoint pt1, CvPoint pt2,
              void* _buffer, int connectivity )
{
    cv::Mat img = cv::cvarrToMat(_img);
    cv::LineIterator li(img, pt1, pt2, connectivity, false);
    uchar* buffer = (uchar*)_buffer;
    size_t pixsize = img.elemSize();
474

475 476
    if( !buffer )
        CV_Error( CV_StsNullPtr, "" );
477

478
    for( int i = 0; i < li.count; i++, ++li )
479
    {
480 481
        for( size_t k = 0; k < pixsize; k++ )
            *buffer++ = li.ptr[k];
482 483
    }

484
    return li.count;
485 486 487 488
}


/* End of file. */