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

Merge pull request #27918 from Kumataro:fix26899_5.x

core: support 16 bit LUT for 5.x #27918

Porting from https://github.com/opencv/opencv/pull/27890
Porting from https://github.com/opencv/opencv/pull/27911 

And support new OpenCV5 types for 16 bit LUT.

### 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-10-20 14:30:28 +09:00
committed by GitHub
parent cc400acefe
commit 879218500d
4 changed files with 207 additions and 150 deletions
+96 -52
View File
@@ -3539,11 +3539,12 @@ INSTANTIATE_TEST_CASE_P(
testing::Values(perf::MatDepth(CV_16F), CV_16BF, CV_Bool, CV_64U, CV_64S, CV_32U)
);
CV_ENUM(LutMatType, CV_8U, CV_16U, CV_16F, CV_32S, CV_32F, CV_64F)
CV_ENUM(LutIdxType, CV_8U, CV_8S, CV_16U, CV_16S)
CV_ENUM(LutMatType, CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F, CV_16F, CV_16BF, CV_Bool, CV_64U, CV_64S, CV_32U)
struct Core_LUT: public testing::TestWithParam<LutMatType>
struct Core_LUT: public testing::TestWithParam< std::tuple<LutIdxType, LutMatType> >
{
template<typename T, int ch, bool same_cn>
template<typename Ti, typename T, int ch, bool same_cn>
cv::Mat referenceWithType(cv::Mat input, cv::Mat table)
{
cv::Mat ref(input.size(), CV_MAKE_TYPE(table.depth(), ch));
@@ -3553,7 +3554,7 @@ struct Core_LUT: public testing::TestWithParam<LutMatType>
{
if(ch == 1)
{
ref.at<T>(i, j) = table.at<T>(input.at<uchar>(i, j));
ref.at<T>(i, j) = table.at<T>(input.at<Ti>(i, j));
}
else
{
@@ -3562,11 +3563,11 @@ struct Core_LUT: public testing::TestWithParam<LutMatType>
{
if (same_cn)
{
val[k] = table.at<Vec<T, ch>>(input.at<Vec<uchar, ch>>(i, j)[k])[k];
val[k] = table.at<Vec<T, ch>>(input.at<Vec<Ti, ch>>(i, j)[k])[k];
}
else
{
val[k] = table.at<T>(input.at<Vec<uchar, ch>>(i, j)[k]);
val[k] = table.at<T>(input.at<Vec<Ti, ch>>(i, j)[k]);
}
}
ref.at<Vec<T, ch>>(i, j) = val;
@@ -3579,80 +3580,108 @@ struct Core_LUT: public testing::TestWithParam<LutMatType>
template<int ch = 1, bool same_cn = false>
cv::Mat reference(cv::Mat input, cv::Mat table)
{
if ((table.depth() == CV_8U) || (table.depth() == CV_8S) || (table.depth() == CV_Bool))
cv::Mat ret = cv::Mat();
if ((input.depth() == CV_8U) || (input.depth() == CV_8S)) // Index type for LUT operation
{
return referenceWithType<uchar, ch, same_cn>(input, table);
switch(table.depth()) // Value type for LUT operation
{
case CV_8U: ret = referenceWithType<uint8_t, uint8_t, ch, same_cn>(input, table); break;
case CV_8S: ret = referenceWithType<uint8_t, int8_t, ch, same_cn>(input, table); break;
case CV_16U: ret = referenceWithType<uint8_t, uint16_t, ch, same_cn>(input, table); break;
case CV_16S: ret = referenceWithType<uint8_t, int16_t, ch, same_cn>(input, table); break;
case CV_32S: ret = referenceWithType<uint8_t, int32_t, ch, same_cn>(input, table); break;
case CV_32F: ret = referenceWithType<uint8_t, float, ch, same_cn>(input, table); break;
case CV_64F: ret = referenceWithType<uint8_t, double, ch, same_cn>(input, table); break;
case CV_16F: ret = referenceWithType<uint8_t, uint16_t, ch, same_cn>(input, table); break;
case CV_16BF: ret = referenceWithType<uint8_t, uint16_t, ch, same_cn>(input, table); break;
case CV_Bool: ret = referenceWithType<uint8_t, uint8_t, ch, same_cn>(input, table); break;
case CV_64U: ret = referenceWithType<uint8_t, uint64_t, ch, same_cn>(input, table); break;
case CV_64S: ret = referenceWithType<uint8_t, int64_t, ch, same_cn>(input, table); break;
case CV_32U: ret = referenceWithType<uint8_t, uint32_t, ch, same_cn>(input, table); break;
default: ret = cv::Mat(); break;
}
}
else if ((table.depth() == CV_16U) || (table.depth() == CV_16S))
else if ((input.depth() == CV_16U) || (input.depth() == CV_16S))
{
return referenceWithType<ushort, ch, same_cn>(input, table);
}
else if ((table.depth() == CV_16F) || (table.depth() == CV_16BF))
{
return referenceWithType<ushort, ch, same_cn>(input, table);
}
else if ((table.depth() == CV_32S) || (table.depth() == CV_32U))
{
return referenceWithType<int, ch, same_cn>(input, table);
}
else if ((table.type() == CV_64S) || (table.type() == CV_64U))
{
return referenceWithType<uint64_t, ch, same_cn>(input, table);
}
else if (table.depth() == CV_32F)
{
return referenceWithType<float, ch, same_cn>(input, table);
}
else if (table.depth() == CV_64F)
{
return referenceWithType<double, ch, same_cn>(input, table);
switch(table.depth()) // Value type for LUT operation
{
case CV_8U: ret = referenceWithType<uint16_t, uint8_t, ch, same_cn>(input, table); break;
case CV_8S: ret = referenceWithType<uint16_t, int8_t, ch, same_cn>(input, table); break;
case CV_16U: ret = referenceWithType<uint16_t, uint16_t, ch, same_cn>(input, table); break;
case CV_16S: ret = referenceWithType<uint16_t, int16_t, ch, same_cn>(input, table); break;
case CV_32S: ret = referenceWithType<uint16_t, int32_t, ch, same_cn>(input, table); break;
case CV_32F: ret = referenceWithType<uint16_t, float, ch, same_cn>(input, table); break;
case CV_64F: ret = referenceWithType<uint16_t, double, ch, same_cn>(input, table); break;
case CV_16F: ret = referenceWithType<uint16_t, uint16_t, ch, same_cn>(input, table); break;
case CV_16BF: ret = referenceWithType<uint16_t, uint16_t, ch, same_cn>(input, table); break;
case CV_Bool: ret = referenceWithType<uint16_t, uint8_t, ch, same_cn>(input, table); break;
case CV_64U: ret = referenceWithType<uint16_t, uint64_t, ch, same_cn>(input, table); break;
case CV_64S: ret = referenceWithType<uint16_t, int64_t, ch, same_cn>(input, table); break;
case CV_32U: ret = referenceWithType<uint16_t, uint32_t, ch, same_cn>(input, table); break;
default: ret = cv::Mat(); break;
}
}
return cv::Mat();
return ret;
}
};
TEST_P(Core_LUT, accuracy)
{
int type = GetParam();
cv::Mat input(117, 113, CV_8UC1);
randu(input, 0, 256);
int idx_type = get<0>(GetParam());
int value_type = get<1>(GetParam());
cv::Mat table(1, 256, CV_MAKE_TYPE(type, 1));
randu(table, 0, getMaxVal(type));
ASSERT_TRUE((idx_type == CV_8U) || (idx_type == CV_8S) || (idx_type == CV_16U ) || (idx_type == CV_16S));
const int tableSize = ((idx_type == CV_8U) || (idx_type == CV_8S)) ? 256: 65536;
cv::Mat input(117, 113, CV_MAKE_TYPE(idx_type, 1));
randu(input, getMinVal(idx_type), getMaxVal(idx_type));
cv::Mat table(1, tableSize, CV_MAKE_TYPE(value_type, 1));
randu(table, getMinVal(value_type), getMaxVal(value_type));
cv::Mat output;
cv::LUT(input, table, output);
ASSERT_NO_THROW(cv::LUT(input, table, output));
ASSERT_FALSE(output.empty());
cv::Mat gt = reference(input, table);
ASSERT_FALSE(gt.empty());
// Force convert to 8U as CV_Bool is not supported in cv::norm for now
// TODO: Remove conversion after cv::norm fix
if (type == CV_Bool)
if (value_type == CV_Bool)
{
output.convertTo(output, CV_8U);
gt.convertTo(gt, CV_8U);
}
ASSERT_EQ(0, cv::norm(output, gt, cv::NORM_INF));
}
TEST_P(Core_LUT, accuracy_multi)
{
int type = (int)GetParam();
cv::Mat input(117, 113, CV_8UC3);
randu(input, 0, 256);
int idx_type = get<0>(GetParam());
int value_type = get<1>(GetParam());
cv::Mat table(1, 256, CV_MAKE_TYPE(type, 1));
randu(table, 0, getMaxVal(type));
ASSERT_TRUE((idx_type == CV_8U) || (idx_type == CV_8S) || (idx_type == CV_16U) || (idx_type == CV_16S));
const int tableSize = ((idx_type == CV_8U) || (idx_type == CV_8S) ) ? 256: 65536;
cv::Mat input(117, 113, CV_MAKE_TYPE(idx_type, 3));
randu(input, getMinVal(idx_type), getMaxVal(idx_type));
cv::Mat table(1, tableSize, CV_MAKE_TYPE(value_type, 1));
randu(table, getMinVal(value_type), getMaxVal(value_type));
cv::Mat output;
cv::LUT(input, table, output);
ASSERT_NO_THROW(cv::LUT(input, table, output));
ASSERT_FALSE(output.empty());
cv::Mat gt = reference<3>(input, table);
ASSERT_FALSE(gt.empty());
// Force convert to 8U as CV_Bool is not supported in cv::norm for now
// TODO: Remove conversion after cv::norm fix
if (type == CV_Bool)
if (value_type == CV_Bool)
{
output.convertTo(output, CV_8U);
gt.convertTo(gt, CV_8U);
@@ -3663,22 +3692,37 @@ TEST_P(Core_LUT, accuracy_multi)
TEST_P(Core_LUT, accuracy_multi2)
{
int type = (int)GetParam();
cv::Mat input(117, 113, CV_8UC3);
randu(input, 0, 256);
int idx_type = get<0>(GetParam());
int value_type = get<1>(GetParam());
cv::Mat table(1, 256, CV_MAKE_TYPE(type, 3));
randu(table, 0, getMaxVal(type));
ASSERT_TRUE((idx_type == CV_8U) || (idx_type == CV_8S) || (idx_type == CV_16U) || (idx_type == CV_16S));
const int tableSize = ((idx_type == CV_8U) || (idx_type == CV_8S)) ? 256: 65536;
cv::Mat input(117, 113, CV_MAKE_TYPE(idx_type, 3));
randu(input, getMinVal(idx_type), getMaxVal(idx_type));
cv::Mat table(1, tableSize, CV_MAKE_TYPE(value_type, 3));
randu(table, getMinVal(value_type), getMaxVal(value_type));
cv::Mat output;
cv::LUT(input, table, output);
ASSERT_NO_THROW(cv::LUT(input, table, output));
ASSERT_FALSE(output.empty());
cv::Mat gt = reference<3, true>(input, table);
ASSERT_FALSE(gt.empty());
// Force convert to 8U as CV_Bool is not supported in cv::norm for now
// TODO: Remove conversion after cv::norm fix
if (value_type == CV_Bool)
{
output.convertTo(output, CV_8U);
gt.convertTo(gt, CV_8U);
}
ASSERT_EQ(0, cv::norm(output, gt, cv::NORM_INF));
}
INSTANTIATE_TEST_CASE_P(/**/, Core_LUT, LutMatType::all());
INSTANTIATE_TEST_CASE_P(/**/, Core_LUT, testing::Combine( LutIdxType::all(), LutMatType::all()));
CV_ENUM(MaskType, CV_8U, CV_8S, CV_Bool)
typedef testing::TestWithParam<MaskType> Core_MaskTypeTest;