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

core: optimize 8UC2 channel extraction

This commit is contained in:
Xi Guo
2026-07-17 20:55:34 +08:00
parent 6f402272e7
commit 1bf1e70c0f
3 changed files with 89 additions and 0 deletions
+24
View File
@@ -30,4 +30,28 @@ PERF_TEST_P( Size_Depth_Channels, split,
SANITY_CHECK(mv, 2e-5);
}
typedef tuple<Size, int> Size_Channel_t;
typedef perf::TestBaseWithParam<Size_Channel_t> Size_Channel;
PERF_TEST_P( Size_Channel, extractChannel,
testing::Combine
(
testing::Values(TYPICAL_MAT_SIZES),
testing::Values(0, 1)
)
)
{
Size sz = get<0>(GetParam());
int channel = get<1>(GetParam());
Mat src(sz, CV_8UC2);
Mat dst(sz, CV_8UC1);
randu(src, 0, 255);
int runs = (sz.width <= 640) ? 8 : 1;
TEST_CYCLE_MULTIRUN(runs) extractChannel(src, dst, channel);
SANITY_CHECK(dst);
}
} // namespace
+38
View File
@@ -418,6 +418,35 @@ static bool ipp_insertChannel(const Mat &src, Mat &dst, int channel)
}
#endif
namespace cv
{
template<int channel> static void extractChannel8uC2_(const Mat& src, Mat& dst)
{
for (int row = 0; row < src.rows; ++row)
{
const uchar* source = src.ptr<uchar>(row);
uchar* destination = dst.ptr<uchar>(row);
int column = 0;
#if (CV_SIMD || CV_SIMD_SCALABLE)
const int lanes = VTraits<v_uint8>::vlanes();
for (; column <= src.cols - lanes; column += lanes)
{
v_uint8 channel0, channel1;
v_load_deinterleave(source + column * 2, channel0, channel1);
v_store(destination + column, channel == 0 ? channel0 : channel1);
}
#endif
for (; column < src.cols; ++column)
destination[column] = source[column * 2 + channel];
}
#if (CV_SIMD || CV_SIMD_SCALABLE)
vx_cleanup();
#endif
}
}
void cv::extractChannel(InputArray _src, OutputArray _dst, int coi)
{
CV_INSTRUMENT_REGION();
@@ -443,6 +472,15 @@ void cv::extractChannel(InputArray _src, OutputArray _dst, int coi)
CV_IPP_RUN_FAST(ipp_extractChannel(src, dst, coi))
if (src.dims <= 2 && src.type() == CV_8UC2)
{
if (coi == 0)
extractChannel8uC2_<0>(src, dst);
else
extractChannel8uC2_<1>(src, dst);
return;
}
mixChannels(&src, 1, &dst, 1, ch, 1);
}
+27
View File
@@ -1602,6 +1602,33 @@ TEST(Core_Arithm, scalar_handling_19599) // https://github.com/opencv/opencv/is
EXPECT_EQ(1, c.rows);
}
TEST(Core_ExtractChannel, twoChannel8uSubmatrix)
{
Mat sourceStorage(5, 37, CV_8UC2);
randu(sourceStorage, 0, 256);
Mat source = sourceStorage(Rect(3, 1, 31, 3));
ASSERT_FALSE(source.isContinuous());
for (int channel = 0; channel < 2; ++channel)
{
Mat destinationStorage(5, 37, CV_8UC1, Scalar::all(0));
Mat destination = destinationStorage(Rect(3, 1, source.cols, source.rows));
Mat expected(source.size(), CV_8UC1);
ASSERT_FALSE(destination.isContinuous());
for (int row = 0; row < source.rows; ++row)
{
const uchar* sourceRow = source.ptr<uchar>(row);
uchar* expectedRow = expected.ptr<uchar>(row);
for (int column = 0; column < source.cols; ++column)
expectedRow[column] = sourceRow[column * 2 + channel];
}
extractChannel(source, destination, channel);
EXPECT_EQ(0, cvtest::norm(expected, destination, NORM_INF));
}
}
// https://github.com/opencv/opencv/issues/24163
typedef tuple<perf::MatDepth,int,int,int> Arith_Regression24163Param;
typedef testing::TestWithParam<Arith_Regression24163Param> Core_Arith_Regression24163;