1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 15:23:05 +04:00

Merge pull request #29082 from vpisarev:fix_input_array_std_vector_5x

fix vector<T> and vector<vector<T>> handling via InputArray/OutputArray
This commit is contained in:
Alexander Smorkalov
2026-05-21 14:22:00 +03:00
committed by GitHub
2 changed files with 231 additions and 176 deletions
+167 -176
View File
@@ -7,6 +7,51 @@
namespace cv {
typedef Vec<int, 5> Vec5i;
typedef Vec<int, 7> Vec7i;
typedef Vec<int, 9> Vec9i;
typedef Vec<int, 10> Vec10i;
typedef Vec<int, 11> Vec11i;
typedef Vec<int, 12> Vec12i;
typedef Vec<int, 13> Vec13i;
typedef Vec<int, 14> Vec14i;
typedef Vec<int, 15> Vec15i;
typedef Vec<int, 16> Vec16i;
typedef Vec<int, 32> Vec32i;
typedef Vec<int, 64> Vec64i;
typedef Vec<int, 128> 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<uchar>& v = *(const std::vector<uchar>*)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<std::vector<uchar> >& vv = *(const std::vector<std::vector<uchar> >*)obj;
CV_Assert( 0 <= i && i < (int)vv.size() );
const std::vector<uchar>& 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<T>* v; \
if (k == STD_VECTOR_VECTOR) { \
std::vector<std::vector<T> >* vv = \
reinterpret_cast<std::vector<std::vector<T> >*>(obj); \
CV_Assert(size_t(i) < vv->size()); \
v = &vv->at(i); \
} else { \
v = reinterpret_cast<std::vector<T>*>(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<Mat>& mv) const
{
const std::vector<uchar>& v = *(const std::vector<uchar>*)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<Mat>& mv) const
if( k == STD_VECTOR_VECTOR )
{
const std::vector<std::vector<uchar> >& vv = *(const std::vector<std::vector<uchar> >*)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<uchar>& 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<std::vector<T > >* vv = (const std::vector<std::vector<T > >*)obj; \
size_t n = vv->size(); \
mv.resize(n); \
for (size_t i = 0; i < n; i++) { \
const std::vector<T >& 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<uchar>& v = *(const std::vector<uchar>*)obj;
const std::vector<int>& iv = *(const std::vector<int>*)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<bool>& v = *(const std::vector<bool>*)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<std::vector<uchar> >& vv = *(const std::vector<std::vector<uchar> >*)obj;
if( i < 0 )
return vv.empty() ? Size() : Size((int)vv.size(), 1);
CV_Assert( i < (int)vv.size() );
const std::vector<std::vector<int> >& ivv = *(const std::vector<std::vector<int> >*)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<const std::vector<std::vector<int> >*>(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<std::vector<uchar> >& vv = *(const std::vector<std::vector<uchar> >*)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<std::vector<T > >* vv = (const std::vector<std::vector<T > >*)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<T >*)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<uchar>& v = *(const std::vector<uchar>*)obj;
return v.empty();
}
if( k == STD_BOOL_VECTOR )
{
const std::vector<bool>& v = *(const std::vector<bool>*)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<std::vector<uchar> >& vv = *(const std::vector<std::vector<uchar> >*)obj;
return vv.empty();
}
if( k == STD_VECTOR_MAT )
{
const std::vector<Mat>& vv = *(const std::vector<Mat>*)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<uchar>* v = (std::vector<uchar>*)obj;
int esz = CV_ELEM_SIZE(flags);
if( k == STD_VECTOR_VECTOR )
if( k == STD_VECTOR || (k == STD_VECTOR_VECTOR && i >= 0) )
{
std::vector<std::vector<uchar> >& vv = *(std::vector<std::vector<uchar> >*)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<T>* v; \
if (k == STD_VECTOR_VECTOR) { \
std::vector<std::vector<T> >* vv = reinterpret_cast<std::vector<std::vector<T> >*>(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<std::vector<T>*>(obj); \
} \
CV_Assert(!fixedSize() || len == v->size()); \
v->resize(len); \
} \
break
int esz = CV_ELEM_SIZE(type0);
CV_Assert(!fixedSize() || len == ((std::vector<uchar>*)v)->size() / esz);
switch( esz )
{
case 1:
((std::vector<uchar>*)v)->resize(len);
break;
case 2:
((std::vector<Vec2b>*)v)->resize(len);
break;
case 3:
((std::vector<Vec3b>*)v)->resize(len);
break;
case 4:
((std::vector<int>*)v)->resize(len);
break;
case 6:
((std::vector<Vec3s>*)v)->resize(len);
break;
case 8:
((std::vector<Vec2i>*)v)->resize(len);
break;
case 12:
((std::vector<Vec3i>*)v)->resize(len);
break;
case 16:
((std::vector<Vec4i>*)v)->resize(len);
break;
case 20:
((std::vector<Vec<int, 5> >*)v)->resize(len);
break;
case 24:
((std::vector<Vec6i>*)v)->resize(len);
break;
case 28:
((std::vector<Vec<int, 7> >*)v)->resize(len);
break;
case 32:
((std::vector<Vec8i>*)v)->resize(len);
break;
case 36:
((std::vector<Vec<int, 9> >*)v)->resize(len);
break;
case 40:
((std::vector<Vec<int, 10> >*)v)->resize(len);
break;
case 44:
((std::vector<Vec<int, 11> >*)v)->resize(len);
break;
case 48:
((std::vector<Vec<int, 12> >*)v)->resize(len);
break;
case 52:
((std::vector<Vec<int, 13> >*)v)->resize(len);
break;
case 56:
((std::vector<Vec<int, 14> >*)v)->resize(len);
break;
case 60:
((std::vector<Vec<int, 15> >*)v)->resize(len);
break;
case 64:
((std::vector<Vec<int, 16> >*)v)->resize(len);
break;
case 128:
((std::vector<Vec<int, 32> >*)v)->resize(len);
break;
case 256:
((std::vector<Vec<int, 64> >*)v)->resize(len);
break;
case 512:
((std::vector<Vec<int, 128> >*)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<std::vector<T> >* vv = \
reinterpret_cast<std::vector<std::vector<T> >*>(obj); \
vv->clear(); \
} else { \
std::vector<T>* v = reinterpret_cast<std::vector<T>*>(obj); \
v->clear(); \
} \
break
if( k == STD_VECTOR_VECTOR )
{
((std::vector<std::vector<uchar> >*)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<bool>*)obj)->clear();
return;
}
if( k == STD_VECTOR_UMAT )
{
((std::vector<UMat>*)obj)->clear();
+64
View File
@@ -2978,4 +2978,68 @@ TEST(Mat, issue_27080)
EXPECT_EQ(cv::norm(src3, src4, NORM_L1), UINT_MAX);
}
template<typename _Tp, int cn> static void make_vector(std::vector<cv::Vec<_Tp, cn> >& 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<Vec3s> vv0_s, vv1_s;
std::vector<std::vector<short> > 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<Vec4d> vv0_d, vv1_d;
std::vector<std::vector<double> > 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<double>(), &cn_d[2][0]);
EXPECT_EQ(0., err2);
}
}} // namespace