1/*M///////////////////////////////////////////////////////////////////////////////////////
2//
3// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4//
5// By downloading, copying, installing or using the software you agree to this license.
6// If you do not agree to this license, do not download, install,
7// copy or use the software.
8//
9//
10// License Agreement
11// For Open Source Computer Vision Library
12//
13// Copyright (C) 2014, Itseez Inc., all rights reserved.
14// Third party copyrights are property of their respective owners.
15//
16// Redistribution and use in source and binary forms, with or without modification,
17// are permitted provided that the following conditions are met:
18//
19// * Redistribution's of source code must retain the above copyright notice,
20// this list of conditions and the following disclaimer.
21//
22// * Redistribution's in binary form must reproduce the above copyright notice,
23// this list of conditions and the following disclaimer in the documentation
24// and/or other materials provided with the distribution.
25//
26// * The name of the copyright holders may not be used to endorse or promote products
27// derived from this software without specific prior written permission.
28//
29// This software is provided by the copyright holders and contributors "as is" and
30// any express or implied warranties, including, but not limited to, the implied
31// warranties of merchantability and fitness for a particular purpose are disclaimed.
32// In no event shall the Intel Corporation or contributors be liable for any direct,
33// indirect, incidental, special, exemplary, or consequential damages
34// (including, but not limited to, procurement of substitute goods or services;
35// loss of use, data, or profits; or business interruption) however caused
36// and on any theory of liability, whether in contract, strict liability,
37// or tort (including negligence or otherwise) arising in any way out of
38// the use of this software, even if advised of the possibility of such damage.
39//
40//M*/
41
42#include "precomp.hpp"
43#include "opencl_kernels_core.hpp"
44#include "umatrix.hpp"
45
46#include <opencv2/core/utils/tls.hpp>
47
48///////////////////////////////// UMat implementation ///////////////////////////////
49
50namespace cv {
51
52// forward decls, implementation is below in this file
53void setSize(UMat& m, int _dims, const int* _sz, const size_t* _steps,
54 bool autoSteps = false);
55
56void updateContinuityFlag(UMat& m);
57void finalizeHdr(UMat& m);
58
59UMatData::UMatData(const MatAllocator* allocator)
60{
61 prevAllocator = currAllocator = allocator;
62 urefcount = refcount = mapcount = 0;
63 data = origdata = 0;
64 size = 0;
65 flags = static_cast<UMatData::MemoryFlag>(0);
66 handle = 0;
67 userdata = 0;
68 allocatorFlags_ = 0;
69 originalUMatData = NULL;
70}
71
72UMatData::~UMatData()
73{
74 prevAllocator = currAllocator = 0;
75 urefcount = refcount = 0;
76 CV_Assert(mapcount == 0);
77 data = origdata = 0;
78 size = 0;
79 bool isAsyncCleanup = !!(flags & UMatData::ASYNC_CLEANUP);
80 flags = static_cast<UMatData::MemoryFlag>(0);
81 handle = 0;
82 userdata = 0;
83 allocatorFlags_ = 0;
84 if (originalUMatData)
85 {
86 bool showWarn = false;
87 UMatData* u = originalUMatData;
88 bool zero_Ref = CV_XADD(&(u->refcount), -1) == 1;
89 if (zero_Ref)
90 {
91 // simulate Mat::deallocate
92 if (u->mapcount != 0)
93 {
94 (u->currAllocator ? u->currAllocator : /* TODO allocator ? allocator :*/ Mat::getDefaultAllocator())->unmap(data: u);
95 }
96 else
97 {
98 // we don't do "map", so we can't do "unmap"
99 }
100 }
101 bool zero_URef = CV_XADD(&(u->urefcount), -1) == 1;
102 if (zero_Ref && !zero_URef)
103 showWarn = true;
104 if (zero_Ref && zero_URef) // oops, we need to free resources
105 {
106 showWarn = !isAsyncCleanup;
107 // simulate UMat::deallocate
108 u->currAllocator->deallocate(data: u);
109 }
110#ifndef NDEBUG
111 if (showWarn)
112 {
113 static int warn_message_showed = 0;
114 if (warn_message_showed++ < 100)
115 {
116 fflush(stdout);
117 fprintf(stderr, "\n! OPENCV warning: getUMat()/getMat() call chain possible problem."
118 "\n! Base object is dead, while nested/derived object is still alive or processed."
119 "\n! Please check lifetime of UMat/Mat objects!\n");
120 fflush(stderr);
121 }
122 }
123#else
124 CV_UNUSED(showWarn);
125#endif
126 originalUMatData = NULL;
127 }
128}
129
130#ifndef OPENCV_DISABLE_THREAD_SUPPORT
131
132// it should be a prime number for the best hash function
133enum { UMAT_NLOCKS = 31 };
134static Mutex umatLocks[UMAT_NLOCKS];
135
136static size_t getUMatDataLockIndex(const UMatData* u)
137{
138 size_t idx = ((size_t)(void*)u) % UMAT_NLOCKS;
139 return idx;
140}
141
142void UMatData::lock()
143{
144 size_t idx = getUMatDataLockIndex(u: this);
145 //printf("%d lock(%d)\n", cv::utils::getThreadID(), (int)idx);
146 umatLocks[idx].lock();
147}
148
149void UMatData::unlock()
150{
151 size_t idx = getUMatDataLockIndex(u: this);
152 //printf("%d unlock(%d)\n", cv::utils::getThreadID(), (int)idx);
153 umatLocks[idx].unlock();
154}
155
156
157// Do not allow several lock() calls with different UMatData objects.
158struct UMatDataAutoLocker
159{
160 int usage_count;
161 UMatData* locked_objects[2];
162 UMatDataAutoLocker() : usage_count(0) { locked_objects[0] = NULL; locked_objects[1] = NULL; }
163
164 void lock(UMatData*& u1)
165 {
166 bool locked_1 = (u1 == locked_objects[0] || u1 == locked_objects[1]);
167 if (locked_1)
168 {
169 u1 = NULL;
170 return;
171 }
172 CV_Assert(usage_count == 0); // UMatDataAutoLock can't be used multiple times from the same thread
173 usage_count = 1;
174 locked_objects[0] = u1;
175 u1->lock();
176 }
177 void lock(UMatData*& u1, UMatData*& u2)
178 {
179 bool locked_1 = (u1 == locked_objects[0] || u1 == locked_objects[1]);
180 bool locked_2 = (u2 == locked_objects[0] || u2 == locked_objects[1]);
181 if (locked_1)
182 u1 = NULL;
183 if (locked_2)
184 u2 = NULL;
185 if (locked_1 && locked_2)
186 return;
187 CV_Assert(usage_count == 0); // UMatDataAutoLock can't be used multiple times from the same thread
188 usage_count = 1;
189 locked_objects[0] = u1;
190 locked_objects[1] = u2;
191 if (u1)
192 u1->lock();
193 if (u2)
194 u2->lock();
195 }
196 void release(UMatData* u1, UMatData* u2)
197 {
198 if (u1 == NULL && u2 == NULL)
199 return;
200 CV_Assert(usage_count == 1);
201 usage_count = 0;
202 if (u1)
203 u1->unlock();
204 if (u2)
205 u2->unlock();
206 locked_objects[0] = NULL; locked_objects[1] = NULL;
207 }
208};
209static TLSData<UMatDataAutoLocker>& getUMatDataAutoLockerTLS()
210{
211 CV_SINGLETON_LAZY_INIT_REF(TLSData<UMatDataAutoLocker>, new TLSData<UMatDataAutoLocker>());
212}
213static UMatDataAutoLocker& getUMatDataAutoLocker() { return getUMatDataAutoLockerTLS().getRef(); }
214
215
216UMatDataAutoLock::UMatDataAutoLock(UMatData* u) : u1(u), u2(NULL)
217{
218 getUMatDataAutoLocker().lock(u1);
219}
220UMatDataAutoLock::UMatDataAutoLock(UMatData* u1_, UMatData* u2_) : u1(u1_), u2(u2_)
221{
222 if (getUMatDataLockIndex(u: u1) > getUMatDataLockIndex(u: u2))
223 {
224 std::swap(a&: u1, b&: u2);
225 }
226 getUMatDataAutoLocker().lock(u1, u2);
227}
228UMatDataAutoLock::~UMatDataAutoLock()
229{
230 getUMatDataAutoLocker().release(u1, u2);
231}
232
233#else
234
235void UMatData::lock()
236{
237 // nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
238}
239
240void UMatData::unlock()
241{
242 // nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
243}
244
245UMatDataAutoLock::UMatDataAutoLock(UMatData* u) : u1(u), u2(NULL)
246{
247 // nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
248}
249UMatDataAutoLock::UMatDataAutoLock(UMatData* u1_, UMatData* u2_) : u1(u1_), u2(u2_)
250{
251 // nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
252}
253UMatDataAutoLock::~UMatDataAutoLock()
254{
255 // nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
256}
257
258#endif // OPENCV_DISABLE_THREAD_SUPPORT
259
260//////////////////////////////// UMat ////////////////////////////////
261
262UMat::UMat(UMatUsageFlags _usageFlags) CV_NOEXCEPT
263: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows)
264{}
265
266UMat::UMat(int _rows, int _cols, int _type, UMatUsageFlags _usageFlags)
267: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows)
268{
269 create(rows: _rows, cols: _cols, type: _type);
270}
271
272UMat::UMat(int _rows, int _cols, int _type, const Scalar& _s, UMatUsageFlags _usageFlags)
273: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows)
274{
275 create(rows: _rows, cols: _cols, type: _type);
276 *this = _s;
277}
278
279UMat::UMat(Size _sz, int _type, UMatUsageFlags _usageFlags)
280: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows)
281{
282 create( rows: _sz.height, cols: _sz.width, type: _type );
283}
284
285UMat::UMat(Size _sz, int _type, const Scalar& _s, UMatUsageFlags _usageFlags)
286: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows)
287{
288 create(rows: _sz.height, cols: _sz.width, type: _type);
289 *this = _s;
290}
291
292UMat::UMat(int _dims, const int* _sz, int _type, UMatUsageFlags _usageFlags)
293: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows)
294{
295 create(ndims: _dims, sizes: _sz, type: _type);
296}
297
298UMat::UMat(int _dims, const int* _sz, int _type, const Scalar& _s, UMatUsageFlags _usageFlags)
299: flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(_usageFlags), u(0), offset(0), size(&rows)
300{
301 create(ndims: _dims, sizes: _sz, type: _type);
302 *this = _s;
303}
304
305UMat::UMat(const UMat& m)
306: flags(m.flags), dims(m.dims), rows(m.rows), cols(m.cols), allocator(m.allocator),
307 usageFlags(m.usageFlags), u(m.u), offset(m.offset), size(&rows)
308{
309 addref();
310 if( m.dims <= 2 )
311 {
312 step[0] = m.step[0]; step[1] = m.step[1];
313 }
314 else
315 {
316 dims = 0;
317 copySize(m);
318 }
319}
320
321UMat& UMat::operator=(const UMat& m)
322{
323 if( this != &m )
324 {
325 const_cast<UMat&>(m).addref();
326 release();
327 flags = m.flags;
328 if( dims <= 2 && m.dims <= 2 )
329 {
330 dims = m.dims;
331 rows = m.rows;
332 cols = m.cols;
333 step[0] = m.step[0];
334 step[1] = m.step[1];
335 }
336 else
337 copySize(m);
338 allocator = m.allocator;
339 usageFlags = m.usageFlags;
340 u = m.u;
341 offset = m.offset;
342 }
343 return *this;
344}
345
346UMat UMat::clone() const
347{
348 UMat m;
349 copyTo(m);
350 return m;
351}
352
353void UMat::assignTo(UMat& m, int _type) const
354{
355 if( _type < 0 )
356 m = *this;
357 else
358 convertTo(m, rtype: _type);
359}
360
361void UMat::create(int _rows, int _cols, int _type, UMatUsageFlags _usageFlags)
362{
363 int sz[] = {_rows, _cols};
364 create(ndims: 2, sizes: sz, type: _type, usageFlags: _usageFlags);
365}
366
367void UMat::create(Size _sz, int _type, UMatUsageFlags _usageFlags)
368{
369 create(rows: _sz.height, cols: _sz.width, _type, _usageFlags);
370}
371
372void UMat::addref()
373{
374 if( u )
375 CV_XADD(&(u->urefcount), 1);
376}
377
378void UMat::release()
379{
380 if( u && CV_XADD(&(u->urefcount), -1) == 1 )
381 deallocate();
382 for(int i = 0; i < dims; i++)
383 size.p[i] = 0;
384 u = 0;
385}
386
387bool UMat::empty() const
388{
389 return u == 0 || total() == 0 || dims == 0;
390}
391
392size_t UMat::total() const
393{
394 if( dims <= 2 )
395 return (size_t)rows * cols;
396 size_t p = 1;
397 for( int i = 0; i < dims; i++ )
398 p *= size[i];
399 return p;
400}
401
402
403UMat::UMat(UMat&& m)
404: flags(m.flags), dims(m.dims), rows(m.rows), cols(m.cols), allocator(m.allocator),
405 usageFlags(m.usageFlags), u(m.u), offset(m.offset), size(&rows)
406{
407 if (m.dims <= 2) // move new step/size info
408 {
409 step[0] = m.step[0];
410 step[1] = m.step[1];
411 }
412 else
413 {
414 CV_DbgAssert(m.step.p != m.step.buf);
415 step.p = m.step.p;
416 size.p = m.size.p;
417 m.step.p = m.step.buf;
418 m.size.p = &m.rows;
419 }
420 m.flags = MAGIC_VAL; m.dims = m.rows = m.cols = 0;
421 m.allocator = NULL;
422 m.u = NULL;
423 m.offset = 0;
424}
425
426UMat& UMat::operator=(UMat&& m)
427{
428 if (this == &m)
429 return *this;
430 release();
431 flags = m.flags; dims = m.dims; rows = m.rows; cols = m.cols;
432 allocator = m.allocator; usageFlags = m.usageFlags;
433 u = m.u;
434 offset = m.offset;
435 if (step.p != step.buf) // release self step/size
436 {
437 fastFree(ptr: step.p);
438 step.p = step.buf;
439 size.p = &rows;
440 }
441 if (m.dims <= 2) // move new step/size info
442 {
443 step[0] = m.step[0];
444 step[1] = m.step[1];
445 }
446 else
447 {
448 CV_DbgAssert(m.step.p != m.step.buf);
449 step.p = m.step.p;
450 size.p = m.size.p;
451 m.step.p = m.step.buf;
452 m.size.p = &m.rows;
453 }
454 m.flags = MAGIC_VAL;
455 m.usageFlags = USAGE_DEFAULT;
456 m.dims = m.rows = m.cols = 0;
457 m.allocator = NULL;
458 m.u = NULL;
459 m.offset = 0;
460 return *this;
461}
462
463
464MatAllocator* UMat::getStdAllocator()
465{
466#ifdef HAVE_OPENCL
467 if (ocl::useOpenCL())
468 return ocl::getOpenCLAllocator();
469#endif
470 return Mat::getDefaultAllocator();
471}
472
473void swap( UMat& a, UMat& b )
474{
475 std::swap(a&: a.flags, b&: b.flags);
476 std::swap(a&: a.dims, b&: b.dims);
477 std::swap(a&: a.rows, b&: b.rows);
478 std::swap(a&: a.cols, b&: b.cols);
479 std::swap(a&: a.allocator, b&: b.allocator);
480 std::swap(a&: a.u, b&: b.u);
481 std::swap(a&: a.offset, b&: b.offset);
482
483 std::swap(a&: a.size.p, b&: b.size.p);
484 std::swap(a&: a.step.p, b&: b.step.p);
485 std::swap(a&: a.step.buf[0], b&: b.step.buf[0]);
486 std::swap(a&: a.step.buf[1], b&: b.step.buf[1]);
487
488 if( a.step.p == b.step.buf )
489 {
490 a.step.p = a.step.buf;
491 a.size.p = &a.rows;
492 }
493
494 if( b.step.p == a.step.buf )
495 {
496 b.step.p = b.step.buf;
497 b.size.p = &b.rows;
498 }
499}
500
501
502void setSize( UMat& m, int _dims, const int* _sz,
503 const size_t* _steps, bool autoSteps )
504{
505 CV_Assert( 0 <= _dims && _dims <= CV_MAX_DIM );
506 if( m.dims != _dims )
507 {
508 if( m.step.p != m.step.buf )
509 {
510 fastFree(ptr: m.step.p);
511 m.step.p = m.step.buf;
512 m.size.p = &m.rows;
513 }
514 if( _dims > 2 )
515 {
516 m.step.p = (size_t*)fastMalloc(bufSize: _dims*sizeof(m.step.p[0]) + (_dims+1)*sizeof(m.size.p[0]));
517 m.size.p = (int*)(m.step.p + _dims) + 1;
518 m.size.p[-1] = _dims;
519 m.rows = m.cols = -1;
520 }
521 }
522
523 m.dims = _dims;
524 if( !_sz )
525 return;
526
527 size_t esz = CV_ELEM_SIZE(m.flags), total = esz;
528 int i;
529 for( i = _dims-1; i >= 0; i-- )
530 {
531 int s = _sz[i];
532 CV_Assert( s >= 0 );
533 m.size.p[i] = s;
534
535 if( _steps )
536 m.step.p[i] = i < _dims-1 ? _steps[i] : esz;
537 else if( autoSteps )
538 {
539 m.step.p[i] = total;
540 int64 total1 = (int64)total*s;
541 if( (uint64)total1 != (size_t)total1 )
542 CV_Error( cv::Error::StsOutOfRange, "The total matrix size does not fit to \"size_t\" type" );
543 total = (size_t)total1;
544 }
545 }
546
547 if( _dims == 1 )
548 {
549 m.dims = 2;
550 m.cols = 1;
551 m.step[1] = esz;
552 }
553}
554
555
556void UMat::updateContinuityFlag()
557{
558 flags = cv::updateContinuityFlag(flags, dims, size: size.p, step: step.p);
559}
560
561
562void finalizeHdr(UMat& m)
563{
564 m.updateContinuityFlag();
565 int d = m.dims;
566 if( d > 2 )
567 m.rows = m.cols = -1;
568}
569
570
571UMat Mat::getUMat(AccessFlag accessFlags, UMatUsageFlags usageFlags) const
572{
573 UMat hdr;
574 if(!data)
575 return hdr;
576 if (data != datastart)
577 {
578 Size wholeSize;
579 Point ofs;
580 locateROI(wholeSize, ofs);
581 Size sz(cols, rows);
582 if (ofs.x != 0 || ofs.y != 0)
583 {
584 Mat src = *this;
585 int dtop = ofs.y;
586 int dbottom = wholeSize.height - src.rows - ofs.y;
587 int dleft = ofs.x;
588 int dright = wholeSize.width - src.cols - ofs.x;
589 src.adjustROI(dtop, dbottom, dleft, dright);
590 return src.getUMat(accessFlags, usageFlags)(cv::Rect(ofs.x, ofs.y, sz.width, sz.height));
591 }
592 }
593 CV_Assert(data == datastart);
594
595 accessFlags |= ACCESS_RW;
596 UMatData* new_u = NULL;
597 {
598 MatAllocator *a = allocator, *a0 = getDefaultAllocator();
599 if(!a)
600 a = a0;
601 new_u = a->allocate(dims, sizes: size.p, type: type(), data, step: step.p, flags: accessFlags, usageFlags);
602 new_u->originalUMatData = u;
603 }
604 bool allocated = false;
605 try
606 {
607 allocated = UMat::getStdAllocator()->allocate(data: new_u, accessflags: accessFlags, usageFlags);
608 }
609 catch (const cv::Exception& e)
610 {
611 fprintf(stderr, format: "Exception: %s\n", e.what());
612 }
613 if (!allocated)
614 {
615 allocated = getDefaultAllocator()->allocate(data: new_u, accessflags: accessFlags, usageFlags);
616 CV_Assert(allocated);
617 }
618 if (u != NULL)
619 {
620#ifdef HAVE_OPENCL
621 if (ocl::useOpenCL() && new_u->currAllocator == ocl::getOpenCLAllocator())
622 {
623 CV_Assert(new_u->tempUMat());
624 }
625#endif
626 CV_XADD(&(u->refcount), 1);
627 CV_XADD(&(u->urefcount), 1);
628 }
629 try
630 {
631 hdr.flags = flags;
632 hdr.usageFlags = usageFlags;
633 setSize(m&: hdr, dims: dims, sz: size.p, steps: step.p);
634 finalizeHdr(m&: hdr);
635 hdr.u = new_u;
636 hdr.offset = 0; //data - datastart;
637 hdr.addref();
638 return hdr;
639 }
640 catch(...)
641 {
642 if (u != NULL)
643 {
644 CV_XADD(&(u->refcount), -1);
645 CV_XADD(&(u->urefcount), -1);
646 }
647 new_u->currAllocator->deallocate(data: new_u);
648 throw;
649 }
650
651}
652
653void UMat::create(int d, const int* _sizes, int _type, UMatUsageFlags _usageFlags)
654{
655 int i;
656 CV_Assert(0 <= d && d <= CV_MAX_DIM && _sizes);
657 _type = CV_MAT_TYPE(_type);
658
659 // if param value is USAGE_DEFAULT by implicit default param value -or- explicit value
660 // ...then don't change the existing usageFlags
661 // it is not possible to change usage from non-default to USAGE_DEFAULT through create()
662 // ...instead must construct UMat()
663 if (_usageFlags == cv::USAGE_DEFAULT)
664 {
665 _usageFlags = usageFlags;
666 }
667
668 if( u && (d == dims || (d == 1 && dims <= 2)) && _type == type() && _usageFlags == usageFlags )
669 {
670 for( i = 0; i < d; i++ )
671 if( size[i] != _sizes[i] )
672 break;
673 if( i == d && (d > 1 || size[1] == 1))
674 return;
675 }
676
677 int _sizes_backup[CV_MAX_DIM]; // #5991
678 if (_sizes == (this->size.p))
679 {
680 for(i = 0; i < d; i++ )
681 _sizes_backup[i] = _sizes[i];
682 _sizes = _sizes_backup;
683 }
684
685 release();
686 usageFlags = _usageFlags;
687 if( d == 0 )
688 return;
689 flags = (_type & CV_MAT_TYPE_MASK) | MAGIC_VAL;
690 setSize(m&: *this, dims: d, sz: _sizes, steps: 0, autoSteps: true);
691 offset = 0;
692
693 if( total() > 0 )
694 {
695 MatAllocator *a = allocator, *a0 = getStdAllocator();
696 if (!a)
697 {
698 a = a0;
699 a0 = Mat::getDefaultAllocator();
700 }
701 try
702 {
703 u = a->allocate(dims, sizes: size, type: _type, data: 0, step: step.p, flags: ACCESS_RW /* ignored */, usageFlags);
704 CV_Assert(u != 0);
705 }
706 catch(...)
707 {
708 if(a != a0)
709 u = a0->allocate(dims, sizes: size, type: _type, data: 0, step: step.p, flags: ACCESS_RW /* ignored */, usageFlags);
710 CV_Assert(u != 0);
711 }
712 CV_Assert( step[dims-1] == (size_t)CV_ELEM_SIZE(flags) );
713 }
714
715 finalizeHdr(m&: *this);
716 addref();
717}
718
719void UMat::create(const std::vector<int>& _sizes, int _type, UMatUsageFlags _usageFlags)
720{
721 create(d: (int)_sizes.size(), sizes: _sizes.data(), _type, _usageFlags);
722}
723
724void UMat::copySize(const UMat& m)
725{
726 setSize(m&: *this, dims: m.dims, sz: 0, steps: 0);
727 for( int i = 0; i < dims; i++ )
728 {
729 size[i] = m.size[i];
730 step[i] = m.step[i];
731 }
732}
733
734
735UMat::~UMat()
736{
737 release();
738 if( step.p != step.buf )
739 fastFree(ptr: step.p);
740}
741
742void UMat::deallocate()
743{
744 UMatData* u_ = u;
745 u = NULL;
746 u_->currAllocator->deallocate(data: u_);
747}
748
749
750UMat::UMat(const UMat& m, const Range& _rowRange, const Range& _colRange)
751 : flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(USAGE_DEFAULT), u(0), offset(0), size(&rows)
752{
753 CV_Assert( m.dims >= 2 );
754 if( m.dims > 2 )
755 {
756 AutoBuffer<Range> rs(m.dims);
757 rs[0] = _rowRange;
758 rs[1] = _colRange;
759 for( int i = 2; i < m.dims; i++ )
760 rs[i] = Range::all();
761 *this = m(rs.data());
762 return;
763 }
764
765 *this = m;
766 if( _rowRange != Range::all() && _rowRange != Range(0,rows) )
767 {
768 CV_Assert( 0 <= _rowRange.start && _rowRange.start <= _rowRange.end && _rowRange.end <= m.rows );
769 rows = _rowRange.size();
770 offset += step*_rowRange.start;
771 flags |= SUBMATRIX_FLAG;
772 }
773
774 if( _colRange != Range::all() && _colRange != Range(0,cols) )
775 {
776 CV_Assert( 0 <= _colRange.start && _colRange.start <= _colRange.end && _colRange.end <= m.cols );
777 cols = _colRange.size();
778 offset += _colRange.start*elemSize();
779 flags |= SUBMATRIX_FLAG;
780 }
781
782 updateContinuityFlag();
783
784 if( rows <= 0 || cols <= 0 )
785 {
786 release();
787 rows = cols = 0;
788 }
789}
790
791
792UMat::UMat(const UMat& m, const Rect& roi)
793 : flags(m.flags), dims(2), rows(roi.height), cols(roi.width),
794 allocator(m.allocator), usageFlags(m.usageFlags), u(m.u), offset(m.offset + roi.y*m.step[0]), size(&rows)
795{
796 CV_Assert( m.dims <= 2 );
797
798 size_t esz = CV_ELEM_SIZE(flags);
799 offset += roi.x*esz;
800 CV_Assert( 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols &&
801 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows );
802 if( roi.width < m.cols || roi.height < m.rows )
803 flags |= SUBMATRIX_FLAG;
804
805 step[0] = m.step[0]; step[1] = esz;
806 updateContinuityFlag();
807
808 addref();
809 if( rows <= 0 || cols <= 0 )
810 {
811 rows = cols = 0;
812 release();
813 }
814}
815
816
817UMat::UMat(const UMat& m, const Range* ranges)
818 : flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(USAGE_DEFAULT), u(0), offset(0), size(&rows)
819{
820 int i, d = m.dims;
821
822 CV_Assert(ranges);
823 for( i = 0; i < d; i++ )
824 {
825 Range r = ranges[i];
826 CV_Assert( r == Range::all() || (0 <= r.start && r.start < r.end && r.end <= m.size[i]) );
827 }
828 *this = m;
829 for( i = 0; i < d; i++ )
830 {
831 Range r = ranges[i];
832 if( r != Range::all() && r != Range(0, size.p[i]))
833 {
834 size.p[i] = r.end - r.start;
835 offset += r.start*step.p[i];
836 flags |= SUBMATRIX_FLAG;
837 }
838 }
839 updateContinuityFlag();
840}
841
842UMat::UMat(const UMat& m, const std::vector<Range>& ranges)
843 : flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(USAGE_DEFAULT), u(0), offset(0), size(&rows)
844{
845 int i, d = m.dims;
846
847 CV_Assert((int)ranges.size() == d);
848 for (i = 0; i < d; i++)
849 {
850 Range r = ranges[i];
851 CV_Assert(r == Range::all() || (0 <= r.start && r.start < r.end && r.end <= m.size[i]));
852 }
853 *this = m;
854 for (i = 0; i < d; i++)
855 {
856 Range r = ranges[i];
857 if (r != Range::all() && r != Range(0, size.p[i]))
858 {
859 size.p[i] = r.end - r.start;
860 offset += r.start*step.p[i];
861 flags |= SUBMATRIX_FLAG;
862 }
863 }
864 updateContinuityFlag();
865}
866
867UMat UMat::diag(int d) const
868{
869 CV_Assert( dims <= 2 );
870 UMat m = *this;
871 size_t esz = elemSize();
872 int len;
873
874 if( d >= 0 )
875 {
876 len = std::min(a: cols - d, b: rows);
877 m.offset += esz*d;
878 }
879 else
880 {
881 len = std::min(a: rows + d, b: cols);
882 m.offset -= step[0]*d;
883 }
884 CV_DbgAssert( len > 0 );
885
886 m.size[0] = m.rows = len;
887 m.size[1] = m.cols = 1;
888 m.step[0] += (len > 1 ? esz : 0);
889
890 m.updateContinuityFlag();
891
892 if( size() != Size(1,1) )
893 m.flags |= SUBMATRIX_FLAG;
894
895 return m;
896}
897
898void UMat::locateROI( Size& wholeSize, Point& ofs ) const
899{
900 CV_Assert( dims <= 2 && step[0] > 0 );
901 size_t esz = elemSize(), minstep;
902 ptrdiff_t delta1 = (ptrdiff_t)offset, delta2 = (ptrdiff_t)u->size;
903
904 if( delta1 == 0 )
905 ofs.x = ofs.y = 0;
906 else
907 {
908 ofs.y = (int)(delta1/step[0]);
909 ofs.x = (int)((delta1 - step[0]*ofs.y)/esz);
910 CV_DbgAssert( offset == (size_t)(ofs.y*step[0] + ofs.x*esz) );
911 }
912 minstep = (ofs.x + cols)*esz;
913 wholeSize.height = (int)((delta2 - minstep)/step[0] + 1);
914 wholeSize.height = std::max(a: wholeSize.height, b: ofs.y + rows);
915 wholeSize.width = (int)((delta2 - step*(wholeSize.height-1))/esz);
916 wholeSize.width = std::max(a: wholeSize.width, b: ofs.x + cols);
917}
918
919
920UMat& UMat::adjustROI( int dtop, int dbottom, int dleft, int dright )
921{
922 CV_Assert( dims <= 2 && step[0] > 0 );
923 Size wholeSize; Point ofs;
924 size_t esz = elemSize();
925 locateROI( wholeSize, ofs );
926 int row1 = std::min(a: std::max(a: ofs.y - dtop, b: 0), b: wholeSize.height), row2 = std::max(a: 0, b: std::min(a: ofs.y + rows + dbottom, b: wholeSize.height));
927 int col1 = std::min(a: std::max(a: ofs.x - dleft, b: 0), b: wholeSize.width), col2 = std::max(a: 0, b: std::min(a: ofs.x + cols + dright, b: wholeSize.width));
928 if(row1 > row2)
929 std::swap(a&: row1, b&: row2);
930 if(col1 > col2)
931 std::swap(a&: col1, b&: col2);
932
933 offset += (row1 - ofs.y)*step + (col1 - ofs.x)*esz;
934 rows = row2 - row1; cols = col2 - col1;
935 size.p[0] = rows; size.p[1] = cols;
936 updateContinuityFlag();
937 return *this;
938}
939
940
941UMat UMat::reshape(int new_cn, int new_rows) const
942{
943 int cn = channels();
944 UMat hdr = *this;
945
946 if( dims > 2 && new_rows == 0 && new_cn != 0 && size[dims-1]*cn % new_cn == 0 )
947 {
948 hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((new_cn-1) << CV_CN_SHIFT);
949 hdr.step[dims-1] = CV_ELEM_SIZE(hdr.flags);
950 hdr.size[dims-1] = hdr.size[dims-1]*cn / new_cn;
951 return hdr;
952 }
953
954 CV_Assert( dims <= 2 );
955
956 if( new_cn == 0 )
957 new_cn = cn;
958
959 int total_width = cols * cn;
960
961 if( (new_cn > total_width || total_width % new_cn != 0) && new_rows == 0 )
962 new_rows = rows * total_width / new_cn;
963
964 if( new_rows != 0 && new_rows != rows )
965 {
966 int total_size = total_width * rows;
967 if( !isContinuous() )
968 CV_Error( cv::Error::BadStep,
969 "The matrix is not continuous, thus its number of rows can not be changed" );
970
971 if( (unsigned)new_rows > (unsigned)total_size )
972 CV_Error( cv::Error::StsOutOfRange, "Bad new number of rows" );
973
974 total_width = total_size / new_rows;
975
976 if( total_width * new_rows != total_size )
977 CV_Error( cv::Error::StsBadArg, "The total number of matrix elements "
978 "is not divisible by the new number of rows" );
979
980 hdr.rows = new_rows;
981 hdr.step[0] = total_width * elemSize1();
982 }
983
984 int new_width = total_width / new_cn;
985
986 if( new_width * new_cn != total_width )
987 CV_Error( cv::Error::BadNumChannels,
988 "The total width is not divisible by the new number of channels" );
989
990 hdr.cols = new_width;
991 hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((new_cn-1) << CV_CN_SHIFT);
992 hdr.step[1] = CV_ELEM_SIZE(hdr.flags);
993 return hdr;
994}
995
996UMat UMat::diag(const UMat& d, UMatUsageFlags usageFlags)
997{
998 CV_Assert( d.cols == 1 || d.rows == 1 );
999 int len = d.rows + d.cols - 1;
1000 UMat m(len, len, d.type(), Scalar(0), usageFlags);
1001 UMat md = m.diag();
1002 if( d.cols == 1 )
1003 d.copyTo(m: md);
1004 else
1005 transpose(src: d, dst: md);
1006 return m;
1007}
1008
1009int UMat::checkVector(int _elemChannels, int _depth, bool _requireContinuous) const
1010{
1011 return (depth() == _depth || _depth <= 0) &&
1012 (isContinuous() || !_requireContinuous) &&
1013 ((dims == 2 && (((rows == 1 || cols == 1) && channels() == _elemChannels) ||
1014 (cols == _elemChannels && channels() == 1))) ||
1015 (dims == 3 && channels() == 1 && size.p[2] == _elemChannels && (size.p[0] == 1 || size.p[1] == 1) &&
1016 (isContinuous() || step.p[1] == step.p[2]*size.p[2])))
1017 ? (int)(total()*channels()/_elemChannels) : -1;
1018}
1019
1020UMat UMat::reshape(int _cn, int _newndims, const int* _newsz) const
1021{
1022 if(_newndims == dims)
1023 {
1024 if(_newsz == 0)
1025 return reshape(new_cn: _cn);
1026 if(_newndims == 2)
1027 return reshape(new_cn: _cn, new_rows: _newsz[0]);
1028 }
1029
1030 if (isContinuous())
1031 {
1032 CV_Assert(_cn >= 0 && _newndims > 0 && _newndims <= CV_MAX_DIM && _newsz);
1033
1034 if (_cn == 0)
1035 _cn = this->channels();
1036 else
1037 CV_Assert(_cn <= CV_CN_MAX);
1038
1039 size_t total_elem1_ref = this->total() * this->channels();
1040 size_t total_elem1 = _cn;
1041
1042 AutoBuffer<int, 4> newsz_buf( (size_t)_newndims );
1043
1044 for (int i = 0; i < _newndims; i++)
1045 {
1046 CV_Assert(_newsz[i] >= 0);
1047
1048 if (_newsz[i] > 0)
1049 newsz_buf[i] = _newsz[i];
1050 else if (i < dims)
1051 newsz_buf[i] = this->size[i];
1052 else
1053 CV_Error(cv::Error::StsOutOfRange, "Copy dimension (which has zero size) is not present in source matrix");
1054
1055 total_elem1 *= (size_t)newsz_buf[i];
1056 }
1057
1058 if (total_elem1 != total_elem1_ref)
1059 CV_Error(cv::Error::StsUnmatchedSizes, "Requested and source matrices have different count of elements");
1060
1061 UMat hdr = *this;
1062 hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((_cn-1) << CV_CN_SHIFT);
1063 setSize(m&: hdr, dims: _newndims, sz: newsz_buf.data(), NULL, autoSteps: true);
1064
1065 return hdr;
1066 }
1067
1068 CV_Error(cv::Error::StsNotImplemented, "Reshaping of n-dimensional non-continuous matrices is not supported yet");
1069}
1070
1071Mat UMat::getMat(AccessFlag accessFlags) const
1072{
1073 if(!u)
1074 return Mat();
1075 // TODO Support ACCESS_READ (ACCESS_WRITE) without unnecessary data transfers
1076 accessFlags |= ACCESS_RW;
1077 UMatDataAutoLock autolock(u);
1078 try
1079 {
1080 if(CV_XADD(&u->refcount, 1) == 0)
1081 u->currAllocator->map(data: u, accessflags: accessFlags);
1082 if (u->data != 0)
1083 {
1084 Mat hdr(dims, size.p, type(), u->data + offset, step.p);
1085 hdr.flags = flags;
1086 hdr.u = u;
1087 hdr.datastart = u->data;
1088 hdr.data = u->data + offset;
1089 hdr.datalimit = hdr.dataend = u->data + u->size;
1090 return hdr;
1091 }
1092 }
1093 catch(...)
1094 {
1095 CV_XADD(&u->refcount, -1);
1096 throw;
1097 }
1098 CV_XADD(&u->refcount, -1);
1099 CV_Assert(u->data != 0 && "Error mapping of UMat to host memory.");
1100 return Mat();
1101}
1102
1103void* UMat::handle(AccessFlag accessFlags) const
1104{
1105 if( !u )
1106 return 0;
1107
1108 CV_Assert(u->refcount == 0);
1109 CV_Assert(!u->deviceCopyObsolete() || u->copyOnMap());
1110 if (u->deviceCopyObsolete())
1111 {
1112 u->currAllocator->unmap(data: u);
1113 }
1114
1115 if (!!(accessFlags & ACCESS_WRITE))
1116 u->markHostCopyObsolete(flag: true);
1117
1118 return u->handle;
1119}
1120
1121void UMat::ndoffset(size_t* ofs) const
1122{
1123 // offset = step[0]*ofs[0] + step[1]*ofs[1] + step[2]*ofs[2] + ...;
1124 size_t val = offset;
1125 for( int i = 0; i < dims; i++ )
1126 {
1127 size_t s = step.p[i];
1128 ofs[i] = val / s;
1129 val -= ofs[i]*s;
1130 }
1131}
1132
1133void UMat::copyTo(OutputArray _dst) const
1134{
1135 CV_INSTRUMENT_REGION();
1136
1137#ifdef HAVE_CUDA
1138 if (_dst.isGpuMat())
1139 {
1140 _dst.getGpuMat().upload(*this);
1141 return;
1142 }
1143#endif
1144
1145 int dtype = _dst.type();
1146 if( _dst.fixedType() && dtype != type() )
1147 {
1148 CV_Assert( channels() == CV_MAT_CN(dtype) );
1149 convertTo( m: _dst, rtype: dtype );
1150 return;
1151 }
1152
1153 if( empty() )
1154 {
1155 _dst.release();
1156 return;
1157 }
1158
1159 size_t i, sz[CV_MAX_DIM] = {0}, srcofs[CV_MAX_DIM], dstofs[CV_MAX_DIM], esz = elemSize();
1160 for( i = 0; i < (size_t)dims; i++ )
1161 sz[i] = size.p[i];
1162 sz[dims-1] *= esz;
1163 ndoffset(ofs: srcofs);
1164 srcofs[dims-1] *= esz;
1165
1166 _dst.create( dims, size: size.p, type: type() );
1167 if( _dst.isUMat() )
1168 {
1169 UMat dst = _dst.getUMat();
1170 CV_Assert(dst.u);
1171 if( u == dst.u && dst.offset == offset )
1172 return;
1173
1174 if (u->currAllocator == dst.u->currAllocator)
1175 {
1176 dst.ndoffset(ofs: dstofs);
1177 dstofs[dims-1] *= esz;
1178 u->currAllocator->copy(srcdata: u, dstdata: dst.u, dims, sz, srcofs, srcstep: step.p, dstofs, dststep: dst.step.p, sync: false);
1179 return;
1180 }
1181 }
1182
1183 Mat dst = _dst.getMat();
1184 u->currAllocator->download(data: u, dst: dst.ptr(), dims, sz, srcofs, srcstep: step.p, dststep: dst.step.p);
1185}
1186
1187void UMat::copyTo(OutputArray _dst, InputArray _mask) const
1188{
1189 CV_INSTRUMENT_REGION();
1190
1191 if( _mask.empty() )
1192 {
1193 copyTo(_dst);
1194 return;
1195 }
1196#ifdef HAVE_OPENCL
1197 int cn = channels(), mtype = _mask.type(), mdepth = CV_MAT_DEPTH(mtype), mcn = CV_MAT_CN(mtype);
1198 CV_Assert( mdepth == CV_8U && (mcn == 1 || mcn == cn) );
1199
1200 if (ocl::useOpenCL() && _dst.isUMat() && dims <= 2)
1201 {
1202 UMatData * prevu = _dst.getUMat().u;
1203 _dst.create( dims, size, type: type() );
1204
1205 UMat dst = _dst.getUMat();
1206
1207 bool haveDstUninit = false;
1208 if( prevu != dst.u ) // do not leave dst uninitialized
1209 haveDstUninit = true;
1210
1211 String opts = format(fmt: "-D COPY_TO_MASK -D T1=%s -D scn=%d -D mcn=%d%s",
1212 ocl::memopTypeToStr(t: depth()), cn, mcn,
1213 haveDstUninit ? " -D HAVE_DST_UNINIT" : "");
1214
1215 ocl::Kernel k("copyToMask", ocl::core::copyset_oclsrc, opts);
1216 if (!k.empty())
1217 {
1218 k.args(kernel_args: ocl::KernelArg::ReadOnlyNoSize(m: *this),
1219 kernel_args: ocl::KernelArg::ReadOnlyNoSize(m: _mask.getUMat()),
1220 kernel_args: haveDstUninit ? ocl::KernelArg::WriteOnly(m: dst) :
1221 ocl::KernelArg::ReadWrite(m: dst));
1222
1223 size_t globalsize[2] = { (size_t)cols, (size_t)rows };
1224 if (k.run(dims: 2, globalsize, NULL, sync: false))
1225 {
1226 CV_IMPL_ADD(CV_IMPL_OCL);
1227 return;
1228 }
1229 }
1230 }
1231#endif
1232 Mat src = getMat(accessFlags: ACCESS_READ);
1233 src.copyTo(m: _dst, mask: _mask);
1234}
1235
1236
1237//
1238// void UMat::convertTo moved to convert.dispatch.cpp
1239//
1240
1241UMat& UMat::setTo(InputArray _value, InputArray _mask)
1242{
1243 CV_INSTRUMENT_REGION();
1244
1245 bool haveMask = !_mask.empty();
1246#ifdef HAVE_OPENCL
1247 int tp = type(), cn = CV_MAT_CN(tp), d = CV_MAT_DEPTH(tp);
1248
1249 if( dims <= 2 && cn <= 4 && CV_MAT_DEPTH(tp) < CV_64F && ocl::useOpenCL() )
1250 {
1251 Mat value = _value.getMat();
1252 CV_Assert( checkScalar(value, type(), _value.kind(), _InputArray::UMAT) );
1253 int kercn = haveMask || cn == 3 ? cn : std::max(a: cn, b: ocl::predictOptimalVectorWidth(src1: *this)),
1254 kertp = CV_MAKE_TYPE(d, kercn);
1255
1256 double buf[16] = { 0, 0, 0, 0, 0, 0, 0, 0,
1257 0, 0, 0, 0, 0, 0, 0, 0 };
1258 convertAndUnrollScalar(sc: value, buftype: tp, scbuf: (uchar *)buf, blocksize: kercn / cn);
1259
1260 int scalarcn = kercn == 3 ? 4 : kercn, rowsPerWI = ocl::Device::getDefault().isIntel() ? 4 : 1;
1261 String opts = format(fmt: "-D dstT=%s -D rowsPerWI=%d -D dstST=%s -D dstT1=%s -D cn=%d",
1262 ocl::memopTypeToStr(t: kertp), rowsPerWI,
1263 ocl::memopTypeToStr(CV_MAKETYPE(d, scalarcn)),
1264 ocl::memopTypeToStr(t: d), kercn);
1265
1266 ocl::Kernel setK(haveMask ? "setMask" : "set", ocl::core::copyset_oclsrc, opts);
1267 if( !setK.empty() )
1268 {
1269 ocl::KernelArg scalararg(ocl::KernelArg::CONSTANT, 0, 0, 0, buf, CV_ELEM_SIZE(d) * scalarcn);
1270 UMat mask;
1271
1272 if( haveMask )
1273 {
1274 mask = _mask.getUMat();
1275 CV_Assert( mask.size() == size() && mask.type() == CV_8UC1 );
1276 ocl::KernelArg maskarg = ocl::KernelArg::ReadOnlyNoSize(m: mask),
1277 dstarg = ocl::KernelArg::ReadWrite(m: *this);
1278 setK.args(kernel_args: maskarg, kernel_args: dstarg, kernel_args: scalararg);
1279 }
1280 else
1281 {
1282 ocl::KernelArg dstarg = ocl::KernelArg::WriteOnly(m: *this, wscale: cn, iwscale: kercn);
1283 setK.args(kernel_args: dstarg, kernel_args: scalararg);
1284 }
1285
1286 size_t globalsize[] = { (size_t)cols * cn / kercn, ((size_t)rows + rowsPerWI - 1) / rowsPerWI };
1287 if( setK.run(dims: 2, globalsize, NULL, sync: false) )
1288 {
1289 CV_IMPL_ADD(CV_IMPL_OCL);
1290 return *this;
1291 }
1292 }
1293 }
1294#endif
1295 Mat m = getMat(accessFlags: haveMask ? ACCESS_RW : ACCESS_WRITE);
1296 m.setTo(value: _value, mask: _mask);
1297 return *this;
1298}
1299
1300UMat& UMat::operator = (const Scalar& s)
1301{
1302 setTo(value: s);
1303 return *this;
1304}
1305
1306UMat UMat::t() const
1307{
1308 UMat m;
1309 transpose(src: *this, dst: m);
1310 return m;
1311}
1312
1313UMat UMat::zeros(int rows, int cols, int type, UMatUsageFlags usageFlags)
1314{
1315 return UMat(rows, cols, type, Scalar::all(v0: 0), usageFlags);
1316}
1317
1318UMat UMat::zeros(Size size, int type, UMatUsageFlags usageFlags)
1319{
1320 return UMat(size, type, Scalar::all(v0: 0), usageFlags);
1321}
1322
1323UMat UMat::zeros(int ndims, const int* sz, int type, UMatUsageFlags usageFlags)
1324{
1325 return UMat(ndims, sz, type, Scalar::all(v0: 0), usageFlags);
1326}
1327
1328UMat UMat::ones(int rows, int cols, int type, UMatUsageFlags usageFlags)
1329{
1330 return UMat(rows, cols, type, Scalar(1), usageFlags);
1331}
1332
1333UMat UMat::ones(Size size, int type, UMatUsageFlags usageFlags)
1334{
1335 return UMat(size, type, Scalar(1), usageFlags);
1336}
1337
1338UMat UMat::ones(int ndims, const int* sz, int type, UMatUsageFlags usageFlags)
1339{
1340 return UMat(ndims, sz, type, Scalar(1), usageFlags);
1341}
1342
1343}
1344
1345/* End of file. */
1346

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of opencv/modules/core/src/umatrix.cpp