matrix.cpp 24.6 KB
Newer Older
1 2 3
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
4 5

#include "precomp.hpp"
A
Alexander Alekhin 已提交
6 7
#include "bufferpool.impl.hpp"

8 9
namespace cv {

10 11 12
void MatAllocator::map(UMatData*, int) const
{
}
13

14 15 16
void MatAllocator::unmap(UMatData* u) const
{
    if(u->urefcount == 0 && u->refcount == 0)
A
Alexander Alekhin 已提交
17
    {
18
        deallocate(u);
A
Alexander Alekhin 已提交
19
    }
20
}
21

22 23 24 25 26 27 28 29 30 31
void MatAllocator::download(UMatData* u, void* dstptr,
         int dims, const size_t sz[],
         const size_t srcofs[], const size_t srcstep[],
         const size_t dststep[]) const
{
    if(!u)
        return;
    int isz[CV_MAX_DIM];
    uchar* srcptr = u->data;
    for( int i = 0; i < dims; i++ )
32
    {
33 34
        CV_Assert( sz[i] <= (size_t)INT_MAX );
        if( sz[i] == 0 )
35
            return;
36
        if( srcofs )
37
            srcptr += srcofs[i]*(i <= dims-2 ? srcstep[i] : 1);
38
        isz[i] = (int)sz[i];
39 40
    }

41 42
    Mat src(dims, isz, CV_8U, srcptr, srcstep);
    Mat dst(dims, isz, CV_8U, dstptr, dststep);
43

44 45 46
    const Mat* arrays[] = { &src, &dst };
    uchar* ptrs[2];
    NAryMatIterator it(arrays, ptrs, 2);
47
    size_t planesz = it.size;
48

49
    for( size_t j = 0; j < it.nplanes; j++, ++it )
50 51 52 53 54 55 56 57 58 59 60 61 62
        memcpy(ptrs[1], ptrs[0], planesz);
}


void MatAllocator::upload(UMatData* u, const void* srcptr, int dims, const size_t sz[],
                    const size_t dstofs[], const size_t dststep[],
                    const size_t srcstep[]) const
{
    if(!u)
        return;
    int isz[CV_MAX_DIM];
    uchar* dstptr = u->data;
    for( int i = 0; i < dims; i++ )
63
    {
64 65
        CV_Assert( sz[i] <= (size_t)INT_MAX );
        if( sz[i] == 0 )
66
            return;
67
        if( dstofs )
68
            dstptr += dstofs[i]*(i <= dims-2 ? dststep[i] : 1);
69
        isz[i] = (int)sz[i];
70 71
    }

72 73 74 75 76 77
    Mat src(dims, isz, CV_8U, (void*)srcptr, srcstep);
    Mat dst(dims, isz, CV_8U, dstptr, dststep);

    const Mat* arrays[] = { &src, &dst };
    uchar* ptrs[2];
    NAryMatIterator it(arrays, ptrs, 2);
78
    size_t planesz = it.size;
79

80
    for( size_t j = 0; j < it.nplanes; j++, ++it )
81 82 83 84
        memcpy(ptrs[1], ptrs[0], planesz);
}

void MatAllocator::copy(UMatData* usrc, UMatData* udst, int dims, const size_t sz[],
85
                  const size_t srcofs[], const size_t srcstep[],
86
                  const size_t dstofs[], const size_t dststep[], bool /*sync*/) const
87
{
88 89
    CV_INSTRUMENT_REGION()

90 91 92 93 94 95
    if(!usrc || !udst)
        return;
    int isz[CV_MAX_DIM];
    uchar* srcptr = usrc->data;
    uchar* dstptr = udst->data;
    for( int i = 0; i < dims; i++ )
96
    {
97 98
        CV_Assert( sz[i] <= (size_t)INT_MAX );
        if( sz[i] == 0 )
I
Ilya Lavrenov 已提交
99
            return;
100
        if( srcofs )
I
Ilya Lavrenov 已提交
101
            srcptr += srcofs[i]*(i <= dims-2 ? srcstep[i] : 1);
102
        if( dstofs )
I
Ilya Lavrenov 已提交
103
            dstptr += dstofs[i]*(i <= dims-2 ? dststep[i] : 1);
104 105
        isz[i] = (int)sz[i];
    }
106

107 108
    Mat src(dims, isz, CV_8U, srcptr, srcstep);
    Mat dst(dims, isz, CV_8U, dstptr, dststep);
109

110 111 112
    const Mat* arrays[] = { &src, &dst };
    uchar* ptrs[2];
    NAryMatIterator it(arrays, ptrs, 2);
113
    size_t planesz = it.size;
114

115
    for( size_t j = 0; j < it.nplanes; j++, ++it )
116 117
        memcpy(ptrs[1], ptrs[0], planesz);
}
118

A
Alexander Alekhin 已提交
119
BufferPoolController* MatAllocator::getBufferPoolController(const char* id) const
A
Alexander Alekhin 已提交
120
{
A
Alexander Alekhin 已提交
121
    (void)id;
A
Alexander Alekhin 已提交
122 123 124 125
    static DummyBufferPoolController dummy;
    return &dummy;
}

126
class StdMatAllocator CV_FINAL : public MatAllocator
127 128 129
{
public:
    UMatData* allocate(int dims, const int* sizes, int type,
130
                       void* data0, size_t* step, int /*flags*/, UMatUsageFlags /*usageFlags*/) const CV_OVERRIDE
131
    {
132 133
        size_t total = CV_ELEM_SIZE(type);
        for( int i = dims-1; i >= 0; i-- )
134
        {
135 136 137 138 139 140 141 142 143 144 145
            if( step )
            {
                if( data0 && step[i] != CV_AUTOSTEP )
                {
                    CV_Assert(total <= step[i]);
                    total = step[i];
                }
                else
                    step[i] = total;
            }
            total *= sizes[i];
146
        }
147 148 149 150 151 152
        uchar* data = data0 ? (uchar*)data0 : (uchar*)fastMalloc(total);
        UMatData* u = new UMatData(this);
        u->data = u->origdata = data;
        u->size = total;
        if(data0)
            u->flags |= UMatData::USER_ALLOCATED;
153

154 155
        return u;
    }
156

157
    bool allocate(UMatData* u, int /*accessFlags*/, UMatUsageFlags /*usageFlags*/) const CV_OVERRIDE
158 159 160
    {
        if(!u) return false;
        return true;
161 162
    }

163
    void deallocate(UMatData* u) const CV_OVERRIDE
164
    {
165 166 167
        if(!u)
            return;

168 169 170
        CV_Assert(u->urefcount == 0);
        CV_Assert(u->refcount == 0);
        if( !(u->flags & UMatData::USER_ALLOCATED) )
171
        {
172 173
            fastFree(u->origdata);
            u->origdata = 0;
174
        }
175
        delete u;
176 177
    }
};
178

179 180
namespace
{
M
Matthias Grundmann 已提交
181
    MatAllocator* volatile g_matAllocator = NULL;
182
}
183

184 185
MatAllocator* Mat::getDefaultAllocator()
{
D
Dan 已提交
186 187
    if (g_matAllocator == NULL)
    {
M
Matthias Grundmann 已提交
188 189 190 191 192
        cv::AutoLock lock(cv::getInitializationMutex());
        if (g_matAllocator == NULL)
        {
            g_matAllocator = getStdAllocator();
        }
D
Dan 已提交
193 194
    }
    return g_matAllocator;
195 196 197
}
void Mat::setDefaultAllocator(MatAllocator* allocator)
{
D
Dan 已提交
198
    g_matAllocator = allocator;
199
}
200 201
MatAllocator* Mat::getStdAllocator()
{
D
Dan 已提交
202
    CV_SINGLETON_LAZY_INIT(MatAllocator, new StdMatAllocator())
203 204
}

205
//==================================================================================================
V
Vadim Pisarevsky 已提交
206

207
void setSize( Mat& m, int _dims, const int* _sz, const size_t* _steps, bool autoSteps)
V
Vadim Pisarevsky 已提交
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
{
    CV_Assert( 0 <= _dims && _dims <= CV_MAX_DIM );
    if( m.dims != _dims )
    {
        if( m.step.p != m.step.buf )
        {
            fastFree(m.step.p);
            m.step.p = m.step.buf;
            m.size.p = &m.rows;
        }
        if( _dims > 2 )
        {
            m.step.p = (size_t*)fastMalloc(_dims*sizeof(m.step.p[0]) + (_dims+1)*sizeof(m.size.p[0]));
            m.size.p = (int*)(m.step.p + _dims) + 1;
            m.size.p[-1] = _dims;
223
            m.rows = m.cols = -1;
V
Vadim Pisarevsky 已提交
224 225
        }
    }
226

V
Vadim Pisarevsky 已提交
227 228 229
    m.dims = _dims;
    if( !_sz )
        return;
230

I
Ilya Lavrenov 已提交
231
    size_t esz = CV_ELEM_SIZE(m.flags), esz1 = CV_ELEM_SIZE1(m.flags), total = esz;
232
    for( int i = _dims-1; i >= 0; i-- )
V
Vadim Pisarevsky 已提交
233 234
    {
        int s = _sz[i];
235
        CV_Assert( s >= 0 );
V
Vadim Pisarevsky 已提交
236
        m.size.p[i] = s;
237

V
Vadim Pisarevsky 已提交
238
        if( _steps )
I
Ilya Lavrenov 已提交
239 240 241 242 243 244
        {
            if (_steps[i] % esz1 != 0)
            {
                CV_Error(Error::BadStep, "Step must be a multiple of esz1");
            }

V
Vadim Pisarevsky 已提交
245
            m.step.p[i] = i < _dims-1 ? _steps[i] : esz;
I
Ilya Lavrenov 已提交
246
        }
V
Vadim Pisarevsky 已提交
247 248 249 250 251 252 253 254 255
        else if( autoSteps )
        {
            m.step.p[i] = total;
            int64 total1 = (int64)total*s;
            if( (uint64)total1 != (size_t)total1 )
                CV_Error( CV_StsOutOfRange, "The total matrix size does not fit to \"size_t\" type" );
            total = (size_t)total1;
        }
    }
256

V
Vadim Pisarevsky 已提交
257 258 259 260 261 262 263
    if( _dims == 1 )
    {
        m.dims = 2;
        m.cols = 1;
        m.step[1] = esz;
    }
}
264

265
int updateContinuityFlag(int flags, int dims, const int* size, const size_t* step)
V
Vadim Pisarevsky 已提交
266 267
{
    int i, j;
268
    for( i = 0; i < dims; i++ )
V
Vadim Pisarevsky 已提交
269
    {
270
        if( size[i] > 1 )
V
Vadim Pisarevsky 已提交
271 272
            break;
    }
273

274 275
    uint64 t = (uint64)size[std::min(i, dims-1)]*CV_MAT_CN(flags);
    for( j = dims-1; j > i; j-- )
V
Vadim Pisarevsky 已提交
276
    {
277 278
        t *= size[j];
        if( step[j]*size[j] < step[j-1] )
V
Vadim Pisarevsky 已提交
279 280
            break;
    }
281

282 283 284 285 286 287 288 289
    if( j <= i && t == (uint64)(int)t )
        return flags | Mat::CONTINUOUS_FLAG;
    return flags & ~Mat::CONTINUOUS_FLAG;
}

void Mat::updateContinuityFlag()
{
    flags = cv::updateContinuityFlag(flags, dims, size.p, step.p);
290
}
291

292
void finalizeHdr(Mat& m)
293
{
294
    m.updateContinuityFlag();
295 296
    int d = m.dims;
    if( d > 2 )
V
Vadim Pisarevsky 已提交
297
        m.rows = m.cols = -1;
298
    if(m.u)
299
        m.datastart = m.data = m.u->data;
V
Vadim Pisarevsky 已提交
300 301
    if( m.data )
    {
302 303 304
        m.datalimit = m.datastart + m.size[0]*m.step[0];
        if( m.size[0] > 0 )
        {
305
            m.dataend = m.ptr() + m.size[d-1]*m.step[d-1];
306
            for( int i = 0; i < d-1; i++ )
307 308 309 310
                m.dataend += (m.size[i] - 1)*m.step[i];
        }
        else
            m.dataend = m.datalimit;
V
Vadim Pisarevsky 已提交
311
    }
312 313
    else
        m.dataend = m.datalimit = 0;
V
Vadim Pisarevsky 已提交
314
}
315

316
//==================================================================================================
317

V
Vadim Pisarevsky 已提交
318 319 320
void Mat::create(int d, const int* _sizes, int _type)
{
    int i;
V
Vladislav Vinogradov 已提交
321
    CV_Assert(0 <= d && d <= CV_MAX_DIM && _sizes);
V
Vadim Pisarevsky 已提交
322
    _type = CV_MAT_TYPE(_type);
323

V
Vadim Pisarevsky 已提交
324 325 326 327 328 329 330 331 332 333
    if( data && (d == dims || (d == 1 && dims <= 2)) && _type == type() )
    {
        if( d == 2 && rows == _sizes[0] && cols == _sizes[1] )
            return;
        for( i = 0; i < d; i++ )
            if( size[i] != _sizes[i] )
                break;
        if( i == d && (d > 1 || size[1] == 1))
            return;
    }
334

335 336 337 338 339 340 341 342
    int _sizes_backup[CV_MAX_DIM]; // #5991
    if (_sizes == (this->size.p))
    {
        for(i = 0; i < d; i++ )
            _sizes_backup[i] = _sizes[i];
        _sizes = _sizes_backup;
    }

V
Vadim Pisarevsky 已提交
343 344 345 346
    release();
    if( d == 0 )
        return;
    flags = (_type & CV_MAT_TYPE_MASK) | MAGIC_VAL;
347
    setSize(*this, d, _sizes, 0, true);
348

349
    if( total() > 0 )
V
Vadim Pisarevsky 已提交
350
    {
351
        MatAllocator *a = allocator, *a0 = getDefaultAllocator();
A
Andrey Pavlenko 已提交
352
#ifdef HAVE_TGPU
353 354
        if( !a || a == tegra::getAllocator() )
            a = tegra::getAllocator(d, _sizes, _type);
A
Andrey Pavlenko 已提交
355
#endif
356 357
        if(!a)
            a = a0;
M
Maksim Shabunin 已提交
358
        CV_TRY
359
        {
360
            u = a->allocate(dims, size, _type, 0, step.p, 0, USAGE_DEFAULT);
361
            CV_Assert(u != 0);
362
        }
M
Maksim Shabunin 已提交
363
        CV_CATCH_ALL
364
        {
365
            if(a != a0)
366
                u = a0->allocate(dims, size, _type, 0, step.p, 0, USAGE_DEFAULT);
367
            CV_Assert(u != 0);
368
        }
369
        CV_Assert( step[dims-1] == (size_t)CV_ELEM_SIZE(flags) );
V
Vadim Pisarevsky 已提交
370
    }
371

A
Alexander Alekhin 已提交
372
    addref();
V
Vadim Pisarevsky 已提交
373 374 375
    finalizeHdr(*this);
}

376 377 378 379 380
void Mat::create(const std::vector<int>& _sizes, int _type)
{
    create((int)_sizes.size(), _sizes.data(), _type);
}

V
Vadim Pisarevsky 已提交
381 382 383 384 385 386 387 388 389
void Mat::copySize(const Mat& m)
{
    setSize(*this, m.dims, 0, 0);
    for( int i = 0; i < dims; i++ )
    {
        size[i] = m.size[i];
        step[i] = m.step[i];
    }
}
390

V
Vadim Pisarevsky 已提交
391 392
void Mat::deallocate()
{
393
    if(u)
394 395 396 397 398
    {
        UMatData* u_ = u;
        u = NULL;
        (u_->currAllocator ? u_->currAllocator : allocator ? allocator : getDefaultAllocator())->unmap(u_);
    }
V
Vadim Pisarevsky 已提交
399 400
}

A
Andrey Kamaev 已提交
401
Mat::Mat(const Mat& m, const Range& _rowRange, const Range& _colRange)
402 403
    : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
      datalimit(0), allocator(0), u(0), size(&rows)
V
Vadim Pisarevsky 已提交
404 405 406 407 408
{
    CV_Assert( m.dims >= 2 );
    if( m.dims > 2 )
    {
        AutoBuffer<Range> rs(m.dims);
A
Andrey Kamaev 已提交
409 410
        rs[0] = _rowRange;
        rs[1] = _colRange;
V
Vadim Pisarevsky 已提交
411 412
        for( int i = 2; i < m.dims; i++ )
            rs[i] = Range::all();
413
        *this = m(rs.data());
V
Vadim Pisarevsky 已提交
414 415
        return;
    }
416

V
Vadim Pisarevsky 已提交
417
    *this = m;
M
Maksim Shabunin 已提交
418
    CV_TRY
V
Vadim Pisarevsky 已提交
419
    {
420 421 422 423 424 425 426 427
        if( _rowRange != Range::all() && _rowRange != Range(0,rows) )
        {
            CV_Assert( 0 <= _rowRange.start && _rowRange.start <= _rowRange.end
                       && _rowRange.end <= m.rows );
            rows = _rowRange.size();
            data += step*_rowRange.start;
            flags |= SUBMATRIX_FLAG;
        }
428

429 430 431 432 433 434 435 436 437
        if( _colRange != Range::all() && _colRange != Range(0,cols) )
        {
            CV_Assert( 0 <= _colRange.start && _colRange.start <= _colRange.end
                       && _colRange.end <= m.cols );
            cols = _colRange.size();
            data += _colRange.start*elemSize();
            flags |= SUBMATRIX_FLAG;
        }
    }
M
Maksim Shabunin 已提交
438
    CV_CATCH_ALL
V
Vadim Pisarevsky 已提交
439
    {
440
        release();
M
Maksim Shabunin 已提交
441
        CV_RETHROW();
V
Vadim Pisarevsky 已提交
442
    }
443

444
    updateContinuityFlag();
445

V
Vadim Pisarevsky 已提交
446 447 448 449 450 451
    if( rows <= 0 || cols <= 0 )
    {
        release();
        rows = cols = 0;
    }
}
452 453


V
Vadim Pisarevsky 已提交
454 455
Mat::Mat(const Mat& m, const Rect& roi)
    : flags(m.flags), dims(2), rows(roi.height), cols(roi.width),
456
    data(m.data + roi.y*m.step[0]),
457
    datastart(m.datastart), dataend(m.dataend), datalimit(m.datalimit),
458
    allocator(m.allocator), u(m.u), size(&rows)
V
Vadim Pisarevsky 已提交
459 460
{
    CV_Assert( m.dims <= 2 );
461

462
    size_t esz = CV_ELEM_SIZE(flags);
V
Vadim Pisarevsky 已提交
463 464 465
    data += roi.x*esz;
    CV_Assert( 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols &&
              0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows );
466 467
    if( u )
        CV_XADD(&u->refcount, 1);
468 469
    if( roi.width < m.cols || roi.height < m.rows )
        flags |= SUBMATRIX_FLAG;
470

V
Vadim Pisarevsky 已提交
471
    step[0] = m.step[0]; step[1] = esz;
472
    updateContinuityFlag();
473

V
Vadim Pisarevsky 已提交
474 475 476 477 478 479 480
    if( rows <= 0 || cols <= 0 )
    {
        release();
        rows = cols = 0;
    }
}

481

A
Andrey Kamaev 已提交
482
Mat::Mat(int _dims, const int* _sizes, int _type, void* _data, const size_t* _steps)
483 484
    : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
      datalimit(0), allocator(0), u(0), size(&rows)
V
Vadim Pisarevsky 已提交
485
{
486
    flags |= CV_MAT_TYPE(_type);
487
    datastart = data = (uchar*)_data;
V
Vadim Pisarevsky 已提交
488 489 490
    setSize(*this, _dims, _sizes, _steps, true);
    finalizeHdr(*this);
}
491 492


493 494 495 496 497 498 499 500 501 502 503
Mat::Mat(const std::vector<int>& _sizes, int _type, void* _data, const size_t* _steps)
    : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
      datalimit(0), allocator(0), u(0), size(&rows)
{
    flags |= CV_MAT_TYPE(_type);
    datastart = data = (uchar*)_data;
    setSize(*this, (int)_sizes.size(), _sizes.data(), _steps, true);
    finalizeHdr(*this);
}


A
Andrey Kamaev 已提交
504
Mat::Mat(const Mat& m, const Range* ranges)
505 506
    : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
      datalimit(0), allocator(0), u(0), size(&rows)
V
Vadim Pisarevsky 已提交
507
{
508
    int d = m.dims;
509

V
Vadim Pisarevsky 已提交
510
    CV_Assert(ranges);
511
    for( int i = 0; i < d; i++ )
V
Vadim Pisarevsky 已提交
512 513 514 515 516
    {
        Range r = ranges[i];
        CV_Assert( r == Range::all() || (0 <= r.start && r.start < r.end && r.end <= m.size[i]) );
    }
    *this = m;
517
    for( int i = 0; i < d; i++ )
V
Vadim Pisarevsky 已提交
518 519
    {
        Range r = ranges[i];
520
        if( r != Range::all() && r != Range(0, size.p[i]))
V
Vadim Pisarevsky 已提交
521
        {
522 523 524
            size.p[i] = r.end - r.start;
            data += r.start*step.p[i];
            flags |= SUBMATRIX_FLAG;
V
Vadim Pisarevsky 已提交
525 526
        }
    }
527
    updateContinuityFlag();
V
Vadim Pisarevsky 已提交
528
}
529

530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
Mat::Mat(const Mat& m, const std::vector<Range>& ranges)
    : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
    datalimit(0), allocator(0), u(0), size(&rows)
{
    int d = m.dims;

    CV_Assert((int)ranges.size() == d);
    for (int i = 0; i < d; i++)
    {
        Range r = ranges[i];
        CV_Assert(r == Range::all() || (0 <= r.start && r.start < r.end && r.end <= m.size[i]));
    }
    *this = m;
    for (int i = 0; i < d; i++)
    {
        Range r = ranges[i];
        if (r != Range::all() && r != Range(0, size.p[i]))
        {
            size.p[i] = r.end - r.start;
            data += r.start*step.p[i];
            flags |= SUBMATRIX_FLAG;
        }
    }
553
    updateContinuityFlag();
554
}
555 556


A
Andrey Kamaev 已提交
557
Mat Mat::diag(int d) const
558
{
V
Vadim Pisarevsky 已提交
559
    CV_Assert( dims <= 2 );
A
Andrey Kamaev 已提交
560 561 562
    Mat m = *this;
    size_t esz = elemSize();
    int len;
563

A
Andrey Kamaev 已提交
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
    if( d >= 0 )
    {
        len = std::min(cols - d, rows);
        m.data += esz*d;
    }
    else
    {
        len = std::min(rows + d, cols);
        m.data -= step[0]*d;
    }
    CV_DbgAssert( len > 0 );

    m.size[0] = m.rows = len;
    m.size[1] = m.cols = 1;
    m.step[0] += (len > 1 ? esz : 0);

580
    m.updateContinuityFlag();
A
Andrey Kamaev 已提交
581 582 583 584 585 586

    if( size() != Size(1,1) )
        m.flags |= SUBMATRIX_FLAG;

    return m;
}
587

588

589 590 591
void Mat::pop_back(size_t nelems)
{
    CV_Assert( nelems <= (size_t)size.p[0] );
592

593 594 595 596 597 598 599 600
    if( isSubmatrix() )
        *this = rowRange(0, size.p[0] - (int)nelems);
    else
    {
        size.p[0] -= (int)nelems;
        dataend -= nelems*step.p[0];
    }
}
601 602


603 604
void Mat::push_back_(const void* elem)
{
605
    size_t r = size.p[0];
606 607
    if( isSubmatrix() || dataend + step.p[0] > datalimit )
        reserve( std::max(r + 1, (r*3+1)/2) );
608

609 610
    size_t esz = elemSize();
    memcpy(data + r*step.p[0], elem, esz);
611
    size.p[0] = int(r + 1);
612
    dataend += step.p[0];
613 614 615 616
    uint64 tsz = size.p[0];
    for( int i = 1; i < dims; i++ )
        tsz *= size.p[i];
    if( esz < step.p[0] || tsz != (uint64)(int)tsz )
617 618 619
        flags &= ~CONTINUOUS_FLAG;
}

620

621 622 623
void Mat::reserve(size_t nelems)
{
    const size_t MIN_SIZE = 64;
624

625 626 627
    CV_Assert( (int)nelems >= 0 );
    if( !isSubmatrix() && data + step.p[0]*nelems <= datalimit )
        return;
628

629
    int r = size.p[0];
630

631 632
    if( (size_t)r >= nelems )
        return;
633

634 635
    size.p[0] = std::max((int)nelems, 1);
    size_t newsize = total()*elemSize();
636

637 638
    if( newsize < MIN_SIZE )
        size.p[0] = (int)((MIN_SIZE + newsize - 1)*nelems/newsize);
639

640 641 642 643 644 645 646
    Mat m(dims, size.p, type());
    size.p[0] = r;
    if( r > 0 )
    {
        Mat mpart = m.rowRange(0, r);
        copyTo(mpart);
    }
647

648 649 650 651 652
    *this = m;
    size.p[0] = r;
    dataend = data + step.p[0]*r;
}

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
void Mat::reserveBuffer(size_t nbytes)
{
    size_t esz = 1;
    int mtype = CV_8UC1;
    if (!empty())
    {
        if (!isSubmatrix() && data + nbytes <= dataend)//Should it be datalimit?
            return;
        esz = elemSize();
        mtype = type();
    }

    size_t nelems = (nbytes - 1) / esz + 1;

#if SIZE_MAX > UINT_MAX
    CV_Assert(nelems <= size_t(INT_MAX)*size_t(INT_MAX));
    int newrows = nelems > size_t(INT_MAX) ? nelems > 0x400*size_t(INT_MAX) ? nelems > 0x100000 * size_t(INT_MAX) ? nelems > 0x40000000 * size_t(INT_MAX) ?
                  size_t(INT_MAX) : 0x40000000 : 0x100000 : 0x400 : 1;
#else
    int newrows = nelems > size_t(INT_MAX) ? 2 : 1;
#endif
    int newcols = (int)((nelems - 1) / newrows + 1);

    create(newrows, newcols, mtype);
}

680

681 682 683
void Mat::resize(size_t nelems)
{
    int saveRows = size.p[0];
684 685
    if( saveRows == (int)nelems )
        return;
686
    CV_Assert( (int)nelems >= 0 );
687

688 689
    if( isSubmatrix() || data + step.p[0]*nelems > datalimit )
        reserve(nelems);
690

691 692
    size.p[0] = (int)nelems;
    dataend += (size.p[0] - saveRows)*step.p[0];
693

694
    //updateContinuityFlag(*this);
695 696
}

697 698 699 700 701

void Mat::resize(size_t nelems, const Scalar& s)
{
    int saveRows = size.p[0];
    resize(nelems);
702

703 704 705 706 707
    if( size.p[0] > saveRows )
    {
        Mat part = rowRange(saveRows, size.p[0]);
        part = s;
    }
708 709
}

710 711
void Mat::push_back(const Mat& elems)
{
712 713
    size_t r = size.p[0];
    size_t delta = elems.size.p[0];
714 715
    if( delta == 0 )
        return;
716 717 718 719 720
    if( this == &elems )
    {
        Mat tmp = elems;
        push_back(tmp);
        return;
721
    }
722 723 724 725 726
    if( !data )
    {
        *this = elems.clone();
        return;
    }
727 728 729

    size.p[0] = elems.size.p[0];
    bool eq = size == elems.size;
730
    size.p[0] = int(r);
731
    if( !eq )
I
Ilya Lavrenov 已提交
732
        CV_Error(CV_StsUnmatchedSizes, "Pushed vector length is not equal to matrix row length");
733
    if( type() != elems.type() )
I
Ilya Lavrenov 已提交
734
        CV_Error(CV_StsUnmatchedFormats, "Pushed vector type is not the same as matrix type");
735

736 737
    if( isSubmatrix() || dataend + step.p[0]*delta > datalimit )
        reserve( std::max(r + delta, (r*3+1)/2) );
738

739
    size.p[0] += int(delta);
740
    dataend += step.p[0]*delta;
741

742
    //updateContinuityFlag(*this);
743

744 745 746 747
    if( isContinuous() && elems.isContinuous() )
        memcpy(data + r*step.p[0], elems.data, elems.total()*elems.elemSize());
    else
    {
748
        Mat part = rowRange(int(r), int(r + delta));
749 750 751 752
        elems.copyTo(part);
    }
}

753

V
Vadim Pisarevsky 已提交
754 755 756 757 758
void Mat::locateROI( Size& wholeSize, Point& ofs ) const
{
    CV_Assert( dims <= 2 && step[0] > 0 );
    size_t esz = elemSize(), minstep;
    ptrdiff_t delta1 = data - datastart, delta2 = dataend - datastart;
759

V
Vadim Pisarevsky 已提交
760 761
    if( delta1 == 0 )
        ofs.x = ofs.y = 0;
762 763
    else
    {
V
Vadim Pisarevsky 已提交
764 765 766
        ofs.y = (int)(delta1/step[0]);
        ofs.x = (int)((delta1 - step[0]*ofs.y)/esz);
        CV_DbgAssert( data == datastart + ofs.y*step[0] + ofs.x*esz );
767
    }
V
Vadim Pisarevsky 已提交
768 769 770 771 772
    minstep = (ofs.x + cols)*esz;
    wholeSize.height = (int)((delta2 - minstep)/step[0] + 1);
    wholeSize.height = std::max(wholeSize.height, ofs.y + rows);
    wholeSize.width = (int)((delta2 - step*(wholeSize.height-1))/esz);
    wholeSize.width = std::max(wholeSize.width, ofs.x + cols);
773 774
}

V
Vadim Pisarevsky 已提交
775 776 777 778 779 780
Mat& Mat::adjustROI( int dtop, int dbottom, int dleft, int dright )
{
    CV_Assert( dims <= 2 && step[0] > 0 );
    Size wholeSize; Point ofs;
    size_t esz = elemSize();
    locateROI( wholeSize, ofs );
781 782 783 784 785 786 787
    int row1 = std::min(std::max(ofs.y - dtop, 0), wholeSize.height), row2 = std::max(0, std::min(ofs.y + rows + dbottom, wholeSize.height));
    int col1 = std::min(std::max(ofs.x - dleft, 0), wholeSize.width), col2 = std::max(0, std::min(ofs.x + cols + dright, wholeSize.width));
    if(row1 > row2)
        std::swap(row1, row2);
    if(col1 > col2)
        std::swap(col1, col2);

V
Vadim Pisarevsky 已提交
788 789 790
    data += (row1 - ofs.y)*step + (col1 - ofs.x)*esz;
    rows = row2 - row1; cols = col2 - col1;
    size.p[0] = rows; size.p[1] = cols;
791
    updateContinuityFlag();
V
Vadim Pisarevsky 已提交
792
    return *this;
793
}
794

795 796 797
Mat Mat::reshape(int new_cn, int new_rows) const
{
    int cn = channels();
798
    Mat hdr = *this;
799

800
    if( dims > 2 )
801
    {
802 803 804 805 806 807 808 809 810 811 812 813
        if( new_rows == 0 && new_cn != 0 && size[dims-1]*cn % new_cn == 0 )
        {
            hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((new_cn-1) << CV_CN_SHIFT);
            hdr.step[dims-1] = CV_ELEM_SIZE(hdr.flags);
            hdr.size[dims-1] = hdr.size[dims-1]*cn / new_cn;
            return hdr;
        }
        if( new_rows > 0 )
        {
            int sz[] = { new_rows, (int)(total()/new_rows) };
            return reshape(new_cn, 2, sz);
        }
814
    }
815

816
    CV_Assert( dims <= 2 );
817

818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842
    if( new_cn == 0 )
        new_cn = cn;

    int total_width = cols * cn;

    if( (new_cn > total_width || total_width % new_cn != 0) && new_rows == 0 )
        new_rows = rows * total_width / new_cn;

    if( new_rows != 0 && new_rows != rows )
    {
        int total_size = total_width * rows;
        if( !isContinuous() )
            CV_Error( CV_BadStep,
            "The matrix is not continuous, thus its number of rows can not be changed" );

        if( (unsigned)new_rows > (unsigned)total_size )
            CV_Error( CV_StsOutOfRange, "Bad new number of rows" );

        total_width = total_size / new_rows;

        if( total_width * new_rows != total_size )
            CV_Error( CV_StsBadArg, "The total number of matrix elements "
                                    "is not divisible by the new number of rows" );

        hdr.rows = new_rows;
V
Vadim Pisarevsky 已提交
843
        hdr.step[0] = total_width * elemSize1();
844 845 846 847 848 849 850 851 852 853
    }

    int new_width = total_width / new_cn;

    if( new_width * new_cn != total_width )
        CV_Error( CV_BadNumChannels,
        "The total width is not divisible by the new number of channels" );

    hdr.cols = new_width;
    hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((new_cn-1) << CV_CN_SHIFT);
854
    hdr.step[1] = CV_ELEM_SIZE(hdr.flags);
855 856 857
    return hdr;
}

858
Mat Mat::reshape(int _cn, int _newndims, const int* _newsz) const
859
{
860
    if(_newndims == dims)
861
    {
862 863 864 865
        if(_newsz == 0)
            return reshape(_cn);
        if(_newndims == 2)
            return reshape(_cn, _newsz[0]);
866
    }
867

868
    if (isContinuous())
869
    {
870
        CV_Assert(_cn >= 0 && _newndims > 0 && _newndims <= CV_MAX_DIM && _newsz);
871

872 873 874 875
        if (_cn == 0)
            _cn = this->channels();
        else
            CV_Assert(_cn <= CV_CN_MAX);
876

877 878
        size_t total_elem1_ref = this->total() * this->channels();
        size_t total_elem1 = _cn;
879

880
        AutoBuffer<int, 4> newsz_buf( (size_t)_newndims );
881

882 883 884
        for (int i = 0; i < _newndims; i++)
        {
            CV_Assert(_newsz[i] >= 0);
885

886 887 888 889 890 891
            if (_newsz[i] > 0)
                newsz_buf[i] = _newsz[i];
            else if (i < dims)
                newsz_buf[i] = this->size[i];
            else
                CV_Error(CV_StsOutOfRange, "Copy dimension (which has zero size) is not present in source matrix");
892

893 894
            total_elem1 *= (size_t)newsz_buf[i];
        }
895

896 897
        if (total_elem1 != total_elem1_ref)
            CV_Error(CV_StsUnmatchedSizes, "Requested and source matrices have different count of elements");
898

899 900
        Mat hdr = *this;
        hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((_cn-1) << CV_CN_SHIFT);
901
        setSize(hdr, _newndims, newsz_buf.data(), NULL, true);
902

903
        return hdr;
904
    }
905

906 907
    CV_Error(CV_StsNotImplemented, "Reshaping of n-dimensional non-continuous matrices is not supported yet");
    // TBD
908 909
}

910
Mat Mat::reshape(int _cn, const std::vector<int>& _newshape) const
911
{
912
    if(_newshape.empty())
913
    {
914 915
        CV_Assert(empty());
        return *this;
916 917
    }

918
    return reshape(_cn, (int)_newshape.size(), &_newshape[0]);
919
}
920

921
Mat Mat::diag(const Mat& d)
922
{
923 924 925 926 927 928 929 930 931 932
    CV_Assert( d.cols == 1 || d.rows == 1 );
    int len = d.rows + d.cols - 1;
    Mat m(len, len, d.type(), Scalar(0));
    Mat md = m.diag();
    if( d.cols == 1 )
        d.copyTo(md);
    else
        transpose(d, md);
    return m;
}
933

934
int Mat::checkVector(int _elemChannels, int _depth, bool _requireContinuous) const
A
Andrey Kamaev 已提交
935
{
936 937 938 939 940 941 942
    return data && (depth() == _depth || _depth <= 0) &&
        (isContinuous() || !_requireContinuous) &&
        ((dims == 2 && (((rows == 1 || cols == 1) && channels() == _elemChannels) ||
                        (cols == _elemChannels && channels() == 1))) ||
        (dims == 3 && channels() == 1 && size.p[2] == _elemChannels && (size.p[0] == 1 || size.p[1] == 1) &&
         (isContinuous() || step.p[1] == step.p[2]*size.p[2])))
    ? (int)(total()*channels()/_elemChannels) : -1;
A
Andrey Kamaev 已提交
943 944
}

945
} // cv::