From ba5b40b1a21ba083fae8270ef6b58eaf4821a7b1 Mon Sep 17 00:00:00 2001 From: Arnesh Banerjee Date: Thu, 30 Jul 2026 03:09:43 +0530 Subject: [PATCH] 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 --- modules/core/src/channels.cpp | 6 +++++- modules/core/test/test_mat.cpp | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/modules/core/src/channels.cpp b/modules/core/src/channels.cpp index bc27918a0f..53f673f7f7 100644 --- a/modules/core/src/channels.cpp +++ b/modules/core/src/channels.cpp @@ -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(1, src), std::vector(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)) diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp index 85aba95097..5400111957 100644 --- a/modules/core/test/test_mat.cpp +++ b/modules/core/test/test_mat.cpp @@ -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.