diff --git a/modules/core/src/matrix_wrap.cpp b/modules/core/src/matrix_wrap.cpp index 32f43a55ec..454464ea7c 100644 --- a/modules/core/src/matrix_wrap.cpp +++ b/modules/core/src/matrix_wrap.cpp @@ -7,6 +7,51 @@ namespace cv { +typedef Vec Vec5i; +typedef Vec Vec7i; +typedef Vec Vec9i; +typedef Vec Vec10i; +typedef Vec Vec11i; +typedef Vec Vec12i; +typedef Vec Vec13i; +typedef Vec Vec14i; +typedef Vec Vec15i; +typedef Vec Vec16i; +typedef Vec Vec32i; +typedef Vec Vec64i; +typedef Vec Vec128i; + +#undef STD_VECTOR_SWITCH +#define STD_VECTOR_SWITCH(esz, func) \ + switch( esz ) \ + { \ + case 1: func(uchar); \ + case 2: func(Vec2b); \ + case 3: func(Vec3b); \ + case 4: func(int); \ + case 6: func(Vec3s); \ + case 8: func(Vec2i); \ + case 12: func(Vec3i); \ + case 16: func(Vec4i); \ + case 20: func(Vec5i); \ + case 24: func(Vec6i); \ + case 28: func(Vec7i); \ + case 32: func(Vec8i); \ + case 36: func(Vec9i); \ + case 40: func(Vec10i); \ + case 44: func(Vec11i); \ + case 48: func(Vec12i); \ + case 52: func(Vec13i); \ + case 56: func(Vec14i); \ + case 60: func(Vec15i); \ + case 64: func(Vec16i); \ + case 128: func(Vec32i); \ + case 256: func(Vec64i); \ + case 512: func(Vec128i); \ + default: \ + CV_Error_(cv::Error::StsBadArg, ("Vectors of vectors with element size %d are not supported. Please, modify STD_VECTOR_SWITCH() macro\n", esz)); \ + } + /*************************************************************************************************\ Input/Output Array \*************************************************************************************************/ @@ -38,16 +83,6 @@ Mat _InputArray::getMat_(int i) const return Mat(sz, flags, obj); } - if( k == STD_VECTOR ) - { - CV_Assert( i < 0 ); - int t = CV_MAT_TYPE(flags); - const std::vector& v = *(const std::vector*)obj; - int v_size = size().width; - - return !v.empty() ? Mat(1, &v_size, t, (void*)&v[0]) : Mat(); - } - if( k == STD_BOOL_VECTOR ) { CV_Assert( i < 0 ); @@ -66,15 +101,28 @@ Mat _InputArray::getMat_(int i) const if( k == NONE ) return Mat(); - if( k == STD_VECTOR_VECTOR ) + if( k == STD_VECTOR || k == STD_VECTOR_VECTOR ) { - int t = type(i); - const std::vector >& vv = *(const std::vector >*)obj; - CV_Assert( 0 <= i && i < (int)vv.size() ); - const std::vector& v = vv[i]; - int v_size = size(i).width; + int t = CV_MAT_TYPE(flags); + int esz = CV_ELEM_SIZE(t); - return !v.empty() ? Mat(1, &v_size, t, (void*)&v[0]) : Mat(); + #undef GET_MAT + #define GET_MAT(T) \ + { \ + std::vector* v; \ + if (k == STD_VECTOR_VECTOR) { \ + std::vector >* vv = \ + reinterpret_cast >*>(obj); \ + CV_Assert(size_t(i) < vv->size()); \ + v = &vv->at(i); \ + } else { \ + v = reinterpret_cast*>(obj); \ + } \ + int v_sz = int(v->size()); \ + return v->empty() ? Mat() : Mat(1, &v_sz, t, v->data()); \ + } + + STD_VECTOR_SWITCH(esz, GET_MAT) } if( k == STD_VECTOR_MAT ) @@ -195,12 +243,12 @@ void _InputArray::getMatVector(std::vector& mv) const { const std::vector& v = *(const std::vector*)obj; - size_t n = size().width, esz = CV_ELEM_SIZE(flags); + size_t n = total(), esz = CV_ELEM_SIZE(flags); int t = CV_MAT_DEPTH(flags), cn = CV_MAT_CN(flags); mv.resize(n); for( size_t i = 0; i < n; i++ ) - mv[i] = Mat(1, cn, t, (void*)(&v[0] + esz*i)); + mv[i] = Mat(1, cn, t, (void*)(v.data() + esz*i)); return; } @@ -212,16 +260,25 @@ void _InputArray::getMatVector(std::vector& mv) const if( k == STD_VECTOR_VECTOR ) { - const std::vector >& vv = *(const std::vector >*)obj; - int n = (int)vv.size(); - int t = CV_MAT_TYPE(flags); - mv.resize(n); + int typ = CV_MAT_TYPE(flags); + int esz = CV_ELEM_SIZE(typ); - for( int i = 0; i < n; i++ ) - { - const std::vector& v = vv[i]; - mv[i] = Mat(size(i), t, (void*)&v[0]); - } + #undef GET_VEC_VEC_MAT_VEC + #define GET_VEC_VEC_MAT_VEC(T) \ + { \ + const std::vector >* vv = (const std::vector >*)obj; \ + size_t n = vv->size(); \ + mv.resize(n); \ + for (size_t i = 0; i < n; i++) { \ + const std::vector& vi = vv->at(i); \ + CV_Assert(vi.size() <= (size_t)INT_MAX); \ + int ni = (int)vi.size(); \ + mv[i] = ni > 0 ? Mat(1, &ni, typ, (void*)vi.data()) : Mat(); \ + } \ + } \ + break + + STD_VECTOR_SWITCH(esz, GET_VEC_VEC_MAT_VEC) return; } @@ -469,35 +526,14 @@ Size _InputArray::size(int i) const return sz; } - if( k == STD_VECTOR ) - { - CV_Assert( i < 0 ); - const std::vector& v = *(const std::vector*)obj; - const std::vector& iv = *(const std::vector*)obj; - size_t szb = v.size(), szi = iv.size(); - return szb == szi ? Size((int)szb, 1) : Size((int)(szb/CV_ELEM_SIZE(flags)), 1); - } - - if( k == STD_BOOL_VECTOR ) - { - CV_Assert( i < 0 ); - const std::vector& v = *(const std::vector*)obj; - return Size((int)v.size(), 1); - } - if( k == NONE ) return Size(); - if( k == STD_VECTOR_VECTOR ) + if( k == STD_VECTOR || k == STD_VECTOR_VECTOR || k == STD_BOOL_VECTOR ) { - const std::vector >& vv = *(const std::vector >*)obj; - if( i < 0 ) - return vv.empty() ? Size() : Size((int)vv.size(), 1); - CV_Assert( i < (int)vv.size() ); - const std::vector >& ivv = *(const std::vector >*)obj; - - size_t szb = vv[i].size(), szi = ivv[i].size(); - return szb == szi ? Size((int)szb, 1) : Size((int)(szb/CV_ELEM_SIZE(flags)), 1); + size_t n = total(i); + CV_Assert(n <= (size_t)INT_MAX); + return Size((int)n, 1); } if( k == STD_VECTOR_MAT ) @@ -658,13 +694,14 @@ int _InputArray::sizend(int* arrsz, int i) const for(j = 0; j < d; j++) arrsz[j] = m.size.p[j]; } - else if (k == STD_VECTOR && i < 0 ) + else if (((k == STD_VECTOR || k == STD_BOOL_VECTOR || k == STD_VECTOR_VECTOR) && i < 0) || + (k == STD_VECTOR_VECTOR && i >= 0)) { - Size sz2d = size(); + size_t n = total(i); d = 1; if(arrsz) { - arrsz[0] = sz2d.width; + arrsz[0] = int(n); } } else @@ -696,10 +733,9 @@ bool _InputArray::empty(int i) const CV_Assert((size_t)i < umv->size()); return umv->at(i).empty(); } - else if (k == STD_VECTOR_VECTOR) { - auto vv = reinterpret_cast >*>(obj); - CV_Assert((size_t)i < vv->size()); - return vv->at(i).empty(); + else if (k == STD_VECTOR || k == STD_BOOL_VECTOR || k == STD_VECTOR_VECTOR) { + size_t n = total(i); + return n == 0; } else { CV_Error(Error::StsNotImplemented, ""); } @@ -829,11 +865,10 @@ int _InputArray::dims(int i) const if( k == STD_VECTOR_VECTOR ) { - const std::vector >& vv = *(const std::vector >*)obj; if( i < 0 ) return 1; - CV_Assert( i < (int)vv.size() ); - return 2; + CV_Assert( size_t(i) < total() ); + return 1; } if( k == STD_VECTOR_MAT ) @@ -953,6 +988,25 @@ size_t _InputArray::total(int i) const } } + if (k == STD_VECTOR || k == STD_VECTOR_VECTOR) + { + CV_Assert(i < 0 || k == STD_VECTOR_VECTOR); + int esz = CV_ELEM_SIZE(flags); + + #undef GET_VEC_SIZE + #define GET_VEC_SIZE(T) \ + if (k == STD_VECTOR_VECTOR) { \ + const std::vector >* vv = (const std::vector >*)obj; \ + size_t n = vv->size(); \ + if (i < 0) \ + return n; \ + CV_Assert((size_t)i < n); \ + return vv->at(i).size(); \ + } else \ + return ((const std::vector*)obj)->size() + + STD_VECTOR_SWITCH(esz, GET_VEC_SIZE) + } return size(i).area(); } @@ -1063,27 +1117,15 @@ bool _InputArray::empty() const if (k == MATX) return false; - if( k == STD_VECTOR ) + if( k == STD_VECTOR || k == STD_BOOL_VECTOR || k == STD_VECTOR_VECTOR ) { - const std::vector& v = *(const std::vector*)obj; - return v.empty(); - } - - if( k == STD_BOOL_VECTOR ) - { - const std::vector& v = *(const std::vector*)obj; - return v.empty(); + size_t n = total(-1); + return n == 0; } if( k == NONE ) return true; - if( k == STD_VECTOR_VECTOR ) - { - const std::vector >& vv = *(const std::vector >*)obj; - return vv.empty(); - } - if( k == STD_VECTOR_MAT ) { const std::vector& vv = *(const std::vector*)obj; @@ -1635,104 +1677,40 @@ void _OutputArray::create(int d, const int* sizes, int mtype, int i, if( k == STD_VECTOR || k == STD_VECTOR_VECTOR ) { + CV_Assert(!fixedSize()); + CV_Assert(k == STD_VECTOR_VECTOR || i < 0); CV_Assert( d <= 2 && (size0 == 1 || size1 == 1 || size0*size1 == 0) ); size_t len = size0*size1 > 0 ? size0 + size1 - 1 : 0; - std::vector* v = (std::vector*)obj; + int esz = CV_ELEM_SIZE(flags); - if( k == STD_VECTOR_VECTOR ) + if( k == STD_VECTOR || (k == STD_VECTOR_VECTOR && i >= 0) ) { - std::vector >& vv = *(std::vector >*)obj; - if( i < 0 ) - { - CV_Assert(!fixedSize() || len == vv.size()); - vv.resize(len); - return; - } - CV_Assert( i < (int)vv.size() ); - v = &vv[i]; + int type0 = CV_MAT_TYPE(flags); + CV_Assert( mtype == type0 || (CV_MAT_CN(mtype) == CV_MAT_CN(type0) && ((1 << type0) & fixedDepthMask) != 0) ); } - else - CV_Assert( i < 0 ); - int type0 = CV_MAT_TYPE(flags); - CV_Assert( mtype == type0 || (CV_MAT_CN(mtype) == CV_MAT_CN(type0) && ((1 << type0) & fixedDepthMask) != 0) ); + #undef RESIZE_VEC + #define RESIZE_VEC(T) \ + { \ + std::vector* v; \ + if (k == STD_VECTOR_VECTOR) { \ + std::vector >* vv = reinterpret_cast >*>(obj); \ + if (i < 0) { \ + CV_Assert(!fixedSize() || len == vv->size()); \ + vv->resize(len); \ + return; \ + } \ + CV_Assert(size_t(i) < vv->size()); \ + v = &vv->at(i); \ + } else { \ + v = reinterpret_cast*>(obj); \ + } \ + CV_Assert(!fixedSize() || len == v->size()); \ + v->resize(len); \ + } \ + break - int esz = CV_ELEM_SIZE(type0); - CV_Assert(!fixedSize() || len == ((std::vector*)v)->size() / esz); - switch( esz ) - { - case 1: - ((std::vector*)v)->resize(len); - break; - case 2: - ((std::vector*)v)->resize(len); - break; - case 3: - ((std::vector*)v)->resize(len); - break; - case 4: - ((std::vector*)v)->resize(len); - break; - case 6: - ((std::vector*)v)->resize(len); - break; - case 8: - ((std::vector*)v)->resize(len); - break; - case 12: - ((std::vector*)v)->resize(len); - break; - case 16: - ((std::vector*)v)->resize(len); - break; - case 20: - ((std::vector >*)v)->resize(len); - break; - case 24: - ((std::vector*)v)->resize(len); - break; - case 28: - ((std::vector >*)v)->resize(len); - break; - case 32: - ((std::vector*)v)->resize(len); - break; - case 36: - ((std::vector >*)v)->resize(len); - break; - case 40: - ((std::vector >*)v)->resize(len); - break; - case 44: - ((std::vector >*)v)->resize(len); - break; - case 48: - ((std::vector >*)v)->resize(len); - break; - case 52: - ((std::vector >*)v)->resize(len); - break; - case 56: - ((std::vector >*)v)->resize(len); - break; - case 60: - ((std::vector >*)v)->resize(len); - break; - case 64: - ((std::vector >*)v)->resize(len); - break; - case 128: - ((std::vector >*)v)->resize(len); - break; - case 256: - ((std::vector >*)v)->resize(len); - break; - case 512: - ((std::vector >*)v)->resize(len); - break; - default: - CV_Error_(cv::Error::StsBadArg, ("Vectors with element size %d are not supported. Please, modify OutputArray::create()\n", esz)); - } + STD_VECTOR_SWITCH(esz, RESIZE_VEC) return; } @@ -2106,15 +2084,22 @@ void _OutputArray::release() const if( k == NONE ) return; - if( k == STD_VECTOR ) + if( k == STD_VECTOR || k == STD_VECTOR_VECTOR ) { - create(Size(), CV_MAT_TYPE(flags)); - return; - } + #undef CLEAR_VEC + #define CLEAR_VEC(T) \ + if (k == STD_VECTOR_VECTOR) { \ + std::vector >* vv = \ + reinterpret_cast >*>(obj); \ + vv->clear(); \ + } else { \ + std::vector* v = reinterpret_cast*>(obj); \ + v->clear(); \ + } \ + break - if( k == STD_VECTOR_VECTOR ) - { - ((std::vector >*)obj)->clear(); + int esz = CV_ELEM_SIZE(flags); + STD_VECTOR_SWITCH(esz, CLEAR_VEC); return; } @@ -2124,6 +2109,12 @@ void _OutputArray::release() const return; } + if( k == STD_BOOL_VECTOR ) + { + ((std::vector*)obj)->clear(); + return; + } + if( k == STD_VECTOR_UMAT ) { ((std::vector*)obj)->clear(); diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp index 470d0130f9..85aba95097 100644 --- a/modules/core/test/test_mat.cpp +++ b/modules/core/test/test_mat.cpp @@ -2978,4 +2978,68 @@ TEST(Mat, issue_27080) EXPECT_EQ(cv::norm(src3, src4, NORM_L1), UINT_MAX); } +template static void make_vector(std::vector >& v, int n) +{ + v.clear(); + v.resize(n); + _Tp* data = &v[0][0]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < cn; j++) { + int k = j % 4; + int val = (k == 0 ? 1 : k == 1 ? -1 : k == 2 ? (i+1) : -(i+1))*(i+1); + data[i*cn + j] = (_Tp)val; + } + } +} + +TEST(Core_InputOutputArray, std_vector_vector) +{ + std::vector vv0_s, vv1_s; + std::vector > cn_s; + make_vector(vv0_s, 100); + + split(vv0_s, cn_s); + merge(cn_s, vv1_s); + + double err0 = cvtest::norm(vv0_s, vv1_s, NORM_INF); + EXPECT_EQ(0, err0); + + _InputArray iarr_s(cn_s); + _OutputArray oarr_s(cn_s); + EXPECT_EQ(3u, iarr_s.total(-1)); + size_t narr = iarr_s.total(-1); + for (size_t i = 0; i < narr; i++) { + EXPECT_EQ(MatShape({int(cn_s[i].size())}), iarr_s.shape(int(i))); + } + size_t newsize_s = vv0_s.size()*2; + oarr_s.create(Size((int)newsize_s, 1), CV_16S, 2); + EXPECT_EQ(newsize_s, cn_s[2].size()); + cn_s[1].clear(); + EXPECT_EQ(true, oarr_s.empty(1)); + + std::vector vv0_d, vv1_d; + std::vector > cn_d; + make_vector(vv0_d, 1000); + + split(vv0_d, cn_d); + merge(cn_d, vv1_d); + + double err1 = cvtest::norm(vv0_d, vv1_d, NORM_INF); + EXPECT_EQ(0., err1); + + _InputArray iarr_d(cn_d); + _OutputArray oarr_d(cn_d); + EXPECT_EQ(4u, iarr_d.total(-1)); + size_t newsize_d = vv0_d.size()*3; + oarr_d.create(Size((int)newsize_d, 1), CV_64F, 3); + EXPECT_EQ(newsize_d, cn_d[3].size()); + cn_d[1].clear(); + EXPECT_EQ(true, oarr_d.empty(1)); + Mat m2 = oarr_d.getMat(2); + + double err2 = cvtest::norm(m2, Mat(cn_d[2]), NORM_INF); + EXPECT_EQ(m2.ptr(), &cn_d[2][0]); + EXPECT_EQ(0., err2); +} + }} // namespace