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

Merge pull request #27318 from Kumataro:fix27298

core: add copyAt() for ROI operation #27318

Close https://github.com/opencv/opencv/issues/27320
Close https://github.com/opencv/opencv/issues/27298

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [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:
Kumataro
2025-11-17 16:58:20 +09:00
committed by GitHub
parent 6d52d416e8
commit 6f74546488
4 changed files with 117 additions and 1 deletions
+29
View File
@@ -1237,8 +1237,13 @@ public:
When the operation mask is specified, if the Mat::create call shown above reallocates the matrix,
the newly allocated matrix is initialized with all zeros before copying the data.
If (re)allocation of destination memory is not necessary (e.g. updating ROI), use copyAt() .
@param m Destination matrix. If it does not have a proper size or type before the operation, it is
reallocated.
@sa copyAt
*/
void copyTo( OutputArray m ) const;
@@ -1250,6 +1255,30 @@ public:
*/
void copyTo( OutputArray m, InputArray mask ) const;
/** @brief Overwrites the existing matrix
This method writes existing matrix data, just like copyTo().
But if it does not have a proper size or type before the operation, an exception is thrown.
This function is helpful to update ROI in an existing matrix.
If (re)allocation of destination memory is necessary, use copyTo() .
@param m Destination matrix.
If it does not have a proper size or type before the operation, an exception is thrown.
@sa copyTo
*/
void copyAt( OutputArray m ) const;
/** @overload
@param m Destination matrix.
If it does not have a proper size or type before the operation, an exception is thrown.
@param mask Operation mask of the same size as \*this. Its non-zero elements indicate which matrix
elements need to be copied. The mask has to be of type CV_8U and can have 1 or multiple channels.
*/
void copyAt( OutputArray m, InputArray mask ) const;
/** @brief Converts an array to another data type with optional scaling.
The method converts source pixel values to the target data type. saturate_cast\<\> is applied at
+22
View File
@@ -615,6 +615,28 @@ void Mat::copyTo( OutputArray _dst, InputArray _mask ) const
copymask(ptrs[0], 0, ptrs[2], 0, ptrs[1], 0, sz, &esz);
}
/* dst = src */
void Mat::copyAt( OutputArray _dst ) const
{
CV_INSTRUMENT_REGION();
Mat dst = _dst.getMat();
CV_CheckTrue( !dst.empty(), "dst must not be empty" );
CV_CheckTypeEQ(type(), dst.type(), "Make the type of dst the same as src");
CV_CheckEQ(size(), dst.size(), "Make the size of dst the same as src");
copyTo(_dst);
}
void Mat::copyAt( OutputArray _dst, InputArray _mask ) const
{
CV_INSTRUMENT_REGION();
Mat dst = _dst.getMat();
CV_CheckTrue( !dst.empty(), "dst must not be empty" );
CV_CheckTypeEQ(type(), dst.type(), "Make the type of dst the same as src");
CV_CheckEQ(size(), dst.size(), "Make the size of dst the same as src");
copyTo(_dst, _mask);
}
static bool can_apply_memset(const Mat &mat, const Scalar &s, int &fill_value)
{
+65
View File
@@ -2713,4 +2713,69 @@ TEST(Mat, Recreate1DMatWithSameMeta)
EXPECT_NO_THROW(m.create(dims, depth));
}
// see https://github.com/opencv/opencv/issues/27298
TEST(Mat, copyAt_regression27298)
{
cv::Mat src(40/*height*/, 30/*width*/, CV_8UC1, Scalar(255));
// Normal
{
cv::Mat dst(100, 100, CV_8UC1, Scalar(0));
cv::Mat roi(dst, cv::Rect(0, 0, 30/*width*/, 40/*height*/));
void* roiData = roi.data;
EXPECT_NO_THROW(src.copyTo(roi));
EXPECT_EQ(roi.data, roiData);
EXPECT_EQ(countNonZero(roi), roi.size().width * roi.size().height) << roi;
}
{
cv::Mat dst(100, 100, CV_8UC1, Scalar(0));
cv::Mat roi(dst, cv::Rect(0, 0, 30/*width*/, 40/*height*/));
void* roiData = roi.data;
EXPECT_NO_THROW(src.copyAt(roi));
EXPECT_EQ(roi.data, roiData);
EXPECT_EQ(countNonZero(roi), roi.size().width * roi.size().height) << roi;
}
// Empty
{
cv::Mat roi; // empty
EXPECT_NO_THROW(src.copyTo(roi));
EXPECT_NE(roi.data, nullptr); // Allocated
EXPECT_EQ(countNonZero(roi), roi.size().width * roi.size().height) << roi;
}
{
cv::Mat roi; // empty
EXPECT_ANY_THROW(src.copyAt(roi));
}
// Different Type
{
cv::Mat dst(100, 100, CV_16UC1, Scalar(0));
cv::Mat roi(dst, cv::Rect(0, 0, 30/*width*/, 40/*height*/));
void* roiData = roi.data;
EXPECT_NO_THROW(src.copyTo(roi));
EXPECT_NE(roi.data, roiData); // Reallocated
EXPECT_EQ(countNonZero(roi), roi.size().width * roi.size().height) << roi;
}
{
cv::Mat dst(100, 100, CV_16UC1, Scalar(0));
cv::Mat roi(dst, cv::Rect(0, 0, 30/*width*/, 40/*height*/));
EXPECT_ANY_THROW(src.copyAt(roi));
}
// Different Size
{
cv::Mat dst(100, 100, CV_8UC1, Scalar(0));
cv::Mat roi(dst, cv::Rect(0, 0, 40/*width*/, 30/*height*/));
void* roiData = roi.data;
EXPECT_NO_THROW(src.copyTo(roi));
EXPECT_NE(roi.data, roiData); // Reallocated
EXPECT_EQ(countNonZero(roi), roi.size().width * roi.size().height) << roi;
}
{
cv::Mat dst(100, 100, CV_8UC1, Scalar(0));
cv::Mat roi(dst, cv::Rect(0, 0, 40/*width*/, 30/*height*/));
EXPECT_ANY_THROW(src.copyAt(roi));
}
}
}} // namespace
+1 -1
View File
@@ -212,7 +212,7 @@ bool GifDecoder::readData(Mat &img) {
if(!restore.empty())
{
Mat roi = Mat(lastImage, cv::Rect(left,top,width,height));
restore.copyTo(roi);
restore.copyAt(roi);
}
return hasRead;