1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-31 08:13:04 +04:00

core: restore in-place support for extractChannel (#29568)

extractChannel() stopped supporting in-place operation (dst aliasing
src) after commit 416bf3253 (PR #23473), which replaced

    Mat src = _src.getMat();
    _dst.create(src.dims, &src.size[0], depth);

with a single up-front

    _dst.createSameSize(_src, depth);
    ...
    Mat src = _src.getMat();

When _src and _dst reference the same array, the up-front reallocation
reshapes the shared buffer to a single channel before the multi-channel
source header is fetched. mixChannels() then sees a 1-channel source and
throws for any coi >= 1.

Move createSameSize() back to after the source Mat/UMat is obtained, so
the source header keeps the original multi-channel data alive across the
destination reallocation. This preserves the 0D/1D handling introduced
by createSameSize while restoring the pre-existing in-place contract.

Adds regression test Core_Mat.extractChannel_inplace_29568.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Arnesh Banerjee
2026-07-30 03:09:43 +05:30
parent a5e4c04903
commit ba5b40b1a2
2 changed files with 16 additions and 1 deletions
+5 -1
View File
@@ -428,11 +428,14 @@ void cv::extractChannel(InputArray _src, OutputArray _dst, int coi)
CV_Assert( 0 <= coi && coi < cn );
int ch[] = { coi, 0 };
_dst.createSameSize(_src, depth);
#ifdef HAVE_OPENCL
if (ocl::isOpenCLActivated() && _src.dims() <= 2 && _dst.isUMat())
{
UMat src = _src.getUMat();
// NB: fetch the source before (re)allocating the destination so that
// in-place operation (_src and _dst referencing the same array) keeps
// the multi-channel source alive while dst is reshaped to 1 channel.
_dst.createSameSize(_src, depth);
UMat dst = _dst.getUMat();
mixChannels(std::vector<UMat>(1, src), std::vector<UMat>(1, dst), ch, 1);
return;
@@ -440,6 +443,7 @@ void cv::extractChannel(InputArray _src, OutputArray _dst, int coi)
#endif
Mat src = _src.getMat();
_dst.createSameSize(_src, depth);
Mat dst = _dst.getMat();
CV_IPP_RUN_FAST(ipp_extractChannel(src, dst, coi))
+11
View File
@@ -1381,6 +1381,17 @@ TEST(Core_Mat, regression_9507)
EXPECT_EQ(25u, m2.total());
}
TEST(Core_Mat, extractChannel_inplace_29568)
{
// https://github.com/opencv/opencv/issues/29568
// extractChannel() must support in-place operation (dst aliasing src).
Mat mat(3, 3, CV_8UC3, Scalar(1, 2, 3));
ASSERT_NO_THROW(cv::extractChannel(mat, mat, 1));
EXPECT_EQ(1, mat.channels());
EXPECT_EQ(Size(3, 3), mat.size());
EXPECT_EQ(0, cv::norm(mat, Mat(3, 3, CV_8UC1, Scalar(2)), NORM_INF));
}
TEST(Core_Mat, empty)
{
// Should not crash.