1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 07:43:03 +04:00

Merge pull request #26254 from vpisarev:extra_tests_for_reshape

Added extra tests for reshape #26254

Attempt to reproduce problems described in #25174. No success; everything works as expected. Probably, the function has been used improperly. Slightly modified the code of Mat::reshape() to provide better diagnostic.

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [x] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
Vadim Pisarevsky
2024-11-01 11:37:56 +03:00
committed by GitHub
parent a95658f106
commit df06d2eac2
4 changed files with 303 additions and 52 deletions
+17 -7
View File
@@ -329,17 +329,25 @@ void Mat::copyTo( OutputArray _dst ) const
}
#endif
int stype = type();
int dtype = _dst.type();
if( _dst.fixedType() && dtype != type() )
if( _dst.fixedType() && dtype != stype )
{
CV_Assert( channels() == CV_MAT_CN(dtype) );
CV_Assert( CV_MAT_CN(stype) == CV_MAT_CN(dtype) );
convertTo( _dst, dtype );
return;
}
if( empty() )
if( dims == 0 && empty() )
{
_dst.release();
void* obj = _dst.getObj();
if (_dst.isMat())
reinterpret_cast<Mat*>(obj)->flags = Mat::MAGIC_VAL | Mat::CONTINUOUS_FLAG | stype;
else if (_dst.isUMat())
reinterpret_cast<UMat*>(obj)->flags = UMat::MAGIC_VAL | UMat::CONTINUOUS_FLAG | stype;
else if (_dst.isGpuMat())
reinterpret_cast<cuda::GpuMat*>(obj)->flags = stype;
return;
}
@@ -348,10 +356,12 @@ void Mat::copyTo( OutputArray _dst ) const
(_dst.fixedSize() && _dst.dims() == 1);
if( _dst.isUMat() )
{
_dst.create( dims, size.p, type(), -1, allowTransposed );
_dst.create( dims, size.p, stype, -1, allowTransposed );
if (empty())
return;
UMat dst = _dst.getUMat();
CV_Assert(dst.u != NULL);
size_t i, sz[CV_MAX_DIM] = {1}, dstofs[CV_MAX_DIM] = {0}, esz = elemSize();
size_t i, sz[CV_MAX_DIM] = {1}, dstofs[CV_MAX_DIM] = {0}, esz = CV_ELEM_SIZE(stype);
CV_Assert(dims >= 0 && dims < CV_MAX_DIM);
for( i = 0; i < (size_t)dims; i++ )
sz[i] = size.p[i];
@@ -365,7 +375,7 @@ void Mat::copyTo( OutputArray _dst ) const
if( dims <= 2 )
{
_dst.create( dims, size.p, type(), -1, allowTransposed );
_dst.create( dims, size.p, stype, -1, allowTransposed );
Mat dst = _dst.getMat();
if( data == dst.data )
return;
@@ -389,7 +399,7 @@ void Mat::copyTo( OutputArray _dst ) const
return;
}
_dst.create( dims, size, type() );
_dst.create( dims, size, stype );
Mat dst = _dst.getMat();
if( data == dst.data )
return;
+32 -25
View File
@@ -1725,27 +1725,26 @@ Mat Mat::reshape(int new_cn, int new_rows) const
int cn = channels();
Mat hdr = *this;
if( new_cn == 0 )
new_cn = cn;
if( dims > 2 )
{
if( new_rows == 0 && new_cn != 0 && size[dims-1]*cn % new_cn == 0 )
if( new_rows == 0 )
{
// special case: just change the number of channnels; retain the same shape,
// except for the last, innermost dimension
CV_Assert(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()*cn/new_rows) };
return reshape(new_cn, 2, sz);
}
CV_Assert( new_rows > 0 );
int sz[] = { new_rows, (int)(total()*cn/new_rows) };
return reshape(new_cn, 2, sz);
}
CV_Assert( dims <= 2 );
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 )
@@ -1758,9 +1757,6 @@ Mat Mat::reshape(int new_cn, int new_rows) const
CV_Error( cv::Error::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::Error::StsOutOfRange, "Bad new number of rows" );
total_width = total_size / new_rows;
if( total_width * new_rows != total_size )
@@ -1810,22 +1806,33 @@ Mat Mat::reshape(int _cn, int _newndims, const int* _newsz) const
AutoBuffer<int, 4> newsz_buf( (size_t)_newndims );
int m1_idx = -1;
for (int i = 0; i < _newndims; i++)
{
CV_Assert(_newsz[i] >= 0);
if (_newsz[i] > 0)
newsz_buf[i] = _newsz[i];
else if (i < dims)
newsz_buf[i] = this->size[i];
else
CV_Error(cv::Error::StsOutOfRange, "Copy dimension (which has zero size) is not present in source matrix");
total_elem1 *= (size_t)newsz_buf[i];
if (_newsz[i] >= 0) {
if (_newsz[i] == 0 && i < dims)
newsz_buf[i] = size.p[i];
else
newsz_buf[i] = _newsz[i];
total_elem1 *= (size_t)newsz_buf[i];
} else {
if (m1_idx >= 0)
CV_Error(cv::Error::StsBadSize, "More than one '-1' occured in the new shape");
m1_idx = i;
}
}
if (total_elem1 != total_elem1_ref)
if (m1_idx >= 0) {
if (total_elem1 == 0) {
CV_Assert(total_elem1_ref == 0);
total_elem1 = 1;
}
CV_Assert(total_elem1_ref % total_elem1 == 0);
newsz_buf[m1_idx] = (int)(total_elem1_ref / total_elem1);
} else if (total_elem1 != total_elem1_ref) {
CV_Error(cv::Error::StsUnmatchedSizes, "Requested and source matrices have different count of elements");
}
Mat hdr = *this;
hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((_cn-1) << CV_CN_SHIFT);
+39 -20
View File
@@ -1063,9 +1063,6 @@ UMat UMat::reshape(int new_cn, int new_rows) const
CV_Error( cv::Error::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::Error::StsOutOfRange, "Bad new number of rows" );
total_width = total_size / new_rows;
if( total_width * new_rows != total_size )
@@ -1127,7 +1124,7 @@ UMat UMat::reshape(int _cn, int _newndims, const int* _newsz) const
if (isContinuous())
{
CV_Assert(_cn >= 0 && _newndims >= 0 && _newndims <= CV_MAX_DIM && _newsz);
CV_Assert(_cn >= 0 && _newndims >= 0 && _newndims <= CV_MAX_DIM && (_newndims == 0 || _newsz != 0));
if (_cn == 0)
_cn = this->channels();
@@ -1139,22 +1136,33 @@ UMat UMat::reshape(int _cn, int _newndims, const int* _newsz) const
AutoBuffer<int, 4> newsz_buf( (size_t)std::max(_newndims, 1) );
int m1_idx = -1;
for (int i = 0; i < _newndims; i++)
{
CV_Assert(_newsz[i] >= 0);
if (_newsz[i] > 0)
newsz_buf[i] = _newsz[i];
else if (i < dims)
newsz_buf[i] = this->size[i];
else
CV_Error(cv::Error::StsOutOfRange, "Copy dimension (which has zero size) is not present in source matrix");
total_elem1 *= (size_t)newsz_buf[i];
if (_newsz[i] >= 0) {
if (_newsz[i] == 0 && i < dims)
newsz_buf[i] = size.p[i];
else
newsz_buf[i] = _newsz[i];
total_elem1 *= (size_t)newsz_buf[i];
} else {
if (m1_idx >= 0)
CV_Error(cv::Error::StsBadSize, "More than one '-1' occured in the new shape");
m1_idx = i;
}
}
if (total_elem1 != total_elem1_ref)
if (m1_idx >= 0) {
if (total_elem1 == 0) {
CV_Assert(total_elem1_ref == 0);
total_elem1 = 1;
}
CV_Assert(total_elem1_ref % total_elem1 == 0);
newsz_buf[m1_idx] = (int)(total_elem1_ref / total_elem1);
} else if (total_elem1 != total_elem1_ref) {
CV_Error(cv::Error::StsUnmatchedSizes, "Requested and source matrices have different count of elements");
}
UMat hdr = *this;
hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((_cn-1) << CV_CN_SHIFT);
@@ -1249,22 +1257,30 @@ void UMat::copyTo(OutputArray _dst) const
}
#endif
int stype = type();
int dtype = _dst.type();
if( _dst.fixedType() && dtype != type() )
if( _dst.fixedType() && dtype != stype )
{
CV_Assert( channels() == CV_MAT_CN(dtype) );
CV_Assert( CV_MAT_CN(stype) == CV_MAT_CN(dtype) );
convertTo( _dst, dtype );
return;
}
if( empty() )
if( dims == 0 && empty() )
{
_dst.release();
void* obj = _dst.getObj();
if (_dst.isMat())
reinterpret_cast<Mat*>(obj)->flags = Mat::MAGIC_VAL | Mat::CONTINUOUS_FLAG | stype;
else if (_dst.isUMat())
reinterpret_cast<UMat*>(obj)->flags = UMat::MAGIC_VAL | UMat::CONTINUOUS_FLAG | stype;
else if (_dst.isGpuMat())
reinterpret_cast<cuda::GpuMat*>(obj)->flags = stype;
return;
}
size_t sz[CV_MAX_DIM] = {1}, srcofs[CV_MAX_DIM]={0}, dstofs[CV_MAX_DIM]={0};
size_t esz = elemSize();
size_t esz = CV_ELEM_SIZE(stype);
int i, d = std::max(dims, 1);
for( i = 0; i < d; i++ )
sz[i] = size.p[i];
@@ -1272,7 +1288,10 @@ void UMat::copyTo(OutputArray _dst) const
ndoffset(srcofs);
srcofs[d-1] *= esz;
_dst.create( dims, size.p, type() );
_dst.create( dims, size.p, stype );
if (empty())
return;
if( _dst.isUMat() )
{
UMat dst = _dst.getUMat();