mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 23:33:05 +04:00
Merge branch 4.x
This commit is contained in:
Vendored
+3
-3
@@ -1,7 +1,7 @@
|
||||
function(download_fastcv root_dir)
|
||||
|
||||
# Commit SHA in the opencv_3rdparty repo
|
||||
set(FASTCV_COMMIT "abe340d0fb7f19fa9315080e3c8616642e98a296")
|
||||
set(FASTCV_COMMIT "2265e79b3b9a8512a9c615b8c4d0244e88f45a9d")
|
||||
|
||||
# Define actual FastCV versions
|
||||
if(ANDROID)
|
||||
@@ -16,8 +16,8 @@ function(download_fastcv root_dir)
|
||||
endif()
|
||||
elseif(UNIX AND NOT APPLE AND NOT IOS AND NOT XROS)
|
||||
if(AARCH64)
|
||||
set(FCV_PACKAGE_NAME "fastcv_linux_aarch64_2025_04_29.tgz")
|
||||
set(FCV_PACKAGE_HASH "e2ce60e25c8e4113a7af2bd243118f4c")
|
||||
set(FCV_PACKAGE_NAME "fastcv_linux_aarch64_2025_05_29.tgz")
|
||||
set(FCV_PACKAGE_HASH "decd490524f786e103125b8b948151f3")
|
||||
else()
|
||||
message("FastCV: fastcv lib for 32-bit Linux is not supported for now!")
|
||||
endif()
|
||||
|
||||
Vendored
+9
-3
@@ -17,9 +17,15 @@ function(download_ippicv root_var)
|
||||
set(OPENCV_ICV_NAME "ippicv_2022.0.0_lnx_intel64_20240904_general.tgz")
|
||||
set(OPENCV_ICV_HASH "63717ee0f918ad72fb5a737992a206d1")
|
||||
else()
|
||||
set(IPPICV_COMMIT "7f55c0c26be418d494615afca15218566775c725")
|
||||
set(OPENCV_ICV_NAME "ippicv_2021.12.0_lnx_ia32_20240425_general.tgz")
|
||||
set(OPENCV_ICV_HASH "85ffa2b9ed7802b93c23fa27b0097d36")
|
||||
if(ANDROID)
|
||||
set(IPPICV_COMMIT "c7c6d527dde5fee7cb914ee9e4e20f7436aab3a1")
|
||||
set(OPENCV_ICV_NAME "ippicv_2021.10.1_lnx_ia32_20231206_general.tgz")
|
||||
set(OPENCV_ICV_HASH "d9510f3ce08f6074aac472a5c19a3b53")
|
||||
else()
|
||||
set(IPPICV_COMMIT "7f55c0c26be418d494615afca15218566775c725")
|
||||
set(OPENCV_ICV_NAME "ippicv_2021.12.0_lnx_ia32_20240425_general.tgz")
|
||||
set(OPENCV_ICV_HASH "85ffa2b9ed7802b93c23fa27b0097d36")
|
||||
endif()
|
||||
endif()
|
||||
elseif(WIN32 AND NOT ARM)
|
||||
set(OPENCV_ICV_PLATFORM "windows")
|
||||
|
||||
@@ -276,6 +276,13 @@
|
||||
publisher = {Walter de Gruyter},
|
||||
url = {https://hal.science/hal-00437581v1}
|
||||
}
|
||||
@misc{Chatfield2017,
|
||||
author = {Chatfield, Carl},
|
||||
title = {A Simple Method for Distance to Ellipse},
|
||||
year = {2017},
|
||||
publisher = {GitHub},
|
||||
howpublished = {\url{https://blog.chatfield.io/simple-method-for-distance-to-ellipse/}},
|
||||
}
|
||||
@article{Chaumette06,
|
||||
author = {Chaumette, Fran{\c c}ois and Hutchinson, S.},
|
||||
title = {{Visual servo control, Part I: Basic approaches}},
|
||||
|
||||
@@ -137,11 +137,12 @@ HAL and Extension list of APIs
|
||||
| | |fcvFilterSobel7x7u8s16 |
|
||||
| |boxFilter |fcvBoxFilter3x3u8_v3 |
|
||||
| | |fcvBoxFilter5x5u8_v2 |
|
||||
| | |fcvBoxFilterNxNf32 |
|
||||
| |adaptiveThreshold |fcvAdaptiveThresholdGaussian3x3u8_v2 |
|
||||
| | |fcvAdaptiveThresholdGaussian5x5u8_v2 |
|
||||
| | |fcvAdaptiveThresholdMean3x3u8_v2 |
|
||||
| | |fcvAdaptiveThresholdMean5x5u8_v2 |
|
||||
| |pyrUp & pyrDown |fcvPyramidCreateu8_v4 |
|
||||
| |pyrDown |fcvPyramidCreateu8_v4 |
|
||||
| |cvtColor |fcvColorRGB888toYCrCbu8_v3 |
|
||||
| | |fcvColorRGB888ToHSV888u8 |
|
||||
| |gaussianBlur |fcvFilterGaussian5x5u8_v3 |
|
||||
@@ -167,10 +168,15 @@ HAL and Extension list of APIs
|
||||
| |addWeighted |fcvAddWeightedu8_v2 |
|
||||
| |subtract |fcvImageDiffu8f32_v2 |
|
||||
| |SVD & solve |fcvSVDf32_v2 |
|
||||
| |gemm |fcvMatrixMultiplyf32_v2 |
|
||||
| | |fcvMultiplyScalarf32 |
|
||||
| | |fcvAddf32_v2 |
|
||||
|
||||
|
||||
**FastCV based OpenCV Extensions APIs list :**
|
||||
|
||||
These OpenCV extension APIs are implemented under the **cv::fastcv** namespace.
|
||||
|
||||
|OpenCV Extension APIs |Underlying FastCV API for OpenCV acceleration |
|
||||
|----------------------|----------------------------------------------|
|
||||
|matmuls8s32 |fcvMatrixMultiplys8s32 |
|
||||
@@ -195,8 +201,10 @@ HAL and Extension list of APIs
|
||||
|remap |fcvRemapu8_v2 |
|
||||
|remapRGBA |fcvRemapRGBA8888BLu8 |
|
||||
| |fcvRemapRGBA8888NNu8 |
|
||||
|resizeDownBy2 |fcvScaleDownBy2u8_v2 |
|
||||
|resizeDownBy4 |fcvScaleDownBy4u8_v2 |
|
||||
|resizeDown |fcvScaleDownBy2u8_v2 |
|
||||
| |fcvScaleDownBy4u8_v2 |
|
||||
| |fcvScaleDownMNInterleaveu8 |
|
||||
| |fcvScaleDownMNu8 |
|
||||
|meanShift |fcvMeanShiftu8 |
|
||||
| |fcvMeanShifts32 |
|
||||
| |fcvMeanShiftf32 |
|
||||
@@ -246,3 +254,65 @@ HAL and Extension list of APIs
|
||||
| |fcvTrackLKOpticalFlowu8 |
|
||||
|warpPerspective2Plane |fcv2PlaneWarpPerspectiveu8 |
|
||||
|warpPerspective |fcvWarpPerspectiveu8_v5 |
|
||||
|arithmetic_op |fcvAddu8 |
|
||||
| |fcvAdds16_v2 |
|
||||
| |fcvAddf32 |
|
||||
| |fcvSubtractu8 |
|
||||
| |fcvSubtracts16 |
|
||||
|integrateYUV |fcvIntegrateImageYCbCr420PseudoPlanaru8 |
|
||||
|normalizeLocalBox |fcvNormalizeLocalBoxu8 |
|
||||
| |fcvNormalizeLocalBoxf32 |
|
||||
|merge |fcvChannelCombine2Planesu8 |
|
||||
| |fcvChannelCombine3Planesu8 |
|
||||
| |fcvChannelCombine4Planesu8 |
|
||||
|split |fcvDeinterleaveu8 |
|
||||
| |fcvChannelExtractu8 |
|
||||
|warpAffine |fcvTransformAffineu8_v2 |
|
||||
| |fcvTransformAffineClippedu8_v3 |
|
||||
| |fcv3ChannelTransformAffineClippedBCu8 |
|
||||
|
||||
|
||||
**FastCV QDSP based OpenCV Extension APIs list :**
|
||||
These OpenCV extension APIs are implemented under the **cv::fastcv::dsp** namespace.
|
||||
This namespace provides optimized implementations that leverage QDSP (**Qualcomm's Digital Signal Processor**) acceleration using FastCV's Q-suffixed APIs. These functions require DSP initialization (fcvQ6Init).
|
||||
|
||||
|OpenCV Extension APIs |Underlying FastCV API for OpenCV acceleration |
|
||||
|----------------------|----------------------------------------------|
|
||||
|filter2D |fcvFilterCorr3x3s8_v2Q |
|
||||
| |fcvFilterCorrNxNu8Q |
|
||||
| |fcvFilterCorrNxNu8s16Q |
|
||||
| |fcvFilterCorrNxNu8f32Q |
|
||||
|FFT |fcvFFTu8Q |
|
||||
|IFFT |fcvIFFTf32Q |
|
||||
|fcvdspinit |fcvQ6Init |
|
||||
|fcvdspdeinit |fcvQ6DeInit |
|
||||
|Canny |fcvFilterCannyu8Q |
|
||||
|sumOfAbsoluteDiffs |fcvSumOfAbsoluteDiffs8x8u8_v2Q |
|
||||
|thresholdOtsu |fcvFilterThresholdOtsuu8Q |
|
||||
|
||||
**How to Use FastCV QDSP based OpenCV Extension APIs**
|
||||
|
||||
This section outlines the essential steps required to use OpenCV Extension APIs that are accelerated using FastCV on QDSP(**Qualcomm's Digital Signal Processor**).
|
||||
|
||||
1. Initialize QDSP:
|
||||
- Call **cv::fastcv::dsp::fcvdspinit()** to initialize the QDSP.
|
||||
|
||||
2. Allocate memory using **Qualcomm's memory allocator** for all buffers that are being fed to the OpenCV extension API.:
|
||||
- Use **cv::fastcv::getQcAllocator()** to assign the allocator to the buffers.
|
||||
- Example:
|
||||
cv::Mat src;
|
||||
src.allocator = cv::fastcv::getQcAllocator(); **// Set Qualcomm's memory allocator**
|
||||
\
|
||||
After setting Qualcomm's memory allocator, any buffer created using methods like src.create(...), cv::imread(...) etc., will have its memory allocated using Qualcomm's memory allocator.
|
||||
|
||||
3. Call the OpenCV extension API from 'cv::fastcv::dsp':
|
||||
- Example: **cv::fastcv::dsp::thresholdOtsu(src, dst, binaryType);**
|
||||
where 'src' and 'dst' are 'cv::Mat' objects with the Qualcomm's memory allocator,
|
||||
and 'binaryType' is a boolean indicating the thresholding mode.
|
||||
|
||||
4. Deinitialize QDSP:
|
||||
- Call **cv::fastcv::dsp::fcvdspdeinit()** to deinitialize the QDSP.
|
||||
|
||||
|
||||
**Reference Example**:
|
||||
Refer to a working test case using the OpenCV Extension APIs in the opencv_contrib repository:[opencv_contrib/modules/fastcv/test/test_thresh_dsp.cpp](https://github.com/opencv/opencv_contrib/blob/4.x/modules/fastcv/test/test_thresh_dsp.cpp)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 560 KiB After Width: | Height: | Size: 535 KiB |
@@ -231,7 +231,7 @@ private:
|
||||
for (int i = 0; i < 8; i++)
|
||||
coeffs[t*8+i] = 0;
|
||||
coeffs[t*8+3] = 1;
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
float sum = 0;
|
||||
|
||||
@@ -344,7 +344,11 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
solvePnPRansac(points, projectedPoints, intrinsics, distCoeffs, rvec, tvec, false, pointsCount, 0.5f, 0.99, inliers, method);
|
||||
bool isEstimateSuccess = solvePnPRansac(points, projectedPoints, intrinsics, distCoeffs, rvec, tvec, false, pointsCount, 0.5f, 0.99, inliers, method);
|
||||
if (!isEstimateSuccess)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isTestSuccess = inliers.size() + numOutliers >= points.size();
|
||||
|
||||
|
||||
@@ -722,7 +722,7 @@ void finalizeHdr(Mat& m)
|
||||
m.rows = m.cols = -1;
|
||||
if(m.u)
|
||||
m.datastart = m.data = m.u->data;
|
||||
if( m.data )
|
||||
if( m.data && d > 0 )
|
||||
{
|
||||
m.datalimit = m.datastart + m.size[0]*m.step[0];
|
||||
if( m.size[0] > 0 )
|
||||
@@ -736,7 +736,7 @@ void finalizeHdr(Mat& m)
|
||||
m.dataend = m.datalimit;
|
||||
}
|
||||
else
|
||||
m.dataend = m.datalimit = 0;
|
||||
m.dataend = m.datalimit = m.data;
|
||||
}
|
||||
|
||||
//======================================= Mat ======================================================
|
||||
|
||||
@@ -1351,6 +1351,25 @@ TEST(Core_Mat, regression_9507)
|
||||
EXPECT_EQ(25u, m2.total());
|
||||
}
|
||||
|
||||
TEST(Core_Mat, empty)
|
||||
{
|
||||
// Should not crash.
|
||||
uint8_t data[2] = {0, 1};
|
||||
cv::Mat mat_nd(/*ndims=*/0, /*sizes=*/nullptr, CV_8UC1, /*data=*/data);
|
||||
cv::Mat1b mat(0, 0, /*data=*/data, /*steps=*/1);
|
||||
EXPECT_EQ(mat_nd.dims, 0);
|
||||
EXPECT_EQ(mat.dims, 2);
|
||||
#if CV_VERSION_MAJOR < 5
|
||||
EXPECT_LE(mat_nd.total(), 0u);
|
||||
EXPECT_TRUE(mat_nd.empty());
|
||||
#else
|
||||
EXPECT_LE(mat_nd.total(), 1u);
|
||||
EXPECT_FALSE(mat_nd.empty());
|
||||
#endif
|
||||
EXPECT_EQ(mat.total(), 0u);
|
||||
EXPECT_TRUE(mat.empty());
|
||||
}
|
||||
|
||||
TEST(Core_InputArray, empty)
|
||||
{
|
||||
vector<vector<Point> > data;
|
||||
|
||||
@@ -115,8 +115,22 @@ if(HAVE_PROTOBUF)
|
||||
|
||||
if(PROTOBUF_UPDATE_FILES)
|
||||
file(GLOB proto_files "${CMAKE_CURRENT_LIST_DIR}/src/tensorflow/*.proto" "${CMAKE_CURRENT_LIST_DIR}/src/caffe/opencv-caffe.proto" "${CMAKE_CURRENT_LIST_DIR}/src/onnx/opencv-onnx.proto")
|
||||
set(PROTOBUF_GENERATE_CPP_APPEND_PATH ON) # required for tensorflow
|
||||
protobuf_generate_cpp(fw_srcs fw_hdrs ${proto_files})
|
||||
if(CMAKE_VERSION VERSION_LESS "3.13.0")
|
||||
set(PROTOBUF_GENERATE_CPP_APPEND_PATH ON) # required for tensorflow
|
||||
protobuf_generate_cpp(fw_srcs fw_hdrs ${proto_files})
|
||||
else()
|
||||
protobuf_generate(
|
||||
APPEND_PATH # required for tensorflow
|
||||
LANGUAGE cpp
|
||||
IMPORT_DIRS ${Protobuf_IMPORT_DIRS}
|
||||
OUT_VAR fw_srcs
|
||||
PROTOC_EXE ${Protobuf_PROTOC_EXECUTABLE}
|
||||
PROTOS ${proto_files})
|
||||
set(fw_hdrs "${fw_srcs}")
|
||||
# separate the header files and source files
|
||||
list(FILTER fw_srcs EXCLUDE REGEX ".+\.h$")
|
||||
list(FILTER fw_hdrs INCLUDE REGEX ".+\.h$")
|
||||
endif()
|
||||
else()
|
||||
file(GLOB fw_srcs "${CMAKE_CURRENT_LIST_DIR}/misc/tensorflow/*.cc" "${CMAKE_CURRENT_LIST_DIR}/misc/caffe/opencv-caffe.pb.cc" "${CMAKE_CURRENT_LIST_DIR}/misc/onnx/opencv-onnx.pb.cc")
|
||||
file(GLOB fw_hdrs "${CMAKE_CURRENT_LIST_DIR}/misc/tensorflow/*.h" "${CMAKE_CURRENT_LIST_DIR}/misc/caffe/opencv-caffe.pb.h" "${CMAKE_CURRENT_LIST_DIR}/misc/onnx/opencv-onnx.pb.h")
|
||||
|
||||
@@ -518,11 +518,34 @@ bool JpegXLEncoder::write(const Mat& img, const std::vector<int>& params)
|
||||
return false;
|
||||
}
|
||||
|
||||
// get distance param for JxlBasicInfo.
|
||||
float distance = -1.0; // Negative means not set
|
||||
for( size_t i = 0; i < params.size(); i += 2 )
|
||||
{
|
||||
if( params[i] == IMWRITE_JPEGXL_QUALITY )
|
||||
{
|
||||
#if JPEGXL_MAJOR_VERSION > 0 || JPEGXL_MINOR_VERSION >= 10
|
||||
int quality = params[i+1];
|
||||
quality = MIN(MAX(quality, 0), 100);
|
||||
distance = JxlEncoderDistanceFromQuality(static_cast<float>(quality));
|
||||
#else
|
||||
CV_LOG_ONCE_WARNING(NULL, "Quality parameter is supported with libjxl v0.10.0 or later");
|
||||
#endif
|
||||
}
|
||||
if( params[i] == IMWRITE_JPEGXL_DISTANCE )
|
||||
{
|
||||
int distanceInt = params[i+1];
|
||||
distanceInt = MIN(MAX(distanceInt, 0), 25);
|
||||
distance = static_cast<float>(distanceInt);
|
||||
}
|
||||
}
|
||||
|
||||
JxlBasicInfo info;
|
||||
JxlEncoderInitBasicInfo(&info);
|
||||
info.xsize = img.cols;
|
||||
info.ysize = img.rows;
|
||||
info.uses_original_profile = JXL_FALSE;
|
||||
// Lossless encoding requires uses_original_profile = true.
|
||||
info.uses_original_profile = (distance == 0.0) ? JXL_TRUE : JXL_FALSE;
|
||||
|
||||
if( img.channels() == 4 )
|
||||
{
|
||||
@@ -576,30 +599,26 @@ bool JpegXLEncoder::write(const Mat& img, const std::vector<int>& params)
|
||||
return false;
|
||||
|
||||
JxlEncoderFrameSettings* frame_settings = JxlEncoderFrameSettingsCreate(encoder.get(), nullptr);
|
||||
|
||||
// set frame settings with distance params
|
||||
if(distance == 0.0) // lossless
|
||||
{
|
||||
if( JXL_ENC_SUCCESS != JxlEncoderSetFrameLossless(frame_settings, JXL_TRUE) )
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "Failed to call JxlEncoderSetFrameLossless()");
|
||||
}
|
||||
}
|
||||
else if(distance > 0.0) // lossy
|
||||
{
|
||||
if( JXL_ENC_SUCCESS != JxlEncoderSetFrameDistance(frame_settings, distance) )
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "Failed to call JxlEncoderSetFrameDistance()");
|
||||
}
|
||||
}
|
||||
|
||||
// set frame settings from params if available
|
||||
for( size_t i = 0; i < params.size(); i += 2 )
|
||||
{
|
||||
if( params[i] == IMWRITE_JPEGXL_QUALITY )
|
||||
{
|
||||
#if JPEGXL_MAJOR_VERSION > 0 || JPEGXL_MINOR_VERSION >= 10
|
||||
int quality = params[i+1];
|
||||
quality = MIN(MAX(quality, 0), 100);
|
||||
const float distance = JxlEncoderDistanceFromQuality(static_cast<float>(quality));
|
||||
JxlEncoderSetFrameDistance(frame_settings, distance);
|
||||
if (distance == 0)
|
||||
JxlEncoderSetFrameLossless(frame_settings, JXL_TRUE);
|
||||
#else
|
||||
CV_LOG_ONCE_WARNING(NULL, "Quality parameter is supported with libjxl v0.10.0 or later");
|
||||
#endif
|
||||
}
|
||||
if( params[i] == IMWRITE_JPEGXL_DISTANCE )
|
||||
{
|
||||
int distance = params[i+1];
|
||||
distance = MIN(MAX(distance, 0), 25);
|
||||
JxlEncoderSetFrameDistance(frame_settings, distance);
|
||||
if (distance == 0)
|
||||
JxlEncoderSetFrameLossless(frame_settings, JXL_TRUE);
|
||||
}
|
||||
if( params[i] == IMWRITE_JPEGXL_EFFORT )
|
||||
{
|
||||
int effort = params[i+1];
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace opencv_test { namespace {
|
||||
|
||||
#ifdef HAVE_JPEGXL
|
||||
|
||||
#include <jxl/version.h> // For JPEGXL_MAJOR_VERSION and JPEGXL_MINOR_VERSION
|
||||
|
||||
typedef tuple<perf::MatType, int> MatType_and_Distance;
|
||||
typedef testing::TestWithParam<MatType_and_Distance> Imgcodecs_JpegXL_MatType;
|
||||
|
||||
@@ -16,8 +18,8 @@ TEST_P(Imgcodecs_JpegXL_MatType, write_read)
|
||||
const int distanceParam = get<1>(GetParam());
|
||||
|
||||
cv::Scalar col;
|
||||
// Jpeg XL is lossy compression.
|
||||
// There may be small differences in decoding results by environments.
|
||||
// Jpeg XL supports lossy and lossless compressions.
|
||||
// Lossy compression may be small differences in decoding results by environments.
|
||||
double th;
|
||||
|
||||
switch( CV_MAT_DEPTH(matType) )
|
||||
@@ -38,7 +40,7 @@ TEST_P(Imgcodecs_JpegXL_MatType, write_read)
|
||||
}
|
||||
|
||||
// If increasing distanceParam, threshold should be increased.
|
||||
th *= (distanceParam >= 25) ? 5 : ( distanceParam > 2 ) ? 3 : (distanceParam == 2) ? 2: 1;
|
||||
th *= (distanceParam >= 25) ? 5 : (distanceParam > 2) ? 3 : distanceParam;
|
||||
|
||||
bool ret = false;
|
||||
string tmp_fname = cv::tempfile(".jxl");
|
||||
@@ -63,8 +65,8 @@ TEST_P(Imgcodecs_JpegXL_MatType, encode_decode)
|
||||
const int distanceParam = get<1>(GetParam());
|
||||
|
||||
cv::Scalar col;
|
||||
// Jpeg XL is lossy compression.
|
||||
// There may be small differences in decoding results by environments.
|
||||
// Jpeg XL supports lossy and lossless compressions.
|
||||
// Lossy compression may be small differences in decoding results by environments.
|
||||
double th;
|
||||
|
||||
// If alpha=0, libjxl modify color channels(BGR). So do not set it.
|
||||
@@ -86,7 +88,7 @@ TEST_P(Imgcodecs_JpegXL_MatType, encode_decode)
|
||||
}
|
||||
|
||||
// If increasing distanceParam, threshold should be increased.
|
||||
th *= (distanceParam >= 25) ? 5 : ( distanceParam > 2 ) ? 3 : (distanceParam == 2) ? 2: 1;
|
||||
th *= (distanceParam >= 25) ? 5 : (distanceParam > 2) ? 3 : distanceParam;
|
||||
|
||||
bool ret = false;
|
||||
vector<uchar> buff;
|
||||
@@ -130,8 +132,8 @@ TEST_P(Imgcodecs_JpegXL_Effort_DecodingSpeed, encode_decode)
|
||||
const int speed = get<1>(GetParam());
|
||||
|
||||
cv::Scalar col = cv::Scalar(124,76,42);
|
||||
// Jpeg XL is lossy compression.
|
||||
// There may be small differences in decoding results by environments.
|
||||
// Jpeg XL supports lossy and lossless compression.
|
||||
// Lossy compression may be small differences in decoding results by environments.
|
||||
double th = 3; // = 255 / 100 (1%);
|
||||
|
||||
bool ret = false;
|
||||
@@ -305,6 +307,56 @@ TEST(Imgcodecs_JpegXL, imread_truncated_stream)
|
||||
remove(tmp_fname.c_str());
|
||||
}
|
||||
|
||||
// See https://github.com/opencv/opencv/issues/27382
|
||||
TEST(Imgcodecs_JpegXL, imencode_regression27382)
|
||||
{
|
||||
cv::Mat image(1024, 1024, CV_16U);
|
||||
cv::RNG rng(1024);
|
||||
rng.fill(image, cv::RNG::NORMAL, 0, 65535);
|
||||
|
||||
std::vector<unsigned char> buffer;
|
||||
std::vector<int> params = {cv::IMWRITE_JPEGXL_DISTANCE, 0}; // lossless
|
||||
|
||||
EXPECT_NO_THROW(cv::imencode(".jxl", image, buffer, params));
|
||||
|
||||
cv::Mat decoded;
|
||||
EXPECT_NO_THROW(decoded = cv::imdecode(buffer, cv::IMREAD_UNCHANGED));
|
||||
EXPECT_FALSE(decoded.empty());
|
||||
|
||||
cv::Mat diff;
|
||||
cv::absdiff(image, decoded, diff);
|
||||
double max_diff = 0.0;
|
||||
cv::minMaxLoc(diff, nullptr, &max_diff);
|
||||
EXPECT_EQ(max_diff, 0 );
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_JpegXL, imencode_regression27382_2)
|
||||
{
|
||||
cv::Mat image(1024, 1024, CV_16U);
|
||||
cv::RNG rng(1024);
|
||||
rng.fill(image, cv::RNG::NORMAL, 0, 65535);
|
||||
|
||||
std::vector<unsigned char> buffer;
|
||||
std::vector<int> params = {cv::IMWRITE_JPEGXL_QUALITY, 100}; // lossless
|
||||
|
||||
EXPECT_NO_THROW(cv::imencode(".jxl", image, buffer, params));
|
||||
|
||||
cv::Mat decoded;
|
||||
EXPECT_NO_THROW(decoded = cv::imdecode(buffer, cv::IMREAD_UNCHANGED));
|
||||
EXPECT_FALSE(decoded.empty());
|
||||
|
||||
cv::Mat diff;
|
||||
cv::absdiff(image, decoded, diff);
|
||||
double max_diff = 0.0;
|
||||
cv::minMaxLoc(diff, nullptr, &max_diff);
|
||||
#if JPEGXL_MAJOR_VERSION > 0 || JPEGXL_MINOR_VERSION >= 10
|
||||
// Quality parameter is supported with libjxl v0.10.0 or later
|
||||
EXPECT_EQ(max_diff, 0); // Lossless
|
||||
#else
|
||||
EXPECT_NE(max_diff, 0); // Lossy
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif // HAVE_JPEGXL
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ This module offers a comprehensive suite of image processing functions, enabling
|
||||
coordinates needs to be retrieved. In the simplest case, the coordinates can be just rounded to the
|
||||
nearest integer coordinates and the corresponding pixel can be used. This is called a
|
||||
nearest-neighbor interpolation. However, a better result can be achieved by using more
|
||||
sophisticated [interpolation methods](http://en.wikipedia.org/wiki/Multivariate_interpolation) ,
|
||||
sophisticated [interpolation methods](https://en.wikipedia.org/wiki/Multivariate_interpolation) ,
|
||||
where a polynomial function is fit into some neighborhood of the computed pixel \f$(f_x(x,y),
|
||||
f_y(x,y))\f$, and then the value of the polynomial at \f$(f_x(x,y), f_y(x,y))\f$ is taken as the
|
||||
interpolated pixel value. In OpenCV, you can choose between several interpolation methods. See
|
||||
@@ -1467,7 +1467,7 @@ CV_EXPORTS_W void getDerivKernels( OutputArray kx, OutputArray ky,
|
||||
/** @brief Returns Gabor filter coefficients.
|
||||
|
||||
For more details about gabor filter equations and parameters, see: [Gabor
|
||||
Filter](http://en.wikipedia.org/wiki/Gabor_filter).
|
||||
Filter](https://en.wikipedia.org/wiki/Gabor_filter).
|
||||
|
||||
@param ksize Size of the filter returned.
|
||||
@param sigma Standard deviation of the gaussian envelope.
|
||||
@@ -1549,7 +1549,7 @@ CV_EXPORTS_W void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
|
||||
/** @brief Applies the bilateral filter to an image.
|
||||
|
||||
The function applies bilateral filtering to the input image, as described in
|
||||
http://www.dai.ed.ac.uk/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html
|
||||
https://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html
|
||||
bilateralFilter can reduce unwanted noise very well while keeping edges fairly sharp. However, it is
|
||||
very slow compared to most filters.
|
||||
|
||||
@@ -1659,7 +1659,7 @@ stackBlur can generate similar results as Gaussian blur, and the time consumptio
|
||||
It creates a kind of moving stack of colors whilst scanning through the image. Thereby it just has to add one new block of color to the right side
|
||||
of the stack and remove the leftmost color. The remaining colors on the topmost layer of the stack are either added on or reduced by one,
|
||||
depending on if they are on the right or on the left side of the stack. The only supported borderType is BORDER_REPLICATE.
|
||||
Original paper was proposed by Mario Klingemann, which can be found http://underdestruction.com/2004/02/25/stackblur-2004.
|
||||
Original paper was proposed by Mario Klingemann, which can be found https://underdestruction.com/2004/02/25/stackblur-2004.
|
||||
|
||||
@param src input image. The number of channels can be arbitrary, but the depth should be one of
|
||||
CV_8U, CV_16U, CV_16S or CV_32F.
|
||||
@@ -1892,7 +1892,7 @@ Check @ref tutorial_canny_detector "the corresponding tutorial" for more details
|
||||
The function finds edges in the input image and marks them in the output map edges using the
|
||||
Canny algorithm. The smallest value between threshold1 and threshold2 is used for edge linking. The
|
||||
largest value is used to find initial segments of strong edges. See
|
||||
<http://en.wikipedia.org/wiki/Canny_edge_detector>
|
||||
<https://en.wikipedia.org/wiki/Canny_edge_detector>
|
||||
|
||||
@param image 8-bit input image.
|
||||
@param edges output edge map; single channels 8-bit image, which has the same size as image .
|
||||
@@ -2168,7 +2168,7 @@ An example using the Hough line detector in python
|
||||
/** @brief Finds lines in a binary image using the standard Hough transform.
|
||||
|
||||
The function implements the standard or standard multi-scale Hough transform algorithm for line
|
||||
detection. See <http://homepages.inf.ed.ac.uk/rbf/HIPR2/hough.htm> for a good explanation of Hough
|
||||
detection. See <https://homepages.inf.ed.ac.uk/rbf/HIPR2/hough.htm> for a good explanation of Hough
|
||||
transform.
|
||||
|
||||
@param image 8-bit, single-channel binary source image. The image may be modified by the function.
|
||||
@@ -2938,13 +2938,13 @@ An example using the phaseCorrelate function
|
||||
|
||||
The operation takes advantage of the Fourier shift theorem for detecting the translational shift in
|
||||
the frequency domain. It can be used for fast image registration as well as motion estimation. For
|
||||
more information please see <http://en.wikipedia.org/wiki/Phase_correlation>
|
||||
more information please see <https://en.wikipedia.org/wiki/Phase_correlation>
|
||||
|
||||
Calculates the cross-power spectrum of two supplied source arrays. The arrays are padded if needed
|
||||
with getOptimalDFTSize.
|
||||
|
||||
The function performs the following equations:
|
||||
- First it applies a Hanning window (see <http://en.wikipedia.org/wiki/Hann_function>) to each
|
||||
- First it applies a Hanning window (see <https://en.wikipedia.org/wiki/Hann_function>) to each
|
||||
image to remove possible edge effects. This window is cached until the array size changes to speed
|
||||
up processing time.
|
||||
- Next it computes the forward DFTs of each source array:
|
||||
@@ -2974,7 +2974,7 @@ CV_EXPORTS_W Point2d phaseCorrelate(InputArray src1, InputArray src2,
|
||||
|
||||
/** @brief This function computes a Hanning window coefficients in two dimensions.
|
||||
|
||||
See (http://en.wikipedia.org/wiki/Hann_function) and (http://en.wikipedia.org/wiki/Window_function)
|
||||
See (https://en.wikipedia.org/wiki/Hann_function) and (https://en.wikipedia.org/wiki/Window_function)
|
||||
for more information.
|
||||
|
||||
An example is shown below:
|
||||
@@ -3462,7 +3462,7 @@ An example using the GrabCut algorithm
|
||||
|
||||
/** @brief Runs the GrabCut algorithm.
|
||||
|
||||
The function implements the [GrabCut image segmentation algorithm](http://en.wikipedia.org/wiki/GrabCut).
|
||||
The function implements the [GrabCut image segmentation algorithm](https://en.wikipedia.org/wiki/GrabCut).
|
||||
|
||||
@param img Input 8-bit 3-channel image.
|
||||
@param mask Input/output 8-bit single-channel mask. The mask is initialized by the function when
|
||||
@@ -3792,7 +3792,7 @@ CV_EXPORTS_W Moments moments( InputArray array, bool binaryImage = false );
|
||||
/** @brief Calculates seven Hu invariants.
|
||||
|
||||
The function calculates seven Hu invariants (introduced in @cite Hu62; see also
|
||||
<http://en.wikipedia.org/wiki/Image_moment>) defined as:
|
||||
<https://en.wikipedia.org/wiki/Image_moment>) defined as:
|
||||
|
||||
\f[\begin{array}{l} hu[0]= \eta _{20}+ \eta _{02} \\ hu[1]=( \eta _{20}- \eta _{02})^{2}+4 \eta _{11}^{2} \\ hu[2]=( \eta _{30}-3 \eta _{12})^{2}+ (3 \eta _{21}- \eta _{03})^{2} \\ hu[3]=( \eta _{30}+ \eta _{12})^{2}+ ( \eta _{21}+ \eta _{03})^{2} \\ hu[4]=( \eta _{30}-3 \eta _{12})( \eta _{30}+ \eta _{12})[( \eta _{30}+ \eta _{12})^{2}-3( \eta _{21}+ \eta _{03})^{2}]+(3 \eta _{21}- \eta _{03})( \eta _{21}+ \eta _{03})[3( \eta _{30}+ \eta _{12})^{2}-( \eta _{21}+ \eta _{03})^{2}] \\ hu[5]=( \eta _{20}- \eta _{02})[( \eta _{30}+ \eta _{12})^{2}- ( \eta _{21}+ \eta _{03})^{2}]+4 \eta _{11}( \eta _{30}+ \eta _{12})( \eta _{21}+ \eta _{03}) \\ hu[6]=(3 \eta _{21}- \eta _{03})( \eta _{21}+ \eta _{03})[3( \eta _{30}+ \eta _{12})^{2}-( \eta _{21}+ \eta _{03})^{2}]-( \eta _{30}-3 \eta _{12})( \eta _{21}+ \eta _{03})[3( \eta _{30}+ \eta _{12})^{2}-( \eta _{21}+ \eta _{03})^{2}] \\ \end{array}\f]
|
||||
|
||||
@@ -4037,7 +4037,7 @@ An example using approxPolyDP function in python.
|
||||
|
||||
The function cv::approxPolyDP approximates a curve or a polygon with another curve/polygon with less
|
||||
vertices so that the distance between them is less or equal to the specified precision. It uses the
|
||||
Douglas-Peucker algorithm <http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm>
|
||||
Douglas-Peucker algorithm <https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm>
|
||||
|
||||
@param curve Input vector of a 2D point stored in std::vector or Mat
|
||||
@param approxCurve Result of the approximation. The type should match the type of the input curve.
|
||||
@@ -4286,6 +4286,9 @@ ellipse/rotatedRect data contains negative indices, due to the data points being
|
||||
border of the containing Mat element.
|
||||
|
||||
@param points Input 2D point set, stored in std::vector\<\> or Mat
|
||||
|
||||
@note Input point types are @ref Point2i or @ref Point2f and at least 5 points are required.
|
||||
@note @ref getClosestEllipsePoints function can be used to compute the ellipse fitting error.
|
||||
*/
|
||||
CV_EXPORTS_W RotatedRect fitEllipse( InputArray points );
|
||||
|
||||
@@ -4323,6 +4326,9 @@ CV_EXPORTS_W RotatedRect fitEllipse( InputArray points );
|
||||
\f}
|
||||
|
||||
@param points Input 2D point set, stored in std::vector\<\> or Mat
|
||||
|
||||
@note Input point types are @ref Point2i or @ref Point2f and at least 5 points are required.
|
||||
@note @ref getClosestEllipsePoints function can be used to compute the ellipse fitting error.
|
||||
*/
|
||||
CV_EXPORTS_W RotatedRect fitEllipseAMS( InputArray points );
|
||||
|
||||
@@ -4368,6 +4374,9 @@ CV_EXPORTS_W RotatedRect fitEllipseAMS( InputArray points );
|
||||
The scaling factor guarantees that \f$A^T C A =1\f$.
|
||||
|
||||
@param points Input 2D point set, stored in std::vector\<\> or Mat
|
||||
|
||||
@note Input point types are @ref Point2i or @ref Point2f and at least 5 points are required.
|
||||
@note @ref getClosestEllipsePoints function can be used to compute the ellipse fitting error.
|
||||
*/
|
||||
CV_EXPORTS_W RotatedRect fitEllipseDirect( InputArray points );
|
||||
|
||||
@@ -4375,6 +4384,20 @@ CV_EXPORTS_W RotatedRect fitEllipseDirect( InputArray points );
|
||||
An example for fitting line in python
|
||||
*/
|
||||
|
||||
/** @brief Compute for each 2d point the nearest 2d point located on a given ellipse.
|
||||
|
||||
The function computes the nearest 2d location on a given ellipse for a vector of 2d points and is based on @cite Chatfield2017 code.
|
||||
This function can be used to compute for instance the ellipse fitting error.
|
||||
|
||||
@param ellipse_params Ellipse parameters
|
||||
@param points Input 2d points
|
||||
@param closest_pts For each 2d point, their corresponding closest 2d point located on a given ellipse
|
||||
|
||||
@note Input point types are @ref Point2i or @ref Point2f
|
||||
@see fitEllipse, fitEllipseAMS, fitEllipseDirect
|
||||
*/
|
||||
CV_EXPORTS_W void getClosestEllipsePoints( const RotatedRect& ellipse_params, InputArray points, OutputArray closest_pts );
|
||||
|
||||
/** @brief Fits a line to a 2D or 3D point set.
|
||||
|
||||
The function fitLine fits a line to a 2D or 3D point set by minimizing \f$\sum_i \rho(r_i)\f$ where
|
||||
@@ -4393,7 +4416,7 @@ of the following:
|
||||
- DIST_HUBER
|
||||
\f[\rho (r) = \fork{r^2/2}{if \(r < C\)}{C \cdot (r-C/2)}{otherwise} \quad \text{where} \quad C=1.345\f]
|
||||
|
||||
The algorithm is based on the M-estimator ( <http://en.wikipedia.org/wiki/M-estimator> ) technique
|
||||
The algorithm is based on the M-estimator ( <https://en.wikipedia.org/wiki/M-estimator> ) technique
|
||||
that iteratively fits the line using the weighted least-squares algorithm. After each iteration the
|
||||
weights \f$w_i\f$ are adjusted to be inversely proportional to \f$\rho(r_i)\f$ .
|
||||
|
||||
|
||||
@@ -21,14 +21,34 @@ void HoughLinesWithAccumulator(
|
||||
InputArray image, OutputArray lines,
|
||||
double rho, double theta, int threshold,
|
||||
double srn = 0, double stn = 0,
|
||||
double min_theta = 0, double max_theta = CV_PI
|
||||
double min_theta = 0, double max_theta = CV_PI,
|
||||
bool use_edgeval = false
|
||||
)
|
||||
{
|
||||
std::vector<Vec3f> lines_acc;
|
||||
HoughLines(image, lines_acc, rho, theta, threshold, srn, stn, min_theta, max_theta);
|
||||
HoughLines(image, lines_acc, rho, theta, threshold, srn, stn, min_theta, max_theta, use_edgeval);
|
||||
Mat(lines_acc).copyTo(lines);
|
||||
}
|
||||
|
||||
/** @brief Finds circles in a grayscale image using the Hough transform and get accumulator.
|
||||
*
|
||||
* @note This function is for bindings use only. Use original function in C++ code
|
||||
*
|
||||
* @sa HoughCircles
|
||||
*/
|
||||
CV_WRAP static inline
|
||||
void HoughCirclesWithAccumulator(
|
||||
InputArray image, OutputArray circles,
|
||||
int method, double dp, double minDist,
|
||||
double param1 = 100, double param2 = 100,
|
||||
int minRadius = 0, int maxRadius = 0
|
||||
)
|
||||
{
|
||||
std::vector<Vec4f> circles_acc;
|
||||
HoughCircles(image, circles_acc, method, dp, minDist, param1, param2, minRadius, maxRadius);
|
||||
Mat(1, static_cast<int>(circles_acc.size()), CV_32FC4, &circles_acc.front()).copyTo(circles);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // OPENCV_IMGPROC_BINDINGS_HPP
|
||||
|
||||
@@ -876,3 +876,120 @@ cv::RotatedRect cv::fitEllipseDirect( InputArray _points )
|
||||
}
|
||||
return box;
|
||||
}
|
||||
|
||||
namespace cv
|
||||
{
|
||||
// @misc{Chatfield2017,
|
||||
// author = {Chatfield, Carl},
|
||||
// title = {A Simple Method for Distance to Ellipse},
|
||||
// year = {2017},
|
||||
// publisher = {GitHub},
|
||||
// howpublished = {\url{https://blog.chatfield.io/simple-method-for-distance-to-ellipse/}},
|
||||
// }
|
||||
// https://github.com/0xfaded/ellipse_demo/blob/master/ellipse_trig_free.py
|
||||
static void solveFast(float semi_major, float semi_minor, const cv::Point2f& pt, cv::Point2f& closest_pt)
|
||||
{
|
||||
float px = std::abs(pt.x);
|
||||
float py = std::abs(pt.y);
|
||||
|
||||
float tx = 0.707f;
|
||||
float ty = 0.707f;
|
||||
|
||||
float a = semi_major;
|
||||
float b = semi_minor;
|
||||
|
||||
for (int iter = 0; iter < 3; iter++)
|
||||
{
|
||||
float x = a * tx;
|
||||
float y = b * ty;
|
||||
|
||||
float ex = (a*a - b*b) * tx*tx*tx / a;
|
||||
float ey = (b*b - a*a) * ty*ty*ty / b;
|
||||
|
||||
float rx = x - ex;
|
||||
float ry = y - ey;
|
||||
|
||||
float qx = px - ex;
|
||||
float qy = py - ey;
|
||||
|
||||
float r = std::hypotf(rx, ry);
|
||||
float q = std::hypotf(qx, qy);
|
||||
|
||||
tx = std::min(1.0f, std::max(0.0f, (qx * r / q + ex) / a));
|
||||
ty = std::min(1.0f, std::max(0.0f, (qy * r / q + ey) / b));
|
||||
float t = std::hypotf(tx, ty);
|
||||
tx /= t;
|
||||
ty /= t;
|
||||
}
|
||||
|
||||
closest_pt.x = std::copysign(a * tx, pt.x);
|
||||
closest_pt.y = std::copysign(b * ty, pt.y);
|
||||
}
|
||||
} // namespace cv
|
||||
|
||||
void cv::getClosestEllipsePoints( const RotatedRect& ellipse_params, InputArray _points, OutputArray closest_pts )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
Mat points = _points.getMat();
|
||||
int n = points.checkVector(2);
|
||||
int depth = points.depth();
|
||||
CV_Assert(depth == CV_32F || depth == CV_32S);
|
||||
CV_Assert(n > 0);
|
||||
|
||||
bool is_float = (depth == CV_32F);
|
||||
const Point* ptsi = points.ptr<Point>();
|
||||
const Point2f* ptsf = points.ptr<Point2f>();
|
||||
|
||||
float semi_major = ellipse_params.size.width / 2.0f;
|
||||
float semi_minor = ellipse_params.size.height / 2.0f;
|
||||
float angle_deg = ellipse_params.angle;
|
||||
if (semi_major < semi_minor)
|
||||
{
|
||||
std::swap(semi_major, semi_minor);
|
||||
angle_deg += 90;
|
||||
}
|
||||
|
||||
Matx23f align_T_ori_f32;
|
||||
float theta_rad = static_cast<float>(angle_deg * M_PI / 180);
|
||||
float co = std::cos(theta_rad);
|
||||
float si = std::sin(theta_rad);
|
||||
float shift_x = ellipse_params.center.x;
|
||||
float shift_y = ellipse_params.center.y;
|
||||
|
||||
align_T_ori_f32(0,0) = co;
|
||||
align_T_ori_f32(0,1) = si;
|
||||
align_T_ori_f32(0,2) = -co*shift_x - si*shift_y;
|
||||
align_T_ori_f32(1,0) = -si;
|
||||
align_T_ori_f32(1,1) = co;
|
||||
align_T_ori_f32(1,2) = si*shift_x - co*shift_y;
|
||||
|
||||
Matx23f ori_T_align_f32;
|
||||
ori_T_align_f32(0,0) = co;
|
||||
ori_T_align_f32(0,1) = -si;
|
||||
ori_T_align_f32(0,2) = shift_x;
|
||||
ori_T_align_f32(1,0) = si;
|
||||
ori_T_align_f32(1,1) = co;
|
||||
ori_T_align_f32(1,2) = shift_y;
|
||||
|
||||
std::vector<Point2f> closest_pts_list;
|
||||
closest_pts_list.reserve(n);
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
Point2f p = is_float ? ptsf[i] : Point2f((float)ptsi[i].x, (float)ptsi[i].y);
|
||||
Matx31f pmat(p.x, p.y, 1);
|
||||
|
||||
Matx21f X_align = align_T_ori_f32 * pmat;
|
||||
Point2f closest_pt;
|
||||
solveFast(semi_major, semi_minor, Point2f(X_align(0,0), X_align(1,0)), closest_pt);
|
||||
|
||||
pmat(0,0) = closest_pt.x;
|
||||
pmat(1,0) = closest_pt.y;
|
||||
Matx21f closest_pt_ori = ori_T_align_f32 * pmat;
|
||||
closest_pts_list.push_back(Point2f(closest_pt_ori(0,0), closest_pt_ori(1,0)));
|
||||
}
|
||||
|
||||
cv::Mat(closest_pts_list).convertTo(closest_pts, CV_32F);
|
||||
}
|
||||
|
||||
/* End of file. */
|
||||
|
||||
@@ -493,7 +493,7 @@ void Subdiv2D::initDelaunay( Rect rect )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
float big_coord = 3.f * MAX( rect.width, rect.height );
|
||||
float big_coord = 6.f * MAX( rect.width, rect.height );
|
||||
float rx = (float)rect.x;
|
||||
float ry = (float)rect.y;
|
||||
|
||||
|
||||
@@ -500,10 +500,10 @@ PARAM_TEST_CASE(RemapRelative, MatDepth, Channels, Interpolation, BorderType, bo
|
||||
data64FC1.reshape(nChannels, size.height).convertTo(src, srcType);
|
||||
|
||||
cv::Mat mapRelativeX32F(size, CV_32FC1);
|
||||
mapRelativeX32F.setTo(cv::Scalar::all(-0.33));
|
||||
mapRelativeX32F.setTo(cv::Scalar::all(-0.25));
|
||||
|
||||
cv::Mat mapRelativeY32F(size, CV_32FC1);
|
||||
mapRelativeY32F.setTo(cv::Scalar::all(-0.33));
|
||||
mapRelativeY32F.setTo(cv::Scalar::all(-0.25));
|
||||
|
||||
cv::Mat mapAbsoluteX32F = mapRelativeX32F.clone();
|
||||
mapAbsoluteX32F.forEach<float>([&](float& pixel, const int* position) {
|
||||
|
||||
@@ -69,6 +69,8 @@ TEST(Imgproc_CornerSubPix, out_of_image_corners)
|
||||
TEST(Imgproc_CornerSubPix, corners_on_the_edge)
|
||||
{
|
||||
cv::Mat image(500, 500, CV_8UC1);
|
||||
RNG& rng = TS::ptr()->get_rng();
|
||||
cvtest::randUni(rng, image, 0, 255);
|
||||
cv::Size win(1, 1);
|
||||
cv::Size zeroZone(-1, -1);
|
||||
cv::TermCriteria criteria;
|
||||
|
||||
@@ -113,4 +113,197 @@ TEST(Imgproc_FitEllipse_HorizontalLine, accuracy) {
|
||||
EXPECT_NEAR(el.angle, 90, 0.1);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static float get_ellipse_fitting_error(const std::vector<T>& points, const Mat& closest_points) {
|
||||
float mse = 0.0f;
|
||||
for (int i = 0; i < static_cast<int>(points.size()); i++)
|
||||
{
|
||||
Point2f pt_err = Point2f(static_cast<float>(points[i].x), static_cast<float>(points[i].y)) - closest_points.at<Point2f>(i);
|
||||
mse += pt_err.x*pt_err.x + pt_err.y*pt_err.y;
|
||||
}
|
||||
return mse / points.size();
|
||||
}
|
||||
|
||||
TEST(Imgproc_getClosestEllipsePoints, ellipse_mse) {
|
||||
// https://github.com/opencv/opencv/issues/26078
|
||||
std::vector<Point2i> points_list;
|
||||
|
||||
// [1434, 308], [1434, 309], [1433, 310], [1427, 310], [1427, 312], [1426, 313], [1422, 313], [1422, 314],
|
||||
points_list.push_back(Point2i(1434, 308));
|
||||
points_list.push_back(Point2i(1434, 309));
|
||||
points_list.push_back(Point2i(1433, 310));
|
||||
points_list.push_back(Point2i(1427, 310));
|
||||
points_list.push_back(Point2i(1427, 312));
|
||||
points_list.push_back(Point2i(1426, 313));
|
||||
points_list.push_back(Point2i(1422, 313));
|
||||
points_list.push_back(Point2i(1422, 314));
|
||||
|
||||
// [1421, 315], [1415, 315], [1415, 316], [1414, 317], [1408, 317], [1408, 319], [1407, 320], [1403, 320],
|
||||
points_list.push_back(Point2i(1421, 315));
|
||||
points_list.push_back(Point2i(1415, 315));
|
||||
points_list.push_back(Point2i(1415, 316));
|
||||
points_list.push_back(Point2i(1414, 317));
|
||||
points_list.push_back(Point2i(1408, 317));
|
||||
points_list.push_back(Point2i(1408, 319));
|
||||
points_list.push_back(Point2i(1407, 320));
|
||||
points_list.push_back(Point2i(1403, 320));
|
||||
|
||||
// [1403, 321], [1402, 322], [1396, 322], [1396, 323], [1395, 324], [1389, 324], [1389, 326], [1388, 327],
|
||||
points_list.push_back(Point2i(1403, 321));
|
||||
points_list.push_back(Point2i(1402, 322));
|
||||
points_list.push_back(Point2i(1396, 322));
|
||||
points_list.push_back(Point2i(1396, 323));
|
||||
points_list.push_back(Point2i(1395, 324));
|
||||
points_list.push_back(Point2i(1389, 324));
|
||||
points_list.push_back(Point2i(1389, 326));
|
||||
points_list.push_back(Point2i(1388, 327));
|
||||
|
||||
// [1382, 327], [1382, 328], [1381, 329], [1376, 329], [1376, 330], [1375, 331], [1369, 331], [1369, 333],
|
||||
points_list.push_back(Point2i(1382, 327));
|
||||
points_list.push_back(Point2i(1382, 328));
|
||||
points_list.push_back(Point2i(1381, 329));
|
||||
points_list.push_back(Point2i(1376, 329));
|
||||
points_list.push_back(Point2i(1376, 330));
|
||||
points_list.push_back(Point2i(1375, 331));
|
||||
points_list.push_back(Point2i(1369, 331));
|
||||
points_list.push_back(Point2i(1369, 333));
|
||||
|
||||
// [1368, 334], [1362, 334], [1362, 335], [1361, 336], [1359, 336], [1359, 1016], [1365, 1016], [1366, 1017],
|
||||
points_list.push_back(Point2i(1368, 334));
|
||||
points_list.push_back(Point2i(1362, 334));
|
||||
points_list.push_back(Point2i(1362, 335));
|
||||
points_list.push_back(Point2i(1361, 336));
|
||||
points_list.push_back(Point2i(1359, 336));
|
||||
points_list.push_back(Point2i(1359, 1016));
|
||||
points_list.push_back(Point2i(1365, 1016));
|
||||
points_list.push_back(Point2i(1366, 1017));
|
||||
|
||||
// [1366, 1019], [1430, 1019], [1430, 1017], [1431, 1016], [1440, 1016], [1440, 308]
|
||||
points_list.push_back(Point2i(1366, 1019));
|
||||
points_list.push_back(Point2i(1430, 1019));
|
||||
points_list.push_back(Point2i(1430, 1017));
|
||||
points_list.push_back(Point2i(1431, 1016));
|
||||
points_list.push_back(Point2i(1440, 1016));
|
||||
points_list.push_back(Point2i(1440, 308));
|
||||
|
||||
RotatedRect fit_ellipse_params(
|
||||
Point2f(1442.97900390625, 662.1879272460938),
|
||||
Size2f(579.5570678710938, 730.834228515625),
|
||||
20.190902709960938
|
||||
);
|
||||
|
||||
// Point2i
|
||||
{
|
||||
Mat pointsi(points_list);
|
||||
Mat closest_pts;
|
||||
getClosestEllipsePoints(fit_ellipse_params, pointsi, closest_pts);
|
||||
EXPECT_TRUE(pointsi.rows == closest_pts.rows);
|
||||
EXPECT_TRUE(pointsi.cols == closest_pts.cols);
|
||||
EXPECT_TRUE(pointsi.channels() == closest_pts.channels());
|
||||
|
||||
float fit_ellipse_mse = get_ellipse_fitting_error(points_list, closest_pts);
|
||||
EXPECT_NEAR(fit_ellipse_mse, 1.61994, 1e-4);
|
||||
}
|
||||
|
||||
// Point2f
|
||||
{
|
||||
Mat pointsf;
|
||||
Mat(points_list).convertTo(pointsf, CV_32F);
|
||||
|
||||
Mat closest_pts;
|
||||
getClosestEllipsePoints(fit_ellipse_params, pointsf, closest_pts);
|
||||
EXPECT_TRUE(pointsf.rows == closest_pts.rows);
|
||||
EXPECT_TRUE(pointsf.cols == closest_pts.cols);
|
||||
EXPECT_TRUE(pointsf.channels() == closest_pts.channels());
|
||||
|
||||
float fit_ellipse_mse = get_ellipse_fitting_error(points_list, closest_pts);
|
||||
EXPECT_NEAR(fit_ellipse_mse, 1.61994, 1e-4);
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<Point2f> sample_ellipse_pts(const RotatedRect& ellipse_params) {
|
||||
// Sample N points using the ellipse parametric form
|
||||
float xc = ellipse_params.center.x;
|
||||
float yc = ellipse_params.center.y;
|
||||
float a = ellipse_params.size.width / 2;
|
||||
float b = ellipse_params.size.height / 2;
|
||||
float theta = static_cast<float>(ellipse_params.angle * M_PI / 180);
|
||||
|
||||
float cos_th = std::cos(theta);
|
||||
float sin_th = std::sin(theta);
|
||||
int nb_samples = 180;
|
||||
std::vector<Point2f> ellipse_pts(nb_samples);
|
||||
for (int i = 0; i < nb_samples; i++) {
|
||||
float ax = a * cos_th;
|
||||
float ay = a * sin_th;
|
||||
float bx = -b * sin_th;
|
||||
float by = b * cos_th;
|
||||
|
||||
float t = static_cast<float>(i / static_cast<float>(nb_samples) * 2*M_PI);
|
||||
float cos_t = std::cos(t);
|
||||
float sin_t = std::sin(t);
|
||||
|
||||
ellipse_pts[i].x = xc + ax*cos_t + bx*sin_t;
|
||||
ellipse_pts[i].y = yc + ay*cos_t + by*sin_t;
|
||||
}
|
||||
|
||||
return ellipse_pts;
|
||||
}
|
||||
|
||||
TEST(Imgproc_getClosestEllipsePoints, ellipse_mse_2) {
|
||||
const float tol = 1e-3f;
|
||||
|
||||
// bb height > width
|
||||
// Check correctness of the minor/major axes swapping and updated angle in getClosestEllipsePoints
|
||||
{
|
||||
RotatedRect ellipse_params(
|
||||
Point2f(-142.97f, -662.1878f),
|
||||
Size2f(539.557f, 730.83f),
|
||||
27.09960938f
|
||||
);
|
||||
std::vector<Point2f> ellipse_pts = sample_ellipse_pts(ellipse_params);
|
||||
|
||||
Mat pointsf, closest_pts;
|
||||
Mat(ellipse_pts).convertTo(pointsf, CV_32F);
|
||||
getClosestEllipsePoints(ellipse_params, pointsf, closest_pts);
|
||||
|
||||
float ellipse_pts_mse = get_ellipse_fitting_error(ellipse_pts, closest_pts);
|
||||
EXPECT_NEAR(ellipse_pts_mse, 0, tol);
|
||||
}
|
||||
|
||||
// bb height > width + negative angle
|
||||
{
|
||||
RotatedRect ellipse_params(
|
||||
Point2f(-142.97f, 562.1878f),
|
||||
Size2f(53.557f, 730.83f),
|
||||
-75.09960938f
|
||||
);
|
||||
std::vector<Point2f> ellipse_pts = sample_ellipse_pts(ellipse_params);
|
||||
|
||||
Mat pointsf, closest_pts;
|
||||
Mat(ellipse_pts).convertTo(pointsf, CV_32F);
|
||||
getClosestEllipsePoints(ellipse_params, pointsf, closest_pts);
|
||||
|
||||
float ellipse_pts_mse = get_ellipse_fitting_error(ellipse_pts, closest_pts);
|
||||
EXPECT_NEAR(ellipse_pts_mse, 0, tol);
|
||||
}
|
||||
|
||||
// Negative angle
|
||||
{
|
||||
RotatedRect ellipse_params(
|
||||
Point2f(742.97f, -462.1878f),
|
||||
Size2f(535.57f, 130.83f),
|
||||
-75.09960938f
|
||||
);
|
||||
std::vector<Point2f> ellipse_pts = sample_ellipse_pts(ellipse_params);
|
||||
|
||||
Mat pointsf, closest_pts;
|
||||
Mat(ellipse_pts).convertTo(pointsf, CV_32F);
|
||||
getClosestEllipsePoints(ellipse_params, pointsf, closest_pts);
|
||||
|
||||
float ellipse_pts_mse = get_ellipse_fitting_error(ellipse_pts, closest_pts);
|
||||
EXPECT_NEAR(ellipse_pts_mse, 0, tol);
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -772,10 +772,10 @@ TEST_P(Imgproc_RemapRelative, validity)
|
||||
data64FC1.reshape(nChannels, size.height).convertTo(src, srcType);
|
||||
|
||||
cv::Mat mapRelativeX32F(size, CV_32FC1);
|
||||
mapRelativeX32F.setTo(cv::Scalar::all(-0.33));
|
||||
mapRelativeX32F.setTo(cv::Scalar::all(-0.25));
|
||||
|
||||
cv::Mat mapRelativeY32F(size, CV_32FC1);
|
||||
mapRelativeY32F.setTo(cv::Scalar::all(-0.33));
|
||||
mapRelativeY32F.setTo(cv::Scalar::all(-0.25));
|
||||
|
||||
cv::Mat mapAbsoluteX32F = mapRelativeX32F.clone();
|
||||
mapAbsoluteX32F.forEach<float>([&](float& pixel, const int* position) {
|
||||
@@ -811,7 +811,7 @@ TEST_P(Imgproc_RemapRelative, validity)
|
||||
cv::remap(src, dstRelative, mapRelativeX32F, mapRelativeY32F, interpolation | WARP_RELATIVE_MAP, borderType);
|
||||
}
|
||||
|
||||
EXPECT_EQ(cvtest::norm(dstAbsolute, dstRelative, NORM_INF), 0);
|
||||
EXPECT_LE(cvtest::norm(dstAbsolute, dstRelative, NORM_INF), 1);
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ImgProc, Imgproc_RemapRelative, testing::Combine(
|
||||
|
||||
@@ -50,4 +50,18 @@ TEST(Imgproc_Subdiv2D_getTriangleList, regression_5788)
|
||||
EXPECT_EQ(trig_cnt, 105);
|
||||
}
|
||||
|
||||
TEST(Imgproc_Subdiv2D, issue_25696) {
|
||||
std::vector<cv::Point2f> points{
|
||||
{0, 0}, {40, 40}, {84, 104}, {86, 108}
|
||||
};
|
||||
|
||||
cv::Rect subdivRect{cv::Point{-10, -10}, cv::Point{96, 118}};
|
||||
cv::Subdiv2D subdiv{subdivRect};
|
||||
subdiv.insert(points);
|
||||
|
||||
std::vector<cv::Vec6f> triangles;
|
||||
subdiv.getTriangleList(triangles);
|
||||
|
||||
ASSERT_EQ(static_cast<size_t>(2), triangles.size());
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -96,8 +96,10 @@ public class JavaCamera2View extends CameraBridgeViewBase {
|
||||
Log.e(LOGTAG, "Error: camera isn't detected.");
|
||||
return false;
|
||||
}
|
||||
boolean chosen = false; // remember whether the camera ID is set.
|
||||
if (mCameraIndex == CameraBridgeViewBase.CAMERA_ID_ANY) {
|
||||
mCameraID = camList[0];
|
||||
chosen = true;
|
||||
} else {
|
||||
for (String cameraID : camList) {
|
||||
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraID);
|
||||
@@ -107,11 +109,12 @@ public class JavaCamera2View extends CameraBridgeViewBase {
|
||||
characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT)
|
||||
) {
|
||||
mCameraID = cameraID;
|
||||
chosen = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mCameraID == null) { // make JavaCamera2View behaves in the same way as JavaCameraView
|
||||
if (mCameraID == null || !chosen) { // make JavaCamera2View behaves in the same way as JavaCameraView
|
||||
Log.i(LOGTAG, "Selecting camera by index (" + mCameraIndex + ")");
|
||||
if (mCameraIndex < camList.length) {
|
||||
mCameraID = camList[mCameraIndex];
|
||||
|
||||
@@ -65,10 +65,14 @@ Mat triangleWeights()
|
||||
Mat w(LDR_SIZE, 1, CV_32F);
|
||||
int half = LDR_SIZE / 2;
|
||||
int maxVal = LDR_SIZE - 1;
|
||||
for (int i = 0; i < LDR_SIZE; i++)
|
||||
float epsilon = 1e-6f;
|
||||
w.at<float>(0) = epsilon;
|
||||
w.at<float>(LDR_SIZE-1) = epsilon;
|
||||
for (int i = 1; i < LDR_SIZE-1; i++){
|
||||
w.at<float>(i) = (i < half)
|
||||
? static_cast<float>(i)
|
||||
: static_cast<float>(maxVal - i);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,8 +72,10 @@ public:
|
||||
|
||||
double min, max;
|
||||
minMaxLoc(src, &min, &max);
|
||||
float fmin = static_cast<float>(min);
|
||||
float fmax = static_cast<float>(max);
|
||||
if(max - min > DBL_EPSILON) {
|
||||
dst = (src - min) / (max - min);
|
||||
dst = (src - fmin) / (fmax - fmin);
|
||||
} else {
|
||||
src.copyTo(dst);
|
||||
}
|
||||
@@ -139,8 +141,9 @@ public:
|
||||
gray_img /= mean;
|
||||
log_img.release();
|
||||
|
||||
double max;
|
||||
minMaxLoc(gray_img, NULL, &max);
|
||||
double dmax;
|
||||
minMaxLoc(gray_img, NULL, &dmax);
|
||||
float max = static_cast<float>(dmax);
|
||||
CV_Assert(max > 0);
|
||||
|
||||
Mat map;
|
||||
@@ -150,7 +153,6 @@ public:
|
||||
log(2.0f + 8.0f * div, div);
|
||||
map = map.mul(1.0f / div);
|
||||
div.release();
|
||||
|
||||
mapLuminance(img, img, gray_img, map, saturation);
|
||||
|
||||
linear->setGamma(gamma);
|
||||
@@ -223,12 +225,14 @@ public:
|
||||
log_(gray_img, log_img);
|
||||
|
||||
float log_mean = static_cast<float>(sum(log_img)[0] / log_img.total());
|
||||
double log_min, log_max;
|
||||
minMaxLoc(log_img, &log_min, &log_max);
|
||||
double dlog_min, dlog_max;
|
||||
minMaxLoc(log_img, &dlog_min, &dlog_max);
|
||||
float log_max = static_cast<float>(dlog_max);
|
||||
float log_min = static_cast<float>(dlog_min);
|
||||
log_img.release();
|
||||
|
||||
double key = static_cast<float>((log_max - log_mean) / (log_max - log_min));
|
||||
float map_key = 0.3f + 0.7f * pow(static_cast<float>(key), 1.4f);
|
||||
float key = (log_max - log_mean) / (log_max - log_min);
|
||||
float map_key = 0.3f + 0.7f * pow(key, 1.4f);
|
||||
intensity = exp(-intensity);
|
||||
Scalar chan_mean = mean(img);
|
||||
float gray_mean = static_cast<float>(mean(gray_img)[0]);
|
||||
@@ -287,9 +291,9 @@ protected:
|
||||
float gamma, intensity, light_adapt, color_adapt;
|
||||
};
|
||||
|
||||
Ptr<TonemapReinhard> createTonemapReinhard(float gamma, float contrast, float sigma_color, float sigma_space)
|
||||
Ptr<TonemapReinhard> createTonemapReinhard(float gamma, float intensity, float light_adapt, float color_adapt)
|
||||
{
|
||||
return makePtr<TonemapReinhardImpl>(gamma, contrast, sigma_color, sigma_space);
|
||||
return makePtr<TonemapReinhardImpl>(gamma, intensity, light_adapt, color_adapt);
|
||||
}
|
||||
|
||||
class TonemapMantiukImpl CV_FINAL : public TonemapMantiuk
|
||||
|
||||
@@ -79,6 +79,20 @@ class houghcircles_test(NewOpenCVTests):
|
||||
self.assertGreater(float(matches_counter) / len(testCircles), .5)
|
||||
self.assertLess(float(len(circles) - matches_counter) / len(circles), .75)
|
||||
|
||||
circles_acc = cv.HoughCirclesWithAccumulator(
|
||||
image=img,
|
||||
method=cv.HOUGH_GRADIENT,
|
||||
dp=1,
|
||||
minDist=10,
|
||||
circles=np.array([]),
|
||||
param1=150,
|
||||
param2=45,
|
||||
minRadius=1,
|
||||
maxRadius=30)
|
||||
|
||||
self.assertEqual(circles_acc.shape, (1, 2, 4))
|
||||
self.assertEqual(circles_acc[0, 0, 3], 66.)
|
||||
self.assertEqual(circles_acc[0, 1, 3], 62.)
|
||||
|
||||
def test_houghcircles_alt(self):
|
||||
|
||||
@@ -127,5 +141,21 @@ class houghcircles_test(NewOpenCVTests):
|
||||
self.assertGreater(float(matches_counter) / len(testCircles), .5)
|
||||
self.assertLess(float(len(circles) - matches_counter) / len(circles), .75)
|
||||
|
||||
circles_acc = cv.HoughCirclesWithAccumulator(
|
||||
image=img,
|
||||
method=cv.HOUGH_GRADIENT_ALT,
|
||||
dp=1,
|
||||
minDist=10,
|
||||
circles=np.array([]),
|
||||
param1=300,
|
||||
param2=0.9,
|
||||
minRadius=13,
|
||||
maxRadius=15)
|
||||
|
||||
self.assertEqual(circles_acc.shape, (1, 3, 4))
|
||||
self.assertEqual(circles_acc[0, 0, 3], 62.)
|
||||
self.assertEqual(circles_acc[0, 1, 3], 59.)
|
||||
self.assertEqual(circles_acc[0, 2, 3], 47.)
|
||||
|
||||
if __name__ == '__main__':
|
||||
NewOpenCVTests.bootstrap()
|
||||
|
||||
@@ -194,7 +194,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
icvWriteFrame_FFMPEG_p(ffmpegWriter, (const uchar*)image.getMat().ptr(), (int)image.step(), image.cols(), image.rows(), image.channels(), 0);
|
||||
if (!icvWriteFrame_FFMPEG_p(ffmpegWriter, (const uchar*)image.getMat().ptr(), (int)image.step(), image.cols(), image.rows(), image.channels(), 0))
|
||||
CV_LOG_WARNING(NULL, "FFmpeg: Failed to write frame");
|
||||
}
|
||||
virtual bool open( const cv::String& filename, int fourcc, double fps, cv::Size frameSize, const VideoWriterParameters& params )
|
||||
{
|
||||
|
||||
@@ -2525,11 +2525,13 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int
|
||||
// check parameters
|
||||
if (input_pix_fmt == AV_PIX_FMT_BGR24) {
|
||||
if (cn != 3) {
|
||||
CV_LOG_WARNING(NULL, "write frame skipped - expected 3 channels but got " << cn);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (input_pix_fmt == AV_PIX_FMT_GRAY8 || input_pix_fmt == AV_PIX_FMT_GRAY16LE) {
|
||||
if (cn != 1) {
|
||||
CV_LOG_WARNING(NULL, "write frame skipped - expected 1 channel but got " << cn);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2640,14 +2642,16 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int
|
||||
}
|
||||
hw_frame->pts = frame_idx;
|
||||
int ret_write = icv_av_write_frame_FFMPEG(oc, video_st, context, outbuf, outbuf_size, hw_frame, frame_idx);
|
||||
ret = ret_write >= 0 ? true : false;
|
||||
// AVERROR(EAGAIN): continue sending input, not an error
|
||||
ret = (ret_write >= 0 || ret_write == AVERROR(EAGAIN));
|
||||
av_frame_free(&hw_frame);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
picture->pts = frame_idx;
|
||||
int ret_write = icv_av_write_frame_FFMPEG(oc, video_st, context, outbuf, outbuf_size, picture, frame_idx);
|
||||
ret = ret_write >= 0 ? true : false;
|
||||
// AVERROR(EAGAIN): continue sending input, not an error
|
||||
ret = (ret_write >= 0 || ret_write == AVERROR(EAGAIN));
|
||||
}
|
||||
|
||||
frame_idx++;
|
||||
|
||||
@@ -2699,7 +2699,7 @@ void CvVideoWriter_GStreamer::write(InputArray image)
|
||||
}
|
||||
else if (input_pix_fmt == GST_VIDEO_FORMAT_GRAY16_LE) {
|
||||
if (image.type() != CV_16UC1) {
|
||||
CV_WARN("write frame skipped - expected CV_16UC3");
|
||||
CV_WARN("write frame skipped - expected CV_16UC1");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -953,4 +953,81 @@ inline static std::string videoio_ffmpeg_16bit_name_printer(const testing::TestP
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, videoio_ffmpeg_16bit, testing::ValuesIn(sixteen_bit_modes), videoio_ffmpeg_16bit_name_printer);
|
||||
|
||||
typedef tuple<int /*inputType*/, int /*Depth*/, bool /*isColor*/, bool /*isValid*/, string /*description*/> ChannelMismatchTestParams;
|
||||
typedef testing::TestWithParam< ChannelMismatchTestParams > videoio_ffmpeg_channel_mismatch;
|
||||
|
||||
TEST_P(videoio_ffmpeg_channel_mismatch, basic)
|
||||
{
|
||||
if (!videoio_registry::hasBackend(CAP_FFMPEG))
|
||||
throw SkipTestException("FFmpeg backend was not found");
|
||||
|
||||
const string filename = "mismatch_video.mp4";
|
||||
int input_type = get<0>(GetParam());
|
||||
int depth = get<1>(GetParam());
|
||||
bool is_Color = get<2>(GetParam());
|
||||
bool is_valid = get<3>(GetParam());
|
||||
const string description = get<4>(GetParam());
|
||||
|
||||
const double fps = 15.0;
|
||||
const int fourcc = VideoWriter::fourcc('m', 'p', '4', 'v');
|
||||
const Mat frame(480, 640, input_type, Scalar::all(0));
|
||||
|
||||
VideoWriter writer(filename, fourcc, fps, frame.size(),
|
||||
{
|
||||
cv::VIDEOWRITER_PROP_DEPTH, depth,
|
||||
VIDEOWRITER_PROP_IS_COLOR, is_Color
|
||||
});
|
||||
|
||||
if (!writer.isOpened())
|
||||
throw SkipTestException("Failed to open video writer");
|
||||
|
||||
for (int i = 1; i <= 15; i++)
|
||||
{
|
||||
// In case of mismatch between input frame channels and
|
||||
// expected depth/isColor configuration a warning should be printed communicating it
|
||||
writer.write(frame);
|
||||
}
|
||||
|
||||
writer.release();
|
||||
|
||||
VideoCapture cap(filename, CAP_FFMPEG);
|
||||
|
||||
if (is_valid) {
|
||||
ASSERT_TRUE(cap.isOpened()) << "Can't open video for " << description;
|
||||
EXPECT_EQ(cap.get(CAP_PROP_FRAME_COUNT), 15) << "All frames should be written for: " << description;
|
||||
} else {
|
||||
ASSERT_FALSE(cap.isOpened()) << "Video capture should fail to open for: " << description;
|
||||
}
|
||||
|
||||
std::remove(filename.c_str());
|
||||
}
|
||||
|
||||
const ChannelMismatchTestParams mismatch_cases[] =
|
||||
{
|
||||
// Testing input frame channels and expected depth/isColor combinations
|
||||
|
||||
// Open VideoWriter depth/isColor combination: CV_8U/true, everything with 3 channels should be valid
|
||||
make_tuple(CV_16UC1, CV_8U, true, false, "input_CV_16UC1_expected_CV_8U_isColor_true"),
|
||||
make_tuple(CV_8UC1, CV_8U, true, false, "input_CV_8UC1_expected_CV_8U_isColor_true"),
|
||||
make_tuple(CV_8UC3, CV_8U, true, true, "input_CV_8UC3_expected_CV_8U_isColor_true_valid"),
|
||||
make_tuple(CV_16UC3, CV_8U, true, true, "input_CV_16UC3_expected_CV_8U_isColor_true_valid"),
|
||||
|
||||
// Open VideoWriter depth/isColor combination: 16U,8U/false, everything with 1 channel should be valid
|
||||
make_tuple(CV_8UC3, CV_8U, false, false, "input_CV_8UC3_expected_CV_8U_isColor_false"),
|
||||
make_tuple(CV_16UC3, CV_8U, false, false, "input_CV_16UC3_expected_CV_8U_isColor_false"),
|
||||
make_tuple(CV_8UC3, CV_16U, false, false, "input_CV_8UC3_expected_CV_16U_isColor_false"),
|
||||
make_tuple(CV_16UC3, CV_16U, false, false, "input_CV_16UC3_expected_CV_16U_isColor_false"),
|
||||
make_tuple(CV_8UC1, CV_16U, false, true, "input_CV_8UC1_expected_CV_16U_isColor_false_valid"),
|
||||
make_tuple(CV_16UC1, CV_8U, false, true, "input_CV_16UC1_expected_CV_8U_isColor_false_valid"),
|
||||
};
|
||||
|
||||
inline static std::string videoio_ffmpeg_mismatch_name_printer(const testing::TestParamInfo<videoio_ffmpeg_channel_mismatch::ParamType>& info)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << get<4>(info.param);
|
||||
return os.str();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, videoio_ffmpeg_channel_mismatch, testing::ValuesIn(mismatch_cases), videoio_ffmpeg_mismatch_name_printer);
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -138,7 +138,7 @@ class ABI:
|
||||
def __str__(self):
|
||||
return "%s (%s)" % (self.name, self.toolchain)
|
||||
def haveIPP(self):
|
||||
return self.name == "x86_64"
|
||||
return self.name == "x86" or self.name == "x86_64"
|
||||
def haveKleidiCV(self):
|
||||
return self.name == "arm64-v8a"
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@ ABIs = [
|
||||
ABI("2", "armeabi-v7a", None, 21, cmake_vars=dict(ANDROID_ABI='armeabi-v7a with NEON')),
|
||||
ABI("3", "arm64-v8a", None, 21, cmake_vars=dict(ANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES='ON')),
|
||||
ABI("5", "x86_64", None, 21, cmake_vars=dict(ANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES='ON')),
|
||||
ABI("4", "x86", None, 21, cmake_vars=dict(WITH_IPP='OFF')),
|
||||
ABI("4", "x86", None, 21),
|
||||
]
|
||||
|
||||
@@ -2,5 +2,5 @@ ABIs = [
|
||||
ABI("2", "armeabi-v7a", None, 21, cmake_vars=dict(ANDROID_ABI='armeabi-v7a with NEON', WITH_FASTCV='ON')),
|
||||
ABI("3", "arm64-v8a", None, 21, cmake_vars=dict(ANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES='ON', WITH_FASTCV='ON')),
|
||||
ABI("5", "x86_64", None, 21, cmake_vars=dict(ANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES='ON')),
|
||||
ABI("4", "x86", None, 21, cmake_vars=dict(WITH_IPP='OFF')),
|
||||
ABI("4", "x86", None, 21),
|
||||
]
|
||||
|
||||
@@ -35,7 +35,7 @@ int main(int argc, char**argv)
|
||||
|
||||
//! [Tonemap HDR image]
|
||||
Mat ldr;
|
||||
Ptr<Tonemap> tonemap = createTonemap(2.2f);
|
||||
Ptr<TonemapDrago> tonemap = createTonemapDrago(2.2f);
|
||||
tonemap->process(hdr, ldr);
|
||||
//! [Tonemap HDR image]
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ def ellipse():
|
||||
for i in range(NUMBER*2):
|
||||
center = []
|
||||
center.append(np.random.randint(x1, x2))
|
||||
center.append(np.random.randint(x1, x2))
|
||||
center.append(np.random.randint(y1, y2))
|
||||
axes = []
|
||||
axes.append(np.random.randint(0, 200))
|
||||
axes.append(np.random.randint(0, 200))
|
||||
@@ -136,7 +136,7 @@ def circles():
|
||||
for i in range(NUMBER):
|
||||
center = []
|
||||
center.append(np.random.randint(x1, x2))
|
||||
center.append(np.random.randint(x1, x2))
|
||||
center.append(np.random.randint(y1, y2))
|
||||
color = "%06x" % np.random.randint(0, 0xFFFFFF)
|
||||
color = tuple(int(color[i:i+2], 16) for i in (0, 2 ,4))
|
||||
cv.circle(image, tuple(center), np.random.randint(0, 300), color, np.random.randint(-1, 9), lineType)
|
||||
@@ -149,7 +149,7 @@ def string():
|
||||
for i in range(NUMBER):
|
||||
org = []
|
||||
org.append(np.random.randint(x1, x2))
|
||||
org.append(np.random.randint(x1, x2))
|
||||
org.append(np.random.randint(y1, y2))
|
||||
color = "%06x" % np.random.randint(0, 0xFFFFFF)
|
||||
color = tuple(int(color[i:i+2], 16) for i in (0, 2 ,4))
|
||||
cv.putText(image, "Testing text rendering", tuple(org), np.random.randint(0, 8), np.random.randint(0, 100)*0.05+0.1, color, np.random.randint(1, 10), lineType)
|
||||
|
||||
@@ -40,7 +40,7 @@ hdr = merge_debevec.process(images, times, response)
|
||||
## [Make HDR image]
|
||||
|
||||
## [Tonemap HDR image]
|
||||
tonemap = cv.createTonemap(2.2)
|
||||
tonemap = cv.createTonemapDrago(2.2)
|
||||
ldr = tonemap.process(hdr)
|
||||
## [Tonemap HDR image]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user