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

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2025-08-13 10:39:05 +03:00
42 changed files with 1557 additions and 872 deletions
@@ -309,7 +309,10 @@ cv::Mat CalibProcessor::processFrame(const cv::Mat &frame)
{
cv::Mat frameCopy;
cv::Mat frameCopyToSave;
frame.copyTo(frameCopy);
if (frame.channels() == 1)
cv::cvtColor(frame, frameCopy, cv::COLOR_GRAY2BGR);
else
frame.copyTo(frameCopy);
bool isTemplateFound = false;
mCurrentImagePoints.clear();
@@ -66,7 +66,7 @@ As new modules are added to OpenCV-Python, this tutorial will have to be expande
familiar with a particular algorithm and can write up a tutorial including basic theory of the
algorithm and code showing example usage, please do so.
Remember, we **together** can make this project a great success !!!
Remember,**together** we can make this project a great success !!!
Contributors
------------
+2 -1
View File
@@ -17,7 +17,8 @@ endif()
target_include_directories(${HAL_LIB_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/modules/core/include
${CMAKE_SOURCE_DIR}/modules/imgproc/include) # ${CMAKE_SOURCE_DIR}/modules/features2d/include
${CMAKE_SOURCE_DIR}/modules/imgproc/include
${CMAKE_SOURCE_DIR}/modules/features/include)
set(RVV_HAL_FOUND TRUE CACHE INTERNAL "")
set(RVV_HAL_VERSION "0.0.1" CACHE INTERNAL "")
+26
View File
@@ -0,0 +1,26 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_RVV_HAL_FEATURES2D_HPP
#define OPENCV_RVV_HAL_FEATURES2D_HPP
struct cvhalFilter2D;
namespace cv { namespace rvv_hal { namespace features2d {
#if CV_HAL_RVV_1P0_ENABLED
int FAST(const uchar* src_data, size_t src_step, int width, int height,
void** keypoints_data, size_t* keypoints_count,
int threshold, bool nonmax_suppression, int detector_type, void* (*realloc_func)(void*, size_t));
#undef cv_hal_FASTv2
#define cv_hal_FASTv2 cv::rvv_hal::features2d::FAST
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::features2d
#endif // OPENCV_RVV_HAL_IMGPROC_HPP
+1
View File
@@ -27,5 +27,6 @@
#include "include/types.hpp"
#include "include/core.hpp"
#include "include/imgproc.hpp"
#include "include/features2d.hpp"
#endif // OPENCV_HAL_RVV_HPP_INCLUDED
+23
View File
@@ -0,0 +1,23 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2025, SpaceMIT Inc., all rights reserved.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
// Third party copyrights are property of their respective owners.
#ifndef OPENCV_HAL_RVV_FEATURES2D_COMMON_HPP_INCLUDED
#define OPENCV_HAL_RVV_FEATURES2D_COMMON_HPP_INCLUDED
#include <riscv_vector.h>
#include "opencv2/features/hal/interface.h"
namespace cv { namespace rvv_hal { namespace features2d { namespace common {
#if CV_HAL_RVV_1P0_ENABLED
#endif // CV_HAL_RVV_1P0_ENABLED
}}}} // cv::rvv_hal::core::common
#endif // OPENCV_HAL_RVV_CORE_COMMON_HPP_INCLUDED
+256
View File
@@ -0,0 +1,256 @@
#include "rvv_hal.hpp"
#include "common.hpp"
#include <cfloat>
namespace cv { namespace rvv_hal { namespace features2d {
static inline uint8_t cornerScore(const uint8_t* ptr, const int* pixel)
{
constexpr int K = 8, N = 16 + K + 1;
int v = ptr[0];
int16_t d[32] = {0};
for (int k = 0; k < N; k++)
d[k] = (int16_t)(v - ptr[pixel[k]]);
auto vlenb = __riscv_vlenb();
switch (vlenb) {
#define CV_RVV_HAL_FAST_CORNERSOCRE16_CASE(lmul) \
size_t vl = __riscv_vsetvl_e16m##lmul(N); \
vint16m##lmul##_t vd = __riscv_vle16_v_i16m##lmul(d, vl); \
vint16m##lmul##_t q0 = __riscv_vmv_v_x_i16m##lmul((int16_t)(-1000), vl); \
vint16m##lmul##_t q1 = __riscv_vmv_v_x_i16m##lmul((int16_t)(1000), vl); \
vint16m##lmul##_t vds = vd, ak0 = vd, bk0 = vd; \
for (int i = 0; i < 8; i++) { \
vds = __riscv_vslide1down(vds, 0, vl); \
ak0 = __riscv_vmin(ak0, vds, vl); \
bk0 = __riscv_vmax(bk0, vds, vl); \
} \
q0 = __riscv_vmax(q0, __riscv_vmin(ak0, vd, vl), vl); \
q1 = __riscv_vmin(q1, __riscv_vmax(bk0, vd, vl), vl); \
vds = __riscv_vslide1down(vds, 0, vl); \
q0 = __riscv_vmax(q0, __riscv_vmin(ak0, vds, vl), vl); \
q1 = __riscv_vmin(q1, __riscv_vmax(bk0, vds, vl), vl); \
q0 = __riscv_vmax(q0, __riscv_vrsub(q1, 0, vl), vl); \
return (uint8_t)(__riscv_vmv_x(__riscv_vredmax(q0, __riscv_vmv_s_x_i16m1(0, vl), vl)) - 1);
case 16: { // 128-bit
CV_RVV_HAL_FAST_CORNERSOCRE16_CASE(4)
} break;
case 32: { // 256-bit
CV_RVV_HAL_FAST_CORNERSOCRE16_CASE(2)
} break;
default: { // >=512-bit
CV_RVV_HAL_FAST_CORNERSOCRE16_CASE(1)
}
}
}
inline int fast_16(const uchar* src_data, size_t src_step,
int width, int height,
std::vector<cvhalKeyPoint> &keypoints,
int threshold, bool nonmax_suppression)
{
constexpr int patternSize = 16;
constexpr int K = patternSize/2, N = patternSize + K + 1;
constexpr int quarterPatternSize = patternSize/4;
int i, j, k;
int pixel[N] = {0};
pixel[0] = 0 + (int)src_step * 3;
pixel[1] = 1 + (int)src_step * 3;
pixel[2] = 2 + (int)src_step * 2;
pixel[3] = 3 + (int)src_step * 1;
pixel[4] = 3 + (int)src_step * 0;
pixel[5] = 3 + (int)src_step * -1;
pixel[6] = 2 + (int)src_step * -2;
pixel[7] = 1 + (int)src_step * -3;
pixel[8] = 0 + (int)src_step * -3;
pixel[9] = -1 + (int)src_step * -3;
pixel[10] = -2 + (int)src_step * -2;
pixel[11] = -3 + (int)src_step * -1;
pixel[12] = -3 + (int)src_step * 0;
pixel[13] = -3 + (int)src_step * 1;
pixel[14] = -2 + (int)src_step * 2;
pixel[15] = -1 + (int)src_step * 3;
for (k = 16; k < N; k++)
{
pixel[k] = pixel[k - 16];
}
std::vector<uchar> _buf((width+16)*3*(sizeof(ptrdiff_t) + sizeof(uchar)) + 128);
uchar* buf[3];
buf[0] = &_buf[0]; buf[1] = buf[0] + width; buf[2] = buf[1] + width;
ptrdiff_t* cpbuf[3];
cpbuf[0] = (ptrdiff_t*)alignPtr(buf[2] + width, sizeof(ptrdiff_t)) + 1;
cpbuf[1] = cpbuf[0] + width + 1;
cpbuf[2] = cpbuf[1] + width + 1;
memset(buf[0], 0, width*3);
int vlmax = __riscv_vsetvlmax_e8m4();
vuint8m4_t v_c_delta = __riscv_vmv_v_x_u8m4(0x80, vlmax);
vuint8m4_t v_c_threshold = __riscv_vmv_v_x_u8m4((char) threshold, vlmax);
vuint8m4_t v_c_k = __riscv_vmv_v_x_u8m4((uint8_t)K, vlmax);
vuint8m4_t v_c_zero = __riscv_vmv_v_x_u8m4(0, vlmax);
for( i = 3; i < height - 2; i++)
{
const uchar* ptr = src_data + i * src_step + 3;
uchar* curr = buf[(i - 3)%3];
ptrdiff_t* cornerpos = cpbuf[(i - 3)%3];
memset(curr, 0, width);
ptrdiff_t ncorners = 0;
if( i < height - 3 )
{
j = 3;
{
int margin = width - 3;
int vl = __riscv_vsetvl_e8m4(margin - j);
for (; j < margin; j += vl, ptr += vl)
{
vl = __riscv_vsetvl_e8m4(margin - j);
vuint8m4_t v_pixels = __riscv_vle8_v_u8m4(ptr, vl);
// pixels add threshold
vuint8m4_t v_pat = __riscv_vsaddu(v_pixels, v_c_threshold, vl);
// pixels sub threshold
vuint8m4_t v_pst = __riscv_vssubu(v_pixels, v_c_threshold, vl);
vint8m4_t v0 = __riscv_vreinterpret_i8m4(__riscv_vxor(v_pat, v_c_delta, vl));
vint8m4_t v1 = __riscv_vreinterpret_i8m4(__riscv_vxor(v_pst, v_c_delta, vl));
v_pixels = __riscv_vle8_v_u8m4(ptr + pixel[0], vl);
vint8m4_t x0 = __riscv_vreinterpret_i8m4(__riscv_vsub(v_pixels, v_c_delta, vl));
v_pixels = __riscv_vle8_v_u8m4(ptr + pixel[quarterPatternSize], vl);
vint8m4_t x1 = __riscv_vreinterpret_i8m4(__riscv_vsub(v_pixels, v_c_delta, vl));
v_pixels = __riscv_vle8_v_u8m4(ptr + pixel[2*quarterPatternSize], vl);
vint8m4_t x2 = __riscv_vreinterpret_i8m4(__riscv_vsub(v_pixels, v_c_delta, vl));
v_pixels = __riscv_vle8_v_u8m4(ptr + pixel[3*quarterPatternSize], vl);
vint8m4_t x3 = __riscv_vreinterpret_i8m4(__riscv_vsub(v_pixels, v_c_delta, vl));
vbool2_t m0, m1;
m0 = __riscv_vmand(__riscv_vmslt(v0, x0, vl), __riscv_vmslt(v0, x1, vl), vl);
m1 = __riscv_vmand(__riscv_vmslt(x0, v1, vl), __riscv_vmslt(x1, v1, vl), vl);
m0 = __riscv_vmor(m0, __riscv_vmand(__riscv_vmslt(v0, x1, vl), __riscv_vmslt(v0, x2, vl), vl), vl);
m1 = __riscv_vmor(m1, __riscv_vmand(__riscv_vmslt(x1, v1, vl), __riscv_vmslt(x2, v1, vl), vl), vl);
m0 = __riscv_vmor(m0, __riscv_vmand(__riscv_vmslt(v0, x2, vl), __riscv_vmslt(v0, x3, vl), vl), vl);
m1 = __riscv_vmor(m1, __riscv_vmand(__riscv_vmslt(x2, v1, vl), __riscv_vmslt(x3, v1, vl), vl), vl);
m0 = __riscv_vmor(m0, __riscv_vmand(__riscv_vmslt(v0, x3, vl), __riscv_vmslt(v0, x0, vl), vl), vl);
m1 = __riscv_vmor(m1, __riscv_vmand(__riscv_vmslt(x3, v1, vl), __riscv_vmslt(x0, v1, vl), vl), vl);
m0 = __riscv_vmor(m0, m1, vl);
unsigned long mask_cnt = __riscv_vcpop(m0, vl);
if(!mask_cnt)
continue;
// TODO: Test if skipping to the first possible key point pixel if faster
// Memory access maybe expensive since the data is not aligned
// long first_set = __riscv_vfirst(m0, vl);
// if( first_set == -1 ) {
// j -= first_set;
// ptr -= first_set;
// }
vuint8m4_t c0 = __riscv_vmv_v_x_u8m4(0, vl);
vuint8m4_t c1 = __riscv_vmv_v_x_u8m4(0, vl);
vuint8m4_t max0 = __riscv_vmv_v_x_u8m4(0, vl);
vuint8m4_t max1 = __riscv_vmv_v_x_u8m4(0, vl);
for( k = 0; k < N; k++ )
{
vint8m4_t x = __riscv_vreinterpret_i8m4(__riscv_vxor(__riscv_vle8_v_u8m4(ptr + pixel[k], vl), v_c_delta, vl));
m0 = __riscv_vmslt(v0, x, vl);
m1 = __riscv_vmslt(x, v1, vl);
c0 = __riscv_vadd_mu(m0, c0, c0, (uint8_t)1, vl);
c1 = __riscv_vadd_mu(m1, c1, c1, (uint8_t)1, vl);
c0 = __riscv_vmerge(v_c_zero, c0, m0, vl);
c1 = __riscv_vmerge(v_c_zero, c1, m1, vl);
max0 = __riscv_vmaxu(max0, c0, vl);
max1 = __riscv_vmaxu(max1, c1, vl);
}
vbool2_t v_comparek = __riscv_vmsltu(v_c_k, __riscv_vmaxu(max0, max1, vl), vl);
uint8_t m[64];
__riscv_vse8(m, __riscv_vreinterpret_u8m1(v_comparek), vl);
for( k = 0; k < vl; k++ )
{
if( (m[k / 8] >> (k % 8)) & 1 )
{
cornerpos[ncorners++] = j + k;
if(nonmax_suppression) {
curr[j + k] = (uchar)cornerScore(ptr + k, pixel);
}
}
}
}
}
}
cornerpos[-1] = ncorners;
if( i == 3 ) continue;
const uchar* prev = buf[(i - 4 + 3)%3];
const uchar* pprev = buf[(i - 5 + 3)%3];
cornerpos = cpbuf[(i - 4 + 3)%3]; // cornerpos[-1] is used to store a value
ncorners = cornerpos[-1];
for( k = 0; k < ncorners; k++ )
{
j = cornerpos[k];
int score = prev[j];
if(!nonmax_suppression ||
(score > prev[j+1] && score > prev[j-1] &&
score > pprev[j-1] && score > pprev[j] && score > pprev[j+1] &&
score > curr[j-1] && score > curr[j] && score > curr[j+1]) )
{
cvhalKeyPoint kp;
kp.x = (float)j;
kp.y = (float)(i-1);
kp.size = 7.f;
kp.angle = -1.f;
kp.response = (float)score;
kp.octave = 0; // Not used in FAST
kp.class_id = -1; // Not used in FAST
keypoints.push_back(kp);
}
}
}
return CV_HAL_ERROR_OK;
}
int FAST(const uchar* src_data, size_t src_step,
int width, int height, void** keypoints_data,
size_t* keypoints_count, int threshold,
bool nonmax_suppression, int detector_type, void* (*realloc_func)(void*, size_t))
{
int res = CV_HAL_ERROR_UNKNOWN;
switch(detector_type) {
case CV_HAL_TYPE_5_8:
return CV_HAL_ERROR_NOT_IMPLEMENTED;
case CV_HAL_TYPE_7_12:
return CV_HAL_ERROR_NOT_IMPLEMENTED;
case CV_HAL_TYPE_9_16: {
std::vector<cvhalKeyPoint> keypoints;
res = fast_16(src_data, src_step, width, height, keypoints, threshold, nonmax_suppression);
if (res == CV_HAL_ERROR_OK) {
if (keypoints.size() > *keypoints_count) {
*keypoints_count = keypoints.size();
uchar *tmp = (uchar*)realloc_func(*keypoints_data, sizeof(cvhalKeyPoint)*(*keypoints_count));
memcpy(tmp, (uchar*)keypoints.data(), sizeof(cvhalKeyPoint)*(*keypoints_count));
*keypoints_data = tmp;
} else {
*keypoints_count = keypoints.size();
memcpy(*keypoints_data, (uchar*)keypoints.data(), sizeof(cvhalKeyPoint)*(*keypoints_count));
}
}
return res;
}
default:
return res;
}
}
}}} // namespace cv::rvv_hal::features2d
+31 -9
View File
@@ -424,7 +424,9 @@ int cv::cuda::DeviceInfo::clockRate() const
#ifndef HAVE_CUDA
throw_no_cuda();
#else
return deviceProps().get(device_id_)->clockRate;
int clockRate;
cudaSafeCall(cudaDeviceGetAttribute(&clockRate, cudaDevAttrClockRate, device_id_));
return clockRate;
#endif
}
@@ -487,7 +489,9 @@ bool cv::cuda::DeviceInfo::kernelExecTimeoutEnabled() const
#ifndef HAVE_CUDA
throw_no_cuda();
#else
return deviceProps().get(device_id_)->kernelExecTimeoutEnabled != 0;
int kernelExecTimeoutEnabled;
cudaSafeCall(cudaDeviceGetAttribute(&kernelExecTimeoutEnabled, cudaDevAttrKernelExecTimeout, device_id_));
return kernelExecTimeoutEnabled != 0;
#endif
}
@@ -522,7 +526,9 @@ DeviceInfo::ComputeMode cv::cuda::DeviceInfo::computeMode() const
ComputeModeExclusiveProcess
};
return tbl[deviceProps().get(device_id_)->computeMode];
int computeMode;
cudaSafeCall(cudaDeviceGetAttribute(&computeMode, cudaDevAttrComputeMode, device_id_));
return tbl[computeMode];
#endif
}
@@ -554,7 +560,14 @@ int cv::cuda::DeviceInfo::maxTexture1DLinear() const
#ifndef HAVE_CUDA
throw_no_cuda();
#else
return deviceProps().get(device_id_)->maxTexture1DLinear;
#if CUDA_VERSION >= 13000
size_t maxWidthInElements;
cudaChannelFormatDesc fmtDesc = cudaCreateChannelDesc<float4>();
cudaSafeCall(cudaDeviceGetTexture1DLinearMaxWidth(&maxWidthInElements, &fmtDesc, device_id_));
return maxWidthInElements;
#else
return deviceProps().get(device_id_)->maxTexture1DLinear;
#endif
#endif
}
@@ -793,7 +806,9 @@ int cv::cuda::DeviceInfo::memoryClockRate() const
#ifndef HAVE_CUDA
throw_no_cuda();
#else
return deviceProps().get(device_id_)->memoryClockRate;
int memoryClockRate;
cudaSafeCall(cudaDeviceGetAttribute(&memoryClockRate, cudaDevAttrMemoryClockRate, device_id_));
return memoryClockRate;
#endif
}
@@ -933,7 +948,9 @@ void cv::cuda::printCudaDeviceInfo(int device)
if (cores > 0)
printf(" (%2d) Multiprocessors x (%2d) CUDA Cores/MP: %d CUDA Cores\n", prop.multiProcessorCount, cores, cores * prop.multiProcessorCount);
printf(" GPU Clock Speed: %.2f GHz\n", prop.clockRate * 1e-6f);
int clockRate;
cudaSafeCall(cudaDeviceGetAttribute(&clockRate, cudaDevAttrClockRate, dev));
printf(" GPU Clock Speed: %.2f GHz\n", clockRate * 1e-6f);
printf(" Max Texture Dimension Size (x,y,z) 1D=(%d), 2D=(%d,%d), 3D=(%d,%d,%d)\n",
prop.maxTexture1D, prop.maxTexture2D[0], prop.maxTexture2D[1],
@@ -952,8 +969,10 @@ void cv::cuda::printCudaDeviceInfo(int device)
printf(" Maximum memory pitch: %u bytes\n", (int)prop.memPitch);
printf(" Texture alignment: %u bytes\n", (int)prop.textureAlignment);
printf(" Concurrent copy and execution: %s with %d copy engine(s)\n", (prop.deviceOverlap ? "Yes" : "No"), prop.asyncEngineCount);
printf(" Run time limit on kernels: %s\n", prop.kernelExecTimeoutEnabled ? "Yes" : "No");
printf(" Concurrent copy and execution: %s with %d copy engine(s)\n", (prop.asyncEngineCount ? "Yes" : "No"), prop.asyncEngineCount);
int kernelExecTimeoutEnabled;
cudaSafeCall(cudaDeviceGetAttribute(&kernelExecTimeoutEnabled, cudaDevAttrKernelExecTimeout, dev));
printf(" Run time limit on kernels: %s\n", kernelExecTimeoutEnabled ? "Yes" : "No");
printf(" Integrated GPU sharing Host Memory: %s\n", prop.integrated ? "Yes" : "No");
printf(" Support host page-locked memory mapping: %s\n", prop.canMapHostMemory ? "Yes" : "No");
@@ -963,8 +982,11 @@ void cv::cuda::printCudaDeviceInfo(int device)
printf(" Device is using TCC driver mode: %s\n", prop.tccDriver ? "Yes" : "No");
printf(" Device supports Unified Addressing (UVA): %s\n", prop.unifiedAddressing ? "Yes" : "No");
printf(" Device PCI Bus ID / PCI location ID: %d / %d\n", prop.pciBusID, prop.pciDeviceID );
int propComputeMode;
cudaSafeCall(cudaDeviceGetAttribute(&propComputeMode, cudaDevAttrComputeMode, dev));
printf(" Compute Mode:\n");
printf(" %s \n", computeMode[prop.computeMode]);
printf(" %s \n", computeMode[propComputeMode]);
}
printf("\n");
+43
View File
@@ -0,0 +1,43 @@
#include "perf_precomp.hpp"
#include "perf_feature2d.hpp"
namespace opencv_test
{
using namespace perf;
typedef tuple<int, int, bool, string> Fast_Params_t;
typedef perf::TestBaseWithParam<Fast_Params_t> Fast_Params;
PERF_TEST_P(Fast_Params, detect,
testing::Combine(
testing::Values(20,30,100), // threshold
testing::Values(
// (int)FastFeatureDetector::TYPE_5_8,
// (int)FastFeatureDetector::TYPE_7_12,
(int)FastFeatureDetector::TYPE_9_16 // detector_type
),
testing::Bool(), // nonmaxSuppression
testing::Values("cv/inpaint/orig.png",
"cv/cameracalibration/chess9.png")
))
{
int threshold_p = get<0>(GetParam());
int type_p = get<1>(GetParam());
bool nonmaxSuppression_p = get<2>(GetParam());
string filename = getDataPath(get<3>(GetParam()));
Mat img = imread(filename, IMREAD_GRAYSCALE);
ASSERT_FALSE(img.empty()) << "Failed to load image: " << filename;
vector<KeyPoint> keypoints;
declare.in(img);
TEST_CYCLE()
{
FAST(img, keypoints, threshold_p, nonmaxSuppression_p, (FastFeatureDetector::DetectorType)type_p);
}
SANITY_CHECK_NOTHING();
}
} // namespace opencv_test
+19 -5
View File
@@ -429,17 +429,31 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
{
CV_INSTRUMENT_REGION();
const size_t max_fast_features = std::max(_img.total()/100, size_t(1000)); // Simple heuristic that depends on resolution.
CV_OCL_RUN(_img.isUMat() && type == FastFeatureDetector::TYPE_9_16,
ocl_FAST(_img, keypoints, threshold, nonmax_suppression, 10000));
ocl_FAST(_img, keypoints, threshold, nonmax_suppression, (int)max_fast_features));
cv::Mat img = _img.getMat();
CALL_HAL(fast_dense, hal_FAST, img, keypoints, threshold, nonmax_suppression, type);
size_t keypoints_count = 10000;
size_t keypoints_count = 1;
keypoints.clear();
keypoints.resize(keypoints_count);
CALL_HAL(fast, cv_hal_FAST, img.data, img.step, img.cols, img.rows,
(uchar*)(keypoints.data()), &keypoints_count, threshold, nonmax_suppression, type);
KeyPoint* kps = (KeyPoint*)malloc(sizeof(KeyPoint) * keypoints_count);
int hal_ret = cv_hal_FASTv2(img.data, img.step, img.cols, img.rows, (void**)&kps,
&keypoints_count, threshold, nonmax_suppression, type, realloc);
if (hal_ret == CV_HAL_ERROR_OK) {
keypoints.assign(kps, kps + keypoints_count);
free(kps);
return;
} else {
free(kps);
keypoints_count = max_fast_features;
keypoints.clear();
keypoints.resize(keypoints_count);
CALL_HAL(fast, cv_hal_FAST, img.data, img.step, img.cols, img.rows,
(uchar*)(keypoints.data()), &keypoints_count, threshold, nonmax_suppression, type);
}
switch(type) {
case FastFeatureDetector::TYPE_5_8:
+16
View File
@@ -104,8 +104,24 @@ inline int hal_ni_FAST_NMS(const uchar* src_data, size_t src_step, uchar* dst_da
*/
inline int hal_ni_FAST(const uchar* src_data, size_t src_step, int width, int height, uchar* keypoints_data, size_t* keypoints_count, int threshold, bool nonmax_suppression, int /*cv::FastFeatureDetector::DetectorType*/ type) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
/**
@brief Detects corners using the FAST algorithm.
@param src_data Source image data
@param src_step Source image step
@param width Source image width
@param height Source image height
@param keypoints_data Pointer to keypoints
@param keypoints_count Count of keypoints
@param threshold Threshold for keypoint
@param nonmax_suppression Indicates if make nonmaxima suppression or not.
@param type FAST type
@param realloc_func function for reallocation
*/
inline int hal_ni_FASTv2(const uchar* src_data, size_t src_step, int width, int height, void** keypoints_data, size_t* keypoints_count, int threshold, bool nonmax_suppression, int /*cv::FastFeatureDetector::DetectorType*/ type, void* (*realloc_func)(void*, size_t)) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
//! @cond IGNORED
#define cv_hal_FAST hal_ni_FAST
#define cv_hal_FASTv2 hal_ni_FASTv2
//! @endcond
//! @}
@@ -105,16 +105,16 @@ enum ImwriteFlags {
IMWRITE_WEBP_QUALITY = 64, //!< For WEBP, it can be a quality from 1 to 100 (the higher is the better). By default (without any parameter) and for quality above 100 the lossless compression is used.
IMWRITE_HDR_COMPRESSION = (5 << 4) + 0 /* 80 */, //!< specify HDR compression
IMWRITE_PAM_TUPLETYPE = 128,//!< For PAM, sets the TUPLETYPE field to the corresponding string value that is defined for the format
IMWRITE_TIFF_RESUNIT = 256,//!< For TIFF, use to specify which DPI resolution unit to set; see libtiff documentation for valid values
IMWRITE_TIFF_RESUNIT = 256,//!< For TIFF, use to specify which DPI resolution unit to set. See ImwriteTiffResolutionUnitFlags. Default is IMWRITE_TIFF_RESOLUTION_UNIT_INCH.
IMWRITE_TIFF_XDPI = 257,//!< For TIFF, use to specify the X direction DPI
IMWRITE_TIFF_YDPI = 258,//!< For TIFF, use to specify the Y direction DPI
IMWRITE_TIFF_COMPRESSION = 259,//!< For TIFF, use to specify the image compression scheme. See cv::ImwriteTiffCompressionFlags. Note, for images whose depth is CV_32F, only libtiff's SGILOG compression scheme is used. For other supported depths, the compression scheme can be specified by this flag; LZW compression is the default.
IMWRITE_TIFF_ROWSPERSTRIP = 278,//!< For TIFF, use to specify the number of rows per strip.
IMWRITE_TIFF_PREDICTOR = 317,//!< For TIFF, use to specify predictor. See cv::ImwriteTiffPredictorFlags.
IMWRITE_TIFF_PREDICTOR = 317,//!< For TIFF, use to specify predictor. See cv::ImwriteTiffPredictorFlags. Default is IMWRITE_TIFF_PREDICTOR_HORIZONTAL .
IMWRITE_JPEG2000_COMPRESSION_X1000 = 272,//!< For JPEG2000, use to specify the target compression rate (multiplied by 1000). The value can be from 0 to 1000. Default is 1000.
IMWRITE_AVIF_QUALITY = 512,//!< For AVIF, it can be a quality between 0 and 100 (the higher the better). Default is 95.
IMWRITE_AVIF_DEPTH = 513,//!< For AVIF, it can be 8, 10 or 12. If >8, it is stored/read as CV_32F. Default is 8.
IMWRITE_AVIF_SPEED = 514,//!< For AVIF, it is between 0 (slowest) and (fastest). Default is 9.
IMWRITE_AVIF_SPEED = 514,//!< For AVIF, it is between 0 (slowest) and 10(fastest). Default is 9.
IMWRITE_JPEGXL_QUALITY = 640,//!< For JPEG XL, it can be a quality from 0 to 100 (the higher is the better). Default value is 95. If set, distance parameter is re-calicurated from quality level automatically. This parameter request libjxl v0.10 or later.
IMWRITE_JPEGXL_EFFORT = 641,//!< For JPEG XL, encoder effort/speed level without affecting decoding speed; it is between 1 (fastest) and 10 (slowest). Default is 7.
IMWRITE_JPEGXL_DISTANCE = 642,//!< For JPEG XL, distance level for lossy compression: target max butteraugli distance, lower = higher quality, 0 = lossless; range: 0 .. 25. Default is 1.
@@ -175,7 +175,12 @@ enum ImwriteTiffPredictorFlags {
IMWRITE_TIFF_PREDICTOR_NONE = 1, //!< no prediction scheme used
IMWRITE_TIFF_PREDICTOR_HORIZONTAL = 2, //!< horizontal differencing
IMWRITE_TIFF_PREDICTOR_FLOATINGPOINT = 3 //!< floating point predictor
};
enum ImwriteTiffResolutionUnitFlags {
IMWRITE_TIFF_RESOLUTION_UNIT_NONE = 1, //!< no absolute unit of measurement.
IMWRITE_TIFF_RESOLUTION_UNIT_INCH = 2, //!< inch
IMWRITE_TIFF_RESOLUTION_UNIT_CENTIMETER = 3, //!< centimeter
};
enum ImwriteEXRTypeFlags {
+152 -2
View File
@@ -7,10 +7,82 @@
namespace opencv_test
{
#ifdef HAVE_PNG
using namespace perf;
static Animation makeCirclesAnimation(Size size = Size(320, 240), int type = CV_8UC4, int nbits = 8, int frameCount = 40)
{
struct AnimatedCircle {
cv::Point2f pos;
cv::Point2f velocity;
float radius;
float radius_speed;
cv::Scalar color;
cv::Scalar border_color;
};
const int numCircles = 80;
const int maxval = (1 << nbits) - 1;
cv::RNG rng = theRNG();
std::vector<AnimatedCircle> circles;
Animation animation;
// Initialize animated circles
for (int i = 0; i < numCircles; ++i) {
AnimatedCircle c;
c.pos = cv::Point2f(rng.uniform(0.f, (float)size.width),
rng.uniform(0.f, (float)size.height));
c.velocity = cv::Point2f(rng.uniform(-2.f, 2.f),
rng.uniform(-2.f, 2.f));
c.radius = rng.uniform(10.f, 40.f);
c.radius_speed = rng.uniform(-0.5f, 0.5f);
c.color = cv::Scalar(rng.uniform(0, maxval),
rng.uniform(0, maxval),
rng.uniform(0, maxval),
rng.uniform(230, maxval));
c.border_color = c.color;
circles.push_back(c);
}
// Generate frames
for (int frame = 0; frame < frameCount; ++frame) {
cv::Mat img(size, type, cv::Scalar(20, 0, 10, 128));
for (size_t i = 0; i < circles.size(); ++i) {
AnimatedCircle& c = circles[i];
// Update position
c.pos += c.velocity;
// Bounce on edges
if (c.pos.x < 0 || c.pos.x > size.width) c.velocity.x *= -1;
if (c.pos.y < 0 || c.pos.y > size.height) c.velocity.y *= -1;
// Update radius
c.radius += c.radius_speed;
if (c.radius < 10.f || c.radius > 80.f) {
c.radius_speed *= -1;
c.radius = std::max(10.f, std::min(c.radius, 80.f));
}
c.color = c.color - Scalar(c.velocity.x, 0, c.velocity.y, rng.uniform(1, 4));
// Draw
cv::circle(img, c.pos, (int)c.radius, c.color, cv::FILLED, cv::LINE_AA);
cv::circle(img, c.pos, (int)c.radius, c.border_color, 1, cv::LINE_AA);
}
animation.frames.push_back(img);
animation.durations.push_back(20); // milliseconds
}
for (int i = (int)animation.frames.size() - 1; i >= 0; --i) {
animation.frames.push_back(animation.frames[i].clone());
animation.durations.push_back(15);
}
return animation;
}
typedef perf::TestBaseWithParam<std::string> Decode;
typedef perf::TestBaseWithParam<std::string> Encode;
@@ -32,7 +104,9 @@ const string exts[] = {
#ifdef HAVE_JPEGXL
".jxl",
#endif
#ifdef HAVE_PNG
".png",
#endif
#ifdef HAVE_IMGCODEC_PXM
".ppm",
#endif
@@ -54,7 +128,9 @@ const string exts_multi[] = {
#ifdef HAVE_IMGCODEC_GIF
".gif",
#endif
#ifdef HAVE_PNG
".png",
#endif
#ifdef HAVE_TIFF
".tiff",
#endif
@@ -63,6 +139,23 @@ const string exts_multi[] = {
#endif
};
const string exts_anim[] = {
#ifdef HAVE_AVIF
".avif",
#endif
#ifdef HAVE_IMGCODEC_GIF
".gif",
#endif
#ifdef HAVE_PNG
".png",
#endif
#ifdef HAVE_WEBP
".webp",
#endif
};
#ifdef HAVE_PNG
PERF_TEST_P(Decode, bgr, testing::ValuesIn(exts))
{
String filename = getDataPath("perf/1920x1080.png");
@@ -126,6 +219,63 @@ PERF_TEST_P(Encode, multi, testing::ValuesIn(exts_multi))
SANITY_CHECK_NOTHING();
}
#endif // HAVE_PNG
PERF_TEST_P(Encode, animation, testing::ValuesIn(exts_anim))
{
Animation animation = makeCirclesAnimation();
TEST_CYCLE()
{
vector<uchar> buf;
EXPECT_TRUE(imencodeanimation(GetParam().c_str(), animation, buf));
}
SANITY_CHECK_NOTHING();
}
PERF_TEST_P(Encode, multi_page, testing::ValuesIn(exts_multi))
{
Animation animation = makeCirclesAnimation();
TEST_CYCLE()
{
vector<uchar> buf;
EXPECT_TRUE(imencodemulti(GetParam().c_str(), animation.frames, buf));
}
SANITY_CHECK_NOTHING();
}
PERF_TEST_P(Decode, animation, testing::ValuesIn(exts_anim))
{
Animation animation = makeCirclesAnimation();
vector<uchar> buf;
ASSERT_TRUE(imencodeanimation(GetParam().c_str(), animation, buf));
TEST_CYCLE()
{
Animation tmp_animation;
EXPECT_TRUE(imdecodeanimation(buf, tmp_animation));
}
SANITY_CHECK_NOTHING();
}
PERF_TEST_P(Decode, multi_page, testing::ValuesIn(exts_multi))
{
Animation animation = makeCirclesAnimation();
vector<uchar> buf;
ASSERT_TRUE(imencodemulti(GetParam().c_str(), animation.frames, buf));
TEST_CYCLE()
{
vector<Mat> tmp_frames;
EXPECT_TRUE(imdecodemulti(buf, IMREAD_UNCHANGED, tmp_frames));
}
SANITY_CHECK_NOTHING();
}
} // namespace
+16 -3
View File
@@ -319,6 +319,7 @@ AvifEncoder::AvifEncoder() {
m_support_metadata[(size_t)IMAGE_METADATA_XMP] = true;
m_support_metadata[(size_t)IMAGE_METADATA_ICCP] = true;
encoder_ = avifEncoderCreate();
m_supported_encode_key = { IMWRITE_AVIF_QUALITY, IMWRITE_AVIF_DEPTH, IMWRITE_AVIF_SPEED };
}
AvifEncoder::~AvifEncoder() {
@@ -334,9 +335,13 @@ bool AvifEncoder::writeanimation(const Animation& animation,
int bit_depth = 8;
int speed = AVIF_SPEED_FASTEST;
for (size_t i = 0; i < params.size(); i += 2) {
const int value = params[i + 1];
if (params[i] == IMWRITE_AVIF_QUALITY) {
const int quality = std::min(std::max(params[i + 1], AVIF_QUALITY_WORST),
const int quality = std::min(std::max(value, AVIF_QUALITY_WORST),
AVIF_QUALITY_BEST);
if (value != quality) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_AVIF_QUALITY must be between 0 to 100. It is fallbacked to %d", value, quality));
}
#if CV_AVIF_USE_QUALITY
encoder_->quality = quality;
#else
@@ -346,9 +351,17 @@ bool AvifEncoder::writeanimation(const Animation& animation,
AVIF_QUANTIZER_WORST_QUALITY;
#endif
} else if (params[i] == IMWRITE_AVIF_DEPTH) {
bit_depth = params[i + 1];
bit_depth = value;
if ((bit_depth != 8) && (bit_depth !=10) && (bit_depth !=12))
{
bit_depth = 8;
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_AVIF_DEPTH must be 8, 10 or 12. It is fallbacked to %d", value, bit_depth));
}
} else if (params[i] == IMWRITE_AVIF_SPEED) {
speed = params[i + 1];
speed = std::min(std::max(value,0),10);
if (value != speed) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_AVIF_SPEED must be between 0 to 10. It is fallbacked to %d", value, speed));
}
}
}
+8
View File
@@ -155,6 +155,14 @@ bool BaseImageEncoder::isFormatSupported( int depth ) const
return depth == CV_8U;
}
bool BaseImageEncoder::isValidEncodeKey(const int key) const
{
auto first = m_supported_encode_key.begin();
auto last = m_supported_encode_key.end();
return (std::find(first, last, key) != last);
}
String BaseImageEncoder::getDescription() const
{
return m_description;
+8
View File
@@ -224,6 +224,13 @@ public:
*/
virtual bool isFormatSupported(int depth) const;
/**
* @brief Validates if the encoder supports a specific key.
* @param key The key of the encode parameter.
* @return true if key is supported for this encoder, false otherwise.
*/
virtual bool isValidEncodeKey(const int key) const;
/**
* @brief Set the destination for encoding as a file.
* @param filename The name of the file to which the image will be written.
@@ -290,6 +297,7 @@ protected:
std::vector<uchar>* m_buf; ///< Pointer to the buffer for encoded data if using memory-based destination.
bool m_buf_supported; ///< Flag indicating whether buffer-based encoding is supported.
String m_last_error; ///< Stores the last error message encountered during encoding.
std::vector<int> m_supported_encode_key; ///< Supported encode key list
};
}
+15 -5
View File
@@ -719,6 +719,7 @@ ImageDecoder ExrDecoder::newDecoder() const
ExrEncoder::ExrEncoder()
{
m_description = "OpenEXR Image files (*.exr)";
m_supported_encode_key = {IMWRITE_EXR_TYPE, IMWRITE_EXR_COMPRESSION, IMWRITE_EXR_DWA_COMPRESSION_LEVEL};
}
@@ -745,9 +746,10 @@ bool ExrEncoder::write( const Mat& img, const std::vector<int>& params )
for( size_t i = 0; i < params.size(); i += 2 )
{
const int value = params[i+1];
if( params[i] == IMWRITE_EXR_TYPE )
{
switch( params[i+1] )
switch( value )
{
case IMWRITE_EXR_TYPE_HALF:
type = HALF;
@@ -756,12 +758,14 @@ bool ExrEncoder::write( const Mat& img, const std::vector<int>& params )
type = FLOAT;
break;
default:
CV_Error(Error::StsBadArg, "IMWRITE_EXR_TYPE is invalid or not supported");
type = FLOAT;
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_EXR_TYPE must be one of ImwriteEXRTypeFlags. It is fallbacked to IMWRITE_EXR_TYPE_FLOAT", value));
break;
}
}
if ( params[i] == IMWRITE_EXR_COMPRESSION )
{
switch ( params[i + 1] )
switch ( value )
{
case IMWRITE_EXR_COMPRESSION_NO:
header.compression() = NO_COMPRESSION;
@@ -799,7 +803,9 @@ bool ExrEncoder::write( const Mat& img, const std::vector<int>& params )
break;
#endif
default:
CV_Error(Error::StsBadArg, "IMWRITE_EXR_COMPRESSION is invalid or not supported");
header.compression() = ZIP_COMPRESSION;
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_EXR_COMPRESSION must be one of ImwriteEXRCompressionFlags. It is fallbacked to IMWRITE_EXR_COMPRESSION_ZIP", value));
break;
}
}
if (params[i] == IMWRITE_EXR_DWA_COMPRESSION_LEVEL)
@@ -809,7 +815,11 @@ bool ExrEncoder::write( const Mat& img, const std::vector<int>& params )
#elif OPENEXR_VERSION_MAJOR < 3
CV_LOG_ONCE_WARNING(NULL, "Setting `IMWRITE_EXR_DWA_COMPRESSION_LEVEL` not supported in OpenEXR version " + std::to_string(OPENEXR_VERSION_MAJOR) + " (version 3 is required)");
#else
header.dwaCompressionLevel() = params[i + 1];
// See https://github.com/AcademySoftwareFoundation/openexr/blob/v3.3.5/src/lib/OpenEXR/ImfDwaCompressor.cpp#L85
header.dwaCompressionLevel() = std::max(params[i + 1], 0);
if(value < 0) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_EXR_DWA_COMPRESSION_LEVEL must be 0 or more. It is fallbacked to 0", value));
}
#endif
}
}
+20 -5
View File
@@ -554,6 +554,8 @@ GifEncoder::GifEncoder() {
colorNum = 256; // the number of colors in the color table, default 256
dithering = 0; // the level dithering, default 0
globalColorTableSize = 256, localColorTableSize = 0;
m_supported_encode_key = {IMWRITE_GIF_QUALITY, IMWRITE_GIF_DITHER, IMWRITE_GIF_TRANSPARENCY, IMWRITE_GIF_COLORTABLE};
}
GifEncoder::~GifEncoder() {
@@ -576,6 +578,7 @@ bool GifEncoder::writeanimation(const Animation& animation, const std::vector<in
// confirm the params
for (size_t i = 0; i < params.size(); i += 2) {
const int value = params[i+1];
switch (params[i]) {
case IMWRITE_GIF_LOOP:
CV_LOG_WARNING(NULL, "IMWRITE_GIF_LOOP is not functional since 4.12.0. Replaced by cv::Animation::loop_count.");
@@ -584,17 +587,26 @@ bool GifEncoder::writeanimation(const Animation& animation, const std::vector<in
CV_LOG_WARNING(NULL, "IMWRITE_GIF_SPEED is not functional since 4.12.0. Replaced by cv::Animation::durations.");
break;
case IMWRITE_GIF_DITHER:
dithering = std::min(std::max(params[i + 1], -1), 3);
dithering = std::min(std::max(value, -1), 3);
if(value != dithering) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_GIF_DITHER must be between -1 to 3. It is fallbacked to %d", value, dithering));
}
fast = false;
break;
case IMWRITE_GIF_TRANSPARENCY:
criticalTransparency = (uchar)std::min(std::max(params[i + 1], 0), 255);
criticalTransparency = (uchar)std::min(std::max(value, 0), 255);
if(value != criticalTransparency) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_GIF_TRANSPARENCY must be between 0 to 255. It is fallbacked to %d", value, criticalTransparency));
}
break;
case IMWRITE_GIF_COLORTABLE:
localColorTableSize = std::min(std::max(params[i + 1], 0), 1);
localColorTableSize = std::min(std::max(value, 0), 1);
if(value != localColorTableSize) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_GIF_COLORTABLE must be 0 or 1. It is fallbacked to %d", value, localColorTableSize));
}
break;
case IMWRITE_GIF_QUALITY:
switch (params[i + 1]) {
switch (value) {
case IMWRITE_GIF_FAST_FLOYD_DITHER:
fast = true;
dithering = GRFMT_GIF_FloydSteinberg;
@@ -604,10 +616,13 @@ bool GifEncoder::writeanimation(const Animation& animation, const std::vector<in
dithering = GRFMT_GIF_None;
break;
default:
lzwMinCodeSize = std::min(std::max(params[i + 1], 3), 8);
lzwMinCodeSize = std::min(std::max(value, 3), 8);
colorNum = 1 << lzwMinCodeSize;
globalColorTableSize = colorNum;
fast = false;
if(value != lzwMinCodeSize) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_GIF_QUALITY must be one of ImwriteGIFCompressionFlags. It is fallbacked to %d", value, lzwMinCodeSize));
}
break;
}
break; // case IMWRITE_GIF_QUALITY
+14 -1
View File
@@ -43,6 +43,7 @@
#include "precomp.hpp"
#include "grfmt_hdr.hpp"
#include "rgbe.hpp"
#include "opencv2/core/utils/logger.hpp"
#ifdef HAVE_IMGCODEC_HDR
@@ -139,6 +140,7 @@ ImageDecoder HdrDecoder::newDecoder() const
HdrEncoder::HdrEncoder()
{
m_description = "Radiance HDR (*.hdr;*.pic)";
m_supported_encode_key = {IMWRITE_HDR_COMPRESSION};
}
HdrEncoder::~HdrEncoder()
@@ -162,10 +164,21 @@ bool HdrEncoder::write( const Mat& input_img, const std::vector<int>& params )
int compression = IMWRITE_HDR_COMPRESSION_RLE;
for (size_t i = 0; i + 1 < params.size(); i += 2)
{
const int value = params[i+1];
switch (params[i])
{
case IMWRITE_HDR_COMPRESSION:
compression = params[i + 1];
switch(value)
{
case IMWRITE_HDR_COMPRESSION_NONE:
case IMWRITE_HDR_COMPRESSION_RLE:
compression = value;
break;
default:
compression = IMWRITE_HDR_COMPRESSION_RLE;
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_HDR_COMPRESSION must be one of ImwriteHDRCompressionFlags. It is fallbacked to IMWRITE_HDR_COMPRESSION_RLE", value));
break;
}
break;
default:
break;
+33 -11
View File
@@ -616,6 +616,7 @@ JpegEncoder::JpegEncoder()
m_support_metadata[(size_t)IMAGE_METADATA_EXIF] = true;
m_support_metadata[(size_t)IMAGE_METADATA_XMP] = true;
m_support_metadata[(size_t)IMAGE_METADATA_ICCP] = true;
m_supported_encode_key = {IMWRITE_JPEG_QUALITY, IMWRITE_JPEG_PROGRESSIVE, IMWRITE_JPEG_OPTIMIZE, IMWRITE_JPEG_RST_INTERVAL, IMWRITE_JPEG_LUMA_QUALITY, IMWRITE_JPEG_CHROMA_QUALITY, IMWRITE_JPEG_SAMPLING_FACTOR};
}
@@ -724,27 +725,39 @@ bool JpegEncoder::write( const Mat& img, const std::vector<int>& params )
for( size_t i = 0; i < params.size(); i += 2 )
{
const int value = params[i+1];
if( params[i] == IMWRITE_JPEG_QUALITY )
{
quality = params[i+1];
quality = MIN(MAX(quality, 0), 100);
quality = MIN(MAX(value, 0), 100);
if(value != quality) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_JPEG_QUALITY must be between 0 to 100. It is fallbacked to %d", value, quality));
}
}
if( params[i] == IMWRITE_JPEG_PROGRESSIVE )
{
progressive = params[i+1];
progressive = MIN(MAX(value,0), 1);
if(value != progressive) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_JPEG_PROGRESSIVE must be 0 or 1. It is fallbacked to %d", value, progressive));
}
}
if( params[i] == IMWRITE_JPEG_OPTIMIZE )
{
optimize = params[i+1];
optimize = MIN(MAX(value,0), 1);
if(value != optimize) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_JPEG_OPTIMIZE must be 0 or 1. It is fallbacked to %d", value, optimize));
}
}
if( params[i] == IMWRITE_JPEG_LUMA_QUALITY )
{
if (params[i+1] >= 0)
if (value >= 0)
{
luma_quality = MIN(MAX(params[i+1], 0), 100);
luma_quality = MIN(MAX(value, 0), 100);
if(value != luma_quality) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_JPEG_LUMA_QUALITY must be between 0 to 100. It is fallbacked to %d.", value, luma_quality));
}
quality = luma_quality;
@@ -752,6 +765,8 @@ bool JpegEncoder::write( const Mat& img, const std::vector<int>& params )
{
chroma_quality = luma_quality;
}
} else {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_JPEG_LUMA_QUALITY must be between 0 to 100. It is ignored.", value));
}
}
@@ -759,19 +774,26 @@ bool JpegEncoder::write( const Mat& img, const std::vector<int>& params )
{
if (params[i+1] >= 0)
{
chroma_quality = MIN(MAX(params[i+1], 0), 100);
chroma_quality = MIN(MAX(value, 0), 100);
if(value != chroma_quality) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_JPEG_CHROMA_QUALITY must be between 0 to 100. It is fallbacked to %d.", value, chroma_quality));
}
} else {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_JPEG_CHROMA_QUALITY must be between 0 to 100. It is ignored.", value));
}
}
if( params[i] == IMWRITE_JPEG_RST_INTERVAL )
{
rst_interval = params[i+1];
rst_interval = MIN(MAX(rst_interval, 0), 65535L);
rst_interval = MIN(MAX(value, 0), 65535L);
if(value != rst_interval) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_JPEG_RST_INTERVAL must be between 0 to 65535. It is fallbacked to %d.", value, rst_interval));
}
}
if( params[i] == IMWRITE_JPEG_SAMPLING_FACTOR )
{
sampling_factor = static_cast<uint32_t>(params[i+1]);
sampling_factor = static_cast<uint32_t>(value);
switch ( sampling_factor )
{
@@ -784,7 +806,7 @@ bool JpegEncoder::write( const Mat& img, const std::vector<int>& params )
break;
default:
CV_LOG_WARNING(NULL, cv::format("Unknown value for IMWRITE_JPEG_SAMPLING_FACTOR: 0x%06x", sampling_factor ) );
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_JPEG_SAMPLING_FACTOR must be one of ImwriteJPEGSamplingFactorParams. It is fallbacked to IMWRITE_JPEG_SAMPLING_FACTOR_420.", value));
sampling_factor = 0;
break;
}
+9 -1
View File
@@ -493,6 +493,7 @@ bool Jpeg2KDecoder::readComponent16u( unsigned short *data, void *_buffer,
Jpeg2KEncoder::Jpeg2KEncoder()
{
m_description = "JPEG-2000 files (*.jp2)";
m_supported_encode_key = {IMWRITE_JPEG2000_COMPRESSION_X1000};
}
@@ -526,10 +527,17 @@ bool Jpeg2KEncoder::write( const Mat& _img, const std::vector<int>& params )
double target_compression_rate = 1.0;
for( size_t i = 0; i < params.size(); i += 2 )
{
const int value = params[i+1];
switch(params[i])
{
case cv::IMWRITE_JPEG2000_COMPRESSION_X1000:
target_compression_rate = std::min(std::max(params[i+1], 0), 1000) / 1000.0;
{
const int compression = std::min(std::max(value, 0), 1000);
target_compression_rate = static_cast<double>(compression) / 1000.0;
if(value != compression){
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_JPEG2000_COMPRESSION_X1000 must be between 0 to 1000. It is fallbacked to %d", value, compression));
}
}
break;
}
}
@@ -330,14 +330,20 @@ opj_cparameters setupEncoderParameters(const std::vector<int>& params)
bool rate_is_specified = false;
for (size_t i = 0; i < params.size(); i += 2)
{
const int value = params[i + 1];
switch (params[i])
{
case cv::IMWRITE_JPEG2000_COMPRESSION_X1000:
parameters.tcp_rates[0] = 1000.f / std::min(std::max(params[i + 1], 1), 1000);
rate_is_specified = true;
{
const int compression = std::min(std::max(value, 1), 1000);
parameters.tcp_rates[0] = 1000.f / static_cast<float>(compression);
if(value != compression) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_JPEG2000_COMPRESSION_X1000 must be between 1 to 1000. It is fallbacked to 1", value));
}
rate_is_specified = true;
}
break;
default:
CV_LOG_WARNING(NULL, "OpenJPEG2000(encoder): skip unsupported parameter: " << params[i]);
break;
}
}
@@ -685,6 +691,7 @@ ImageDecoder Jpeg2KJ2KOpjDecoder::newDecoder() const
Jpeg2KOpjEncoder::Jpeg2KOpjEncoder()
{
m_description = "JPEG-2000 files (*.jp2)";
m_supported_encode_key = {IMWRITE_JPEG2000_COMPRESSION_X1000};
}
ImageEncoder Jpeg2KOpjEncoder::newEncoder() const
+10 -4
View File
@@ -473,6 +473,7 @@ JpegXLEncoder::JpegXLEncoder()
{
m_description = "JPEG XL files (*.jxl)";
m_buf_supported = true;
m_supported_encode_key = {IMWRITE_JPEGXL_QUALITY, IMWRITE_JPEGXL_EFFORT, IMWRITE_JPEGXL_DISTANCE, IMWRITE_JPEGXL_DECODING_SPEED};
}
JpegXLEncoder::~JpegXLEncoder()
@@ -522,11 +523,14 @@ bool JpegXLEncoder::write(const Mat& img, const std::vector<int>& params)
float distance = -1.0; // Negative means not set
for( size_t i = 0; i < params.size(); i += 2 )
{
const int value = params[i+1];
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 int quality = MIN(MAX(value, 0), 100);
if(value != quality) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_JPEGXL_QUALITY must be between 0 to 100, It is fallbacked to %d", value, quality));
}
distance = JxlEncoderDistanceFromQuality(static_cast<float>(quality));
#else
CV_LOG_ONCE_WARNING(NULL, "Quality parameter is supported with libjxl v0.10.0 or later");
@@ -534,8 +538,10 @@ bool JpegXLEncoder::write(const Mat& img, const std::vector<int>& params)
}
if( params[i] == IMWRITE_JPEGXL_DISTANCE )
{
int distanceInt = params[i+1];
distanceInt = MIN(MAX(distanceInt, 0), 25);
const int distanceInt = MIN(MAX(value, 0), 25);
if(value != distanceInt) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_JPEGXL_DISTANCE must be between 0 to 25, It is fallbacked to %d", value, distanceInt));
}
distance = static_cast<float>(distanceInt);
}
}
+19 -4
View File
@@ -55,6 +55,7 @@
#include "utils.hpp"
#include "grfmt_pam.hpp"
#include "opencv2/core/utils/logger.hpp"
namespace cv {
@@ -657,6 +658,7 @@ PAMEncoder::PAMEncoder()
{
m_description = "Portable arbitrary format (*.pam)";
m_buf_supported = true;
m_supported_encode_key = {IMWRITE_PAM_TUPLETYPE};
}
@@ -689,12 +691,25 @@ bool PAMEncoder::write( const Mat& img, const std::vector<int>& params )
int x, y, tmp, bufsize = 256;
/* parse save file type */
for( size_t i = 0; i < params.size(); i += 2 )
for( size_t i = 0; i < params.size(); i += 2 ) {
const int value = params[i+1];
if( params[i] == IMWRITE_PAM_TUPLETYPE ) {
if ( params[i+1] > IMWRITE_PAM_FORMAT_NULL &&
params[i+1] < (int) PAM_FORMATS_NO)
fmt = &formats[params[i+1]];
switch(value) {
case IMWRITE_PAM_FORMAT_NULL:
case IMWRITE_PAM_FORMAT_BLACKANDWHITE:
case IMWRITE_PAM_FORMAT_GRAYSCALE:
case IMWRITE_PAM_FORMAT_GRAYSCALE_ALPHA:
case IMWRITE_PAM_FORMAT_RGB:
case IMWRITE_PAM_FORMAT_RGB_ALPHA:
fmt = &formats[value];
break;
default:
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PAM_TUPLETYPE must be one of ImwritePAMFlags. It is ignored", value));
fmt = nullptr;
break;
}
}
}
if( m_buf )
{
+49 -8
View File
@@ -913,6 +913,7 @@ PngEncoder::PngEncoder()
memset(palette, 0, sizeof(palette));
memset(trns, 0, sizeof(trns));
memset(op, 0, sizeof(op));
m_supported_encode_key = {IMWRITE_PNG_COMPRESSION, IMWRITE_PNG_STRATEGY, IMWRITE_PNG_BILEVEL, IMWRITE_PNG_FILTER, IMWRITE_PNG_ZLIBBUFFER_SIZE};
}
PngEncoder::~PngEncoder()
@@ -983,26 +984,61 @@ bool PngEncoder::write( const Mat& img, const std::vector<int>& params )
for( size_t i = 0; i < params.size(); i += 2 )
{
const int value = params[i+1];
switch (params[i])
{
case IMWRITE_PNG_COMPRESSION:
m_compression_strategy = IMWRITE_PNG_STRATEGY_DEFAULT; // Default strategy
m_compression_level = params[i+1];
m_compression_level = MIN(MAX(m_compression_level, 0), Z_BEST_COMPRESSION);
m_compression_level = MIN(MAX(value, 0), Z_BEST_COMPRESSION);
if(value != m_compression_level) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_COMPRESSION must be between 0 to 9. It is fallbacked to %d", value, m_compression_level));
}
set_compression_level = true;
break;
case IMWRITE_PNG_STRATEGY:
m_compression_strategy = params[i+1];
m_compression_strategy = MIN(MAX(m_compression_strategy, 0), Z_FIXED);
{
switch(value) {
case IMWRITE_PNG_STRATEGY_DEFAULT:
case IMWRITE_PNG_STRATEGY_FILTERED:
case IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY:
case IMWRITE_PNG_STRATEGY_RLE:
case IMWRITE_PNG_STRATEGY_FIXED:
m_compression_strategy = value;
break;
default:
m_compression_strategy = IMWRITE_PNG_STRATEGY_RLE;
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_STRATEGY must be one of ImwritePNGFlags. It is fallbacked to IMWRITE_PNG_STRATEGY_RLE", value));
break;
}
}
break;
case IMWRITE_PNG_BILEVEL:
m_isBilevel = params[i+1] != 0;
m_isBilevel = value != 0;
if((value != 0) && (value != 1)) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_BILEVEL must be 0 or 1. It is fallbacked to 1", value ));
}
break;
case IMWRITE_PNG_FILTER:
m_filter = params[i+1];
{
switch(value) {
case IMWRITE_PNG_FILTER_NONE:
case IMWRITE_PNG_FILTER_SUB:
case IMWRITE_PNG_FILTER_UP:
case IMWRITE_PNG_FILTER_AVG:
case IMWRITE_PNG_FILTER_PAETH:
case IMWRITE_PNG_FAST_FILTERS:
case IMWRITE_PNG_ALL_FILTERS:
m_filter = value;
break;
default:
m_filter = IMWRITE_PNG_FILTER_SUB;
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_FILTER must be one of ImwritePNGFilterFlags. It is fallbacked to IMWRITE_PNG_FILTER_SUB", value ));
break;
}
}
set_filter = true;
break;
@@ -1011,11 +1047,16 @@ bool PngEncoder::write( const Mat& img, const std::vector<int>& params )
// The minimum limit is 6, which is from from https://github.com/opencv/opencv/blob/4.12.0/3rdparty/libpng/pngset.c#L1600 .
// The maximum limit is 1 MiB, which has been provisionally set. libpng limitation is 2 GiB(INT32_MAX), but it is too large.
// For normal use, 128 or 256 KiB may be sufficient. See https://zlib.net/zlib_how.html .
png_set_compression_buffer_size(png_ptr, MIN(MAX(params[i+1],6), 1024*1024));
{
const int zlen = MIN(MAX(value, 6), 1024*1024);
if(value != zlen) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_ZLIBBUFFER_SIZE must be between 6 to 1024*1024. It is fallbacked to %d", value , zlen));
}
png_set_compression_buffer_size(png_ptr, zlen);
}
break;
default:
CV_LOG_WARNING(NULL, "An unknown or unsupported ImwriteFlags value was specified and has been ignored.");
break;
}
}
+8 -1
View File
@@ -389,6 +389,7 @@ PxMEncoder::PxMEncoder(PxMMode mode) :
CV_Error(Error::StsInternal, "");
}
m_buf_supported = true;
m_supported_encode_key = {IMWRITE_PXM_BINARY};
}
PxMEncoder::~PxMEncoder()
@@ -414,8 +415,14 @@ bool PxMEncoder::write(const Mat& img, const std::vector<int>& params)
for( size_t i = 0; i < params.size(); i += 2 )
{
const int value = params[i+1];
if( params[i] == IMWRITE_PXM_BINARY )
isBinary = params[i+1] != 0;
{
isBinary = value != 0;
if((value != 0) && (value != 1)) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PXM_BINARY must be 0 or 1. It is fallbacked to 1", value));
}
}
}
int mode = mode_;
+38 -6
View File
@@ -482,6 +482,7 @@ SPngEncoder::SPngEncoder()
m_support_metadata[IMAGE_METADATA_EXIF] = true;
m_support_metadata[IMAGE_METADATA_XMP] = true;
m_support_metadata[IMAGE_METADATA_ICCP] = true;
m_supported_encode_key = {IMWRITE_PNG_COMPRESSION, IMWRITE_PNG_STRATEGY, IMWRITE_PNG_BILEVEL, IMWRITE_PNG_FILTER, IMWRITE_PNG_ZLIBBUFFER_SIZE};
}
SPngEncoder::~SPngEncoder()
@@ -534,25 +535,56 @@ bool SPngEncoder::write(const Mat &img, const std::vector<int> &params)
for (size_t i = 0; i < params.size(); i += 2)
{
const int value = params[i+1];
if (params[i] == IMWRITE_PNG_COMPRESSION)
{
compression_strategy = IMWRITE_PNG_STRATEGY_DEFAULT; // Default strategy
compression_level = params[i + 1];
compression_level = MIN(MAX(compression_level, 0), Z_BEST_COMPRESSION);
compression_level = MIN(MAX(value, 0), Z_BEST_COMPRESSION);
if(value != m_compression_level) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_COMPRESSION must be between 0 to 9. It is fallbacked to %d", value, m_compression_level));
}
set_compression_level = true;
}
if (params[i] == IMWRITE_PNG_STRATEGY)
{
compression_strategy = params[i + 1];
compression_strategy = MIN(MAX(compression_strategy, 0), Z_FIXED);
switch(value) {
case IMWRITE_PNG_STRATEGY_DEFAULT:
case IMWRITE_PNG_STRATEGY_FILTERED:
case IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY:
case IMWRITE_PNG_STRATEGY_RLE:
case IMWRITE_PNG_STRATEGY_FIXED:
compression_strategy = value;
break;
default:
compression_strategy = IMWRITE_PNG_STRATEGY_RLE:
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_STRATEGY must be one of ImwritePNGFlags. It is fallbacked to IMWRITE_PNG_STRATEGY_RLE", value));
break;
}
}
if (params[i] == IMWRITE_PNG_BILEVEL)
{
isBilevel = params[i + 1] != 0;
isBilevel = value != 0;
if((value != 0) && (value != 1)) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_BILEVEL must be 0 or 1. It is fallbacked to 1", value ));
}
}
if( params[i] == IMWRITE_PNG_FILTER )
{
filter = params[i+1];
switch(value) {
case IMWRITE_PNG_FILTER_NONE:
case IMWRITE_PNG_FILTER_SUB:
case IMWRITE_PNG_FILTER_UP:
case IMWRITE_PNG_FILTER_AVG:
case IMWRITE_PNG_FILTER_PAETH:
case IMWRITE_PNG_FAST_FILTERS:
case IMWRITE_PNG_ALL_FILTERS:
filter = value;
break;
default:
filter = IMWRITE_PNG_FILTER_SUB;
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_FILTER must be one of ImwritePNGFilterFlags. It is fallbacked to IMWRITE_PNG_FILTER_SUB", value ));
break;
}
set_filter = true;
}
if( params[i] == IMWRITE_PNG_ZLIBBUFFER_SIZE )
+86 -9
View File
@@ -1090,6 +1090,7 @@ TiffEncoder::TiffEncoder()
{
m_description = "TIFF Files (*.tiff;*.tif)";
m_buf_supported = true;
m_supported_encode_key = {IMWRITE_TIFF_RESUNIT, IMWRITE_TIFF_XDPI, IMWRITE_TIFF_YDPI, IMWRITE_TIFF_COMPRESSION, IMWRITE_TIFF_ROWSPERSTRIP, IMWRITE_TIFF_PREDICTOR};
}
TiffEncoder::~TiffEncoder()
@@ -1229,15 +1230,92 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
cv::Ptr<void> tif_cleanup(tif, cv_tiffCloseHandle);
//Settings that matter to all images
int compression = COMPRESSION_LZW;
int predictor = PREDICTOR_HORIZONTAL;
int compression = IMWRITE_TIFF_COMPRESSION_LZW;
int predictor = IMWRITE_TIFF_PREDICTOR_HORIZONTAL;
int resUnit = -1, dpiX = -1, dpiY = -1;
readParam(params, IMWRITE_TIFF_COMPRESSION, compression);
readParam(params, IMWRITE_TIFF_PREDICTOR, predictor);
readParam(params, IMWRITE_TIFF_RESUNIT, resUnit);
readParam(params, IMWRITE_TIFF_XDPI, dpiX);
readParam(params, IMWRITE_TIFF_YDPI, dpiY);
if(readParam(params, IMWRITE_TIFF_COMPRESSION, compression))
{
switch(compression) {
case IMWRITE_TIFF_COMPRESSION_NONE:
case IMWRITE_TIFF_COMPRESSION_CCITTRLE:
case IMWRITE_TIFF_COMPRESSION_CCITTFAX3: // IMWRITE_TIFF_COMPRESSION_CCITT_T4:
case IMWRITE_TIFF_COMPRESSION_CCITTFAX4: // IMWRITE_TIFF_COMPRESSION_CCITT_T6:
case IMWRITE_TIFF_COMPRESSION_LZW:
case IMWRITE_TIFF_COMPRESSION_OJPEG:
case IMWRITE_TIFF_COMPRESSION_JPEG:
case IMWRITE_TIFF_COMPRESSION_T85:
case IMWRITE_TIFF_COMPRESSION_T43:
case IMWRITE_TIFF_COMPRESSION_NEXT:
case IMWRITE_TIFF_COMPRESSION_CCITTRLEW:
case IMWRITE_TIFF_COMPRESSION_PACKBITS:
case IMWRITE_TIFF_COMPRESSION_THUNDERSCAN:
case IMWRITE_TIFF_COMPRESSION_IT8CTPAD:
case IMWRITE_TIFF_COMPRESSION_IT8LW:
case IMWRITE_TIFF_COMPRESSION_IT8MP:
case IMWRITE_TIFF_COMPRESSION_IT8BL:
case IMWRITE_TIFF_COMPRESSION_PIXARFILM:
case IMWRITE_TIFF_COMPRESSION_PIXARLOG:
case IMWRITE_TIFF_COMPRESSION_DEFLATE:
case IMWRITE_TIFF_COMPRESSION_ADOBE_DEFLATE:
case IMWRITE_TIFF_COMPRESSION_DCS:
case IMWRITE_TIFF_COMPRESSION_JBIG:
case IMWRITE_TIFF_COMPRESSION_SGILOG:
case IMWRITE_TIFF_COMPRESSION_SGILOG24:
case IMWRITE_TIFF_COMPRESSION_JP2000:
case IMWRITE_TIFF_COMPRESSION_LERC:
case IMWRITE_TIFF_COMPRESSION_LZMA:
case IMWRITE_TIFF_COMPRESSION_ZSTD:
case IMWRITE_TIFF_COMPRESSION_WEBP:
case IMWRITE_TIFF_COMPRESSION_JXL:
break;
default:
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_TIFF_COMPRESSION must be one of ImwriteTiffCompressionFlags. It is fallbacked to IMWRITE_TIFF_COMPRESSION_LZW", compression));
compression = IMWRITE_TIFF_COMPRESSION_LZW;
break;
}
}
if(readParam(params, IMWRITE_TIFF_PREDICTOR, predictor))
{
switch(predictor) {
case IMWRITE_TIFF_PREDICTOR_NONE:
case IMWRITE_TIFF_PREDICTOR_HORIZONTAL:
case IMWRITE_TIFF_PREDICTOR_FLOATINGPOINT:
break;
default:
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_TIFF_PREDICTOR must be one of ImwriteTiffPredictorFlags. It is fallbacked to IMWRITE_TIFF_PREDICTOR_HORIZONTAL", predictor));
predictor = IMWRITE_TIFF_PREDICTOR_HORIZONTAL;
break;
}
}
if(readParam(params, IMWRITE_TIFF_RESUNIT, resUnit))
{
switch(resUnit) {
case IMWRITE_TIFF_RESOLUTION_UNIT_NONE:
case IMWRITE_TIFF_RESOLUTION_UNIT_INCH:
case IMWRITE_TIFF_RESOLUTION_UNIT_CENTIMETER:
break;
default:
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_TIFF_RESUNIT must be one of ImwriteTiffResolutionUnitFlags. It is fallbacked to IMWRITE_TIFF_RESOLUTION_UNIT_INCH", resUnit));
resUnit = IMWRITE_TIFF_RESOLUTION_UNIT_INCH;
break;
}
}
if(readParam(params, IMWRITE_TIFF_XDPI, dpiX))
{
if(dpiX <= 0) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_TIFF_XDPI must be positive. It is ignored.", dpiX));
dpiX = -1;
}
}
if(readParam(params, IMWRITE_TIFF_YDPI, dpiY))
{
if(dpiY <= 0) {
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_TIFF_YDPI must be positive. It is ignored.", dpiX));
dpiY = -1;
}
}
//Iterate through each image in the vector and write them out as Tiff directories
for (size_t page = 0; page < img_vec.size(); page++)
@@ -1260,8 +1338,7 @@ bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vect
CV_TIFF_CHECK_CALL(TIFFSetField(tif, TIFFTAG_PAGENUMBER, page, img_vec.size()));
}
int compression_param = -1; // OPENCV_FUTURE
if (type == CV_32FC3 && (!readParam(params, IMWRITE_TIFF_COMPRESSION, compression_param) || compression_param == COMPRESSION_SGILOG))
if (type == CV_32FC3 && compression == COMPRESSION_SGILOG)
{
if (!write_32FC3_SGILOG(img, tif))
return false;
+6 -3
View File
@@ -338,6 +338,7 @@ WebPEncoder::WebPEncoder()
m_support_metadata[IMAGE_METADATA_EXIF] = true;
m_support_metadata[IMAGE_METADATA_XMP] = true;
m_support_metadata[IMAGE_METADATA_ICCP] = true;
m_supported_encode_key = {IMWRITE_WEBP_QUALITY};
}
WebPEncoder::~WebPEncoder() { }
@@ -356,15 +357,17 @@ bool WebPEncoder::write(const Mat& img, const std::vector<int>& params)
bool comp_lossless = true;
float quality = 100.0f;
if (params.size() > 1)
for(size_t i = 0; i < params.size(); i += 2)
{
if (params[0] == IMWRITE_WEBP_QUALITY)
const int value = params[i+1];
if (params[i] == IMWRITE_WEBP_QUALITY)
{
comp_lossless = false;
quality = static_cast<float>(params[1]);
quality = static_cast<float>(value);
if (quality < 1.0f)
{
quality = 1.0f;
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_WEBP_QUALITY must be between 1 to 100(lossy) or more(lossless). It is fallbacked to 1", value));
}
if (quality > 100.0f)
{
+55
View File
@@ -364,6 +364,20 @@ static ImageEncoder findEncoder( const String& _ext )
return ImageEncoder();
}
static bool isValidEncodeKeyAtAll(const int key)
{
bool ret = false;
ImageCodecInitializer& codecs = getCodecs();
for( size_t i = 0; i < codecs.encoders.size(); i++ )
{
if( codecs.encoders[i]->isValidEncodeKey(key) == true )
{
ret = true;
break;
}
}
return ret;
}
static void ExifTransform(int orientation, OutputArray img)
{
@@ -1091,6 +1105,27 @@ static bool imwrite_( const String& filename, const std::vector<Mat>& img_vec,
CV_Check(params.size(), (params.size() & 1) == 0, "Encoding 'params' must be key-value pairs");
CV_CheckLE(params.size(), (size_t)(CV_IO_MAX_IMAGE_PARAMS*2), "");
for(size_t v = 0; v < params.size(); v+= 2)
{
const int key = params[v];
if(encoder->isValidEncodeKey(key))
{
// Current encoder supports specified key.
// Do nothing.
}
else if(isValidEncodeKeyAtAll(key))
{
// Current encoder does not support specified key, but some encoder supports it.
CV_LOG_WARNING(nullptr, cv::format("An unsupported key(%d) was specified and has been ignored.", key));
}
else
{
// No encoder supports specified key.
CV_LOG_WARNING(nullptr, cv::format("An unknown key(%d) was specified and has been ignored.", key));
}
}
bool code = false;
try
{
@@ -1625,6 +1660,26 @@ bool imencodeWithMetadata( const String& ext, InputArray _img,
CV_Check(params.size(), (params.size() & 1) == 0, "Encoding 'params' must be key-value pairs");
CV_CheckLE(params.size(), (size_t)(CV_IO_MAX_IMAGE_PARAMS*2), "");
for(size_t v = 0; v < params.size(); v+= 2)
{
const int key = params[v];
if(encoder->isValidEncodeKey(key))
{
// Current encoder supports specified key.
// Do nothing.
}
else if(isValidEncodeKeyAtAll(key))
{
// Current encoder does not support specified key, but some encoder supports it.
CV_LOG_WARNING(nullptr, cv::format("An unsupported key(%d) was specified and has been ignored.", key));
}
else
{
// No encoder supports specified key.
CV_LOG_WARNING(nullptr, cv::format("An unknown key(%d) was specified and has been ignored.", key));
}
}
bool code = false;
String filename;
if( !encoder->setDestination(buf) )
-11
View File
@@ -128,12 +128,6 @@ TEST_P(Imgcodecs_Avif_Image_WriteReadSuite, imwrite_imread) {
// Encode.
const string output = cv::tempfile(".avif");
if (!IsBitDepthValid()) {
EXPECT_NO_FATAL_FAILURE(
cv::imwrite(output, img_original, encoding_params_));
EXPECT_NE(0, remove(output.c_str()));
return;
}
EXPECT_NO_THROW(cv::imwrite(output, img_original, encoding_params_));
// Read from file.
@@ -164,11 +158,6 @@ TEST_P(Imgcodecs_Avif_Image_EncodeDecodeSuite, imencode_imdecode) {
bool result = true;
EXPECT_NO_THROW(
result = cv::imencode(".avif", img_original, buf, encoding_params_););
if (!IsBitDepthValid()) {
EXPECT_FALSE(result);
return;
}
EXPECT_TRUE(result);
// Read back.
+7 -11
View File
@@ -257,20 +257,16 @@ TEST(Imgcodecs_Gif, read_gif_special){
}
TEST(Imgcodecs_Gif,write_gif_flags){
const string root = cvtest::TS::ptr()->get_data_path();
const string png_filename = root + "gifsuite/special1.png";
vector<uchar> buff;
const int expected_rows=611;
const int expected_cols=293;
Mat img_gt = Mat::ones(expected_rows, expected_cols, CV_8UC1);
vector<int> param;
param.push_back(IMWRITE_GIF_QUALITY);
param.push_back(7);
param.push_back(IMWRITE_GIF_DITHER);
param.push_back(2);
EXPECT_NO_THROW(imencode(".png", img_gt, buff, param));
Mat img_gt = Mat::ones(expected_rows, expected_cols, CV_8UC3);
const vector<int> param = { IMWRITE_GIF_QUALITY, IMWRITE_GIF_FAST_NO_DITHER, IMWRITE_GIF_DITHER, 3};
bool ret = false;
EXPECT_NO_THROW(ret = imencode(".gif", img_gt, buff, param));
EXPECT_TRUE(ret);
Mat img;
EXPECT_NO_THROW(img = imdecode(buff, IMREAD_ANYDEPTH)); // hang
EXPECT_NO_THROW(img = imdecode(buff, IMREAD_COLOR));
EXPECT_FALSE(img.empty());
EXPECT_EQ(img.cols, expected_cols);
EXPECT_EQ(img.rows, expected_rows);
@@ -280,7 +276,7 @@ TEST(Imgcodecs_Gif,write_gif_flags){
TEST(Imgcodecs_Gif, write_gif_big) {
const string root = cvtest::TS::ptr()->get_data_path();
const string png_filename = root + "gifsuite/gif_big.png";
const string gif_filename = cv::tempfile(".png");
const string gif_filename = cv::tempfile(".gif");
cv::Mat img;
ASSERT_NO_THROW(img = cv::imread(png_filename, IMREAD_UNCHANGED));
ASSERT_FALSE(img.empty());
+34
View File
@@ -166,6 +166,8 @@ TEST_P(Imgcodecs_ExtSize, write_imageseq)
continue;
if (cn == 1 && ext == ".gif")
continue;
if (cn == 1 && ext == ".webp")
continue;
string filename = cv::tempfile(format("%d%s", cn, ext.c_str()).c_str());
Mat img_gt(size, CV_MAKETYPE(CV_8U, cn), Scalar::all(0));
@@ -257,6 +259,9 @@ const string all_exts[] =
#ifdef HAVE_IMGCODEC_GIF
".gif",
#endif
#ifdef HAVE_WEBP
".webp",
#endif
};
vector<Size> all_sizes()
@@ -307,6 +312,35 @@ TEST_P(Imgcodecs_pbm, write_read)
INSTANTIATE_TEST_CASE_P(All, Imgcodecs_pbm, testing::Bool());
#endif
// See https://github.com/opencv/opencv/issues/27557
typedef testing::TestWithParam<string> Imgcodecs_invalid_key;
TEST_P(Imgcodecs_invalid_key, encode_regression27557)
{
const string ext = GetParam();
const int matType = ((ext == ".pbm") || (ext == ".pgm"))? CV_8UC1 : CV_8UC3;
Mat src(100, 100, matType, Scalar(0, 255, 0));
std::vector<uchar> buf;
bool status = false;
EXPECT_NO_THROW(status = imencode(ext, src, buf, { -1, -1 }));
EXPECT_TRUE(status);
}
TEST_P(Imgcodecs_invalid_key, write_regression27557)
{
const string ext = GetParam();
string fname = tempfile(ext.c_str());
const int matType = ((ext == ".pbm") || (ext == ".pgm"))? CV_8UC1 : CV_8UC3;
Mat src(100, 100, matType, Scalar(0, 255, 0));
std::vector<uchar> buf;
bool status = false;
EXPECT_NO_THROW(status = imwrite(fname, src, { -1, -1 }));
EXPECT_TRUE(status);
remove(fname.c_str());
}
INSTANTIATE_TEST_CASE_P(All, Imgcodecs_invalid_key, testing::ValuesIn(all_exts));
//==================================================================================================
+1 -1
View File
@@ -72,7 +72,7 @@ TEST(Imgcodecs_WebP, encode_decode_lossy_webp)
{
std::vector<int> params;
params.push_back(IMWRITE_WEBP_QUALITY);
params.push_back(q);
params.push_back(MAX(q,1));
string output = cv::tempfile(".webp");
EXPECT_NO_THROW(cv::imwrite(output, img, params));
@@ -13,6 +13,7 @@
// Copyright (C) 2000-2008, 2018, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Copyright (C) 2014-2015, Itseez Inc., all rights reserved.
// Copyright (C) 2025, Advanced Micro Devices, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
@@ -174,8 +175,8 @@ bilateralFilter_8u( const Mat& src, Mat& dst, int d,
return;
}
double gauss_color_coeff = -0.5/(sigma_color*sigma_color);
double gauss_space_coeff = -0.5/(sigma_space*sigma_space);
float gauss_color_coeff = (float)(-0.5/(sigma_color*sigma_color));
float gauss_space_coeff = (float)(-0.5/(sigma_space*sigma_space));
if( d <= 0 )
radius = cvRound(sigma_space*1.5);
@@ -195,15 +196,31 @@ bilateralFilter_8u( const Mat& src, Mat& dst, int d,
int* space_ofs = &_space_ofs[0];
// initialize color-related bilateral filter coefficients
i = 0;
#if (CV_SIMD || CV_SIMD_SCALABLE)
int nlanes = VTraits<v_float32>::vlanes();
v_float32 v_gauss_color_coeff = vx_setall_f32(gauss_color_coeff);
float counter[16] = {0.0, 1., 2., 3., 4., 5., 6., 7.,
8., 9., 10., 11., 12., 13., 14., 15.};
v_float32 v_i = vx_load(counter);
v_float32 v_inc = vx_setall_f32(float(nlanes));
for( i = 0; i < 256*cn; i++ )
for( ; i < (256*cn) - nlanes; i += nlanes )
{
v_float32 v_color_weight = v_mul(v_mul(v_i,v_i), v_gauss_color_coeff);
v_store(color_weight + i, v_exp(v_color_weight));
v_i = v_add(v_i, v_inc);
}
#endif
for(; i < 256*cn; i++ )
{
color_weight[i] = (float)std::exp(i*i*gauss_color_coeff);
}
// initialize space-related bilateral filter coefficients
for( i = -radius, maxk = 0; i <= radius; i++ )
{
j = -radius;
for( ; j <= radius; j++ )
{
double r = std::sqrt((double)i*i + (double)j*j);
File diff suppressed because it is too large Load Diff
+10 -4
View File
@@ -2035,9 +2035,12 @@ void fillPoly( InputOutputArray _img, const Point** pts, const int* npts, int nc
edges.reserve( total + 1 );
for (i = 0; i < ncontours; i++)
{
if (npts[i] > 0 && pts[i])
const Point* currentContour = pts[i];
const int currentContourLength = npts[i];
if ( (currentContourLength > 0) && currentContour )
{
std::vector<Point2l> _pts(pts[i], pts[i] + npts[i]);
AutoBuffer<Point2l> _pts(currentContourLength);
std::copy(currentContour, currentContour+currentContourLength, _pts.data());
CollectPolyEdges(img, _pts.data(), npts[i], edges, buf, line_type, shift, offset);
}
}
@@ -2064,8 +2067,11 @@ void polylines( InputOutputArray _img, const Point* const* pts, const int* npts,
for( int i = 0; i < ncontours; i++ )
{
std::vector<Point2l> _pts(pts[i], pts[i]+npts[i]);
PolyLine( img, _pts.data(), npts[i], isClosed, buf, thickness, line_type, shift );
const Point* currentContour = pts[i];
const int currentContourLength = npts[i];
AutoBuffer<Point2l> _pts(currentContourLength);
std::copy(currentContour, currentContour+currentContourLength, _pts.data());
PolyLine( img, _pts.data(), currentContourLength, isClosed, buf, thickness, line_type, shift );
}
}
+1
View File
@@ -3,3 +3,4 @@ Specification-Version: @OPENCV_VERSION@
Implementation-Title: OpenCV
Implementation-Version: @OPENCV_VCSVERSION@
Implementation-Date: @OPENCV_TIMESTAMP@
Automatic-Module-Name: org.opencv
+1
View File
@@ -24,6 +24,7 @@
<attribute name="Implementation-Title" value="OpenCV"/>
<attribute name="Implementation-Version" value="@OPENCV_VCSVERSION@"/>
<attribute name="Implementation-Date" value="${timestamp}"/>
<attribute name="Automatic-Module-Name" value="org.opencv"/>
</manifest>
</jar>
</target>
+13
View File
@@ -397,3 +397,16 @@ Module['matFromImageData'] = function(imageData) {
mat.data.set(imageData.data);
return mat;
};
// Add Symbol.dispose support for using declaration in TypeScript 5.2+ and future JS
if (
typeof Symbol !== "undefined" &&
Symbol.dispose &&
typeof cv !== "undefined" &&
cv.Mat &&
typeof cv.Mat.prototype.delete === "function"
) {
cv.Mat.prototype[Symbol.dispose] = cv.Mat.prototype.delete;
// Optionally repeat for other types that require manual cleanup:
if (cv.UMat) cv.UMat.prototype[Symbol.dispose] = cv.UMat.prototype.delete;
// Add more as OpenCV gains new manual-cleanup classes
}
+1 -1
View File
@@ -30,7 +30,7 @@ public:
virtual bool grabFrame() CV_OVERRIDE;
virtual bool retrieveFrame(int outputType, OutputArray frame) CV_OVERRIDE;
virtual int getCaptureDomain() CV_OVERRIDE;
virtual bool isOpened() const;
virtual bool isOpened() const CV_OVERRIDE;
protected:
void open(int index);
void close();
+1 -5
View File
@@ -389,12 +389,8 @@ void CvVideoWriter_Images::write(InputArray image)
cv::String filename = cv::format(filename_pattern.c_str(), (int)currentframe);
CV_Assert(!filename.empty());
std::vector<int> image_params = params;
image_params.push_back(0); // append parameters 'stop' mark
image_params.push_back(0);
cv::Mat img = image.getMat();
cv::imwrite(filename, img, image_params);
cv::imwrite(filename, img);
currentframe++;
}