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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user