mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 23:33:05 +04:00
Compare commits
9 Commits
0e09f1a238
...
4.x
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b6c3df954 | |||
| a906dfbed2 | |||
| b7860407f0 | |||
| dee2bb288b | |||
| 70fc346580 | |||
| 664f59e750 | |||
| 19ef7e6e16 | |||
| c8446af29a | |||
| 5ab3e2e580 |
@@ -7,7 +7,7 @@
|
||||
* Courses: <https://opencv.org/courses>
|
||||
* Docs: <https://docs.opencv.org/4.x/>
|
||||
* Q&A forum: <https://forum.opencv.org>
|
||||
* previous forum (read only): <http://answers.opencv.org>
|
||||
* previous forum (read only): <https://answers.opencv.org>
|
||||
* Issue tracking: <https://github.com/opencv/opencv/issues>
|
||||
* Additional OpenCV functionality: <https://github.com/opencv/opencv_contrib>
|
||||
* Donate to OpenCV: <https://opencv.org/support/>
|
||||
@@ -28,9 +28,9 @@ Please read the [contribution guidelines](https://github.com/opencv/opencv/wiki/
|
||||
### Additional Resources
|
||||
|
||||
* [Submit your OpenCV-based project](https://form.jotform.com/233105358823151) for inclusion in Community Friday on opencv.org
|
||||
* [Subscribe to the OpenCV YouTube Channel](http://youtube.com/@opencvofficial) featuring OpenCV Live, an hour-long streaming show
|
||||
* [Follow OpenCV on LinkedIn](http://linkedin.com/company/opencv/) for daily posts showing the state-of-the-art in computer vision & AI
|
||||
* [Subscribe to the OpenCV YouTube Channel](https://youtube.com/@opencvofficial) featuring OpenCV Live, an hour-long streaming show
|
||||
* [Follow OpenCV on LinkedIn](https://linkedin.com/company/opencv/) for daily posts showing the state-of-the-art in computer vision & AI
|
||||
* [Apply to be an OpenCV Volunteer](https://form.jotform.com/232745316792159) to help organize events and online campaigns as well as amplify them
|
||||
* [Follow OpenCV on Mastodon](http://mastodon.social/@opencv) in the Fediverse
|
||||
* [Follow OpenCV on Mastodon](https://mastodon.social/@opencv) in the Fediverse
|
||||
* [Follow OpenCV on Twitter](https://twitter.com/opencvlive)
|
||||
* [OpenCV.ai](https://opencv.ai): Computer Vision and AI development services from the OpenCV team.
|
||||
|
||||
@@ -46,6 +46,13 @@ if(WITH_IPP_CALLS_ENFORCED)
|
||||
message("WITH_IPP_CALLS_ENFORCED=${WITH_IPP_CALLS_ENFORCED}: enforced IPP calls are enabled in IPP HAL")
|
||||
endif()
|
||||
|
||||
# Enable cv::instr tracing of IPP calls inside the HAL so they show up in the
|
||||
# instrumentation trace / IPP weight. Reuses the engine exported from
|
||||
# opencv_core (symbols resolved at link time as ipphal is archived into core).
|
||||
if(ENABLE_INSTRUMENTATION)
|
||||
target_compile_definitions(ipphal PRIVATE ENABLE_INSTRUMENTATION)
|
||||
endif()
|
||||
|
||||
target_include_directories(ipphal PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-suggest-override)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// 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) 2026, Intel Corporation, all rights reserved.
|
||||
|
||||
#ifndef __IPP_HAL_UTILS_HPP__
|
||||
#define __IPP_HAL_UTILS_HPP__
|
||||
@@ -23,7 +24,22 @@
|
||||
# include "ipp.h"
|
||||
#endif
|
||||
|
||||
// IPP call instrumentation for the standalone IPP HAL.
|
||||
//
|
||||
// The HAL is built as a separate static library that does not include the
|
||||
// internal core/private.hpp, so by default its IPP calls never appear in the
|
||||
// cv::instr trace (reported IPP weight = 0%). When the parent build enables
|
||||
// ENABLE_INSTRUMENTATION, the shared instrumentation.private.hpp provides the
|
||||
// exact same CV_INSTRUMENT_FUN_IPP macro used by core (backed by symbols exported
|
||||
// from libopencv_core, resolved at link time), so HAL IPP calls are traced
|
||||
// identically to in-module ones. Otherwise the no-op passthrough is used.
|
||||
#if !defined(CV_INSTRUMENT_FUN_IPP)
|
||||
#if defined(ENABLE_INSTRUMENTATION)
|
||||
#include "opencv2/core/utils/instrumentation.private.hpp"
|
||||
#else
|
||||
#define CV_INSTRUMENT_FUN_IPP(FUN, ...) ((FUN)(__VA_ARGS__))
|
||||
#endif // defined(ENABLE_INSTRUMENTATION)
|
||||
#endif // !defined(CV_INSTRUMENT_FUN_IPP)
|
||||
|
||||
#define CV_HAL_CHECK_USE_IPP() if(!cv::ipp::useIPP()) return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
|
||||
@@ -690,23 +690,13 @@ public:
|
||||
TLSData<InstrTLSStruct> tlsStruct;
|
||||
};
|
||||
|
||||
class CV_EXPORTS IntrumentationRegion
|
||||
{
|
||||
public:
|
||||
IntrumentationRegion(const char* funName, const char* fileName, int lineNum, void *retAddress, bool alwaysExpand, TYPE instrType = TYPE_GENERAL, IMPL implType = IMPL_PLAIN);
|
||||
~IntrumentationRegion();
|
||||
|
||||
private:
|
||||
bool m_disabled; // region status
|
||||
uint64 m_regionTicks;
|
||||
};
|
||||
|
||||
CV_EXPORTS InstrStruct& getInstrumentStruct();
|
||||
InstrTLSStruct& getInstrumentTLSStruct();
|
||||
CV_EXPORTS InstrNode* getCurrentNode();
|
||||
}
|
||||
}
|
||||
|
||||
#include "opencv2/core/utils/instrumentation.private.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define CV_INSTRUMENT_GET_RETURN_ADDRESS _ReturnAddress()
|
||||
#else
|
||||
@@ -718,45 +708,6 @@ CV_EXPORTS InstrNode* getCurrentNode();
|
||||
#define CV_INSTRUMENT_REGION_CUSTOM_META(NAME, ALWAYS_EXPAND, TYPE, IMPL)\
|
||||
void *CVAUX_CONCAT(__curr_address__, __LINE__) = [&]() {return CV_INSTRUMENT_GET_RETURN_ADDRESS;}();\
|
||||
::cv::instr::IntrumentationRegion CVAUX_CONCAT(__instr_region__, __LINE__) (NAME, __FILE__, __LINE__, CVAUX_CONCAT(__curr_address__, __LINE__), false, ::cv::instr::TYPE_GENERAL, ::cv::instr::IMPL_PLAIN);
|
||||
// Instrument functions with non-void return type
|
||||
#define CV_INSTRUMENT_FUN_RT_META(TYPE, IMPL, ERROR_COND, FUN, ...) ([&]()\
|
||||
{\
|
||||
if(::cv::instr::useInstrumentation()){\
|
||||
::cv::instr::IntrumentationRegion __instr__(#FUN, __FILE__, __LINE__, NULL, false, TYPE, IMPL);\
|
||||
try{\
|
||||
auto instrStatus = ((FUN)(__VA_ARGS__));\
|
||||
if(ERROR_COND){\
|
||||
::cv::instr::getCurrentNode()->m_payload.m_funError = true;\
|
||||
CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit");\
|
||||
}\
|
||||
return instrStatus;\
|
||||
}catch(...){\
|
||||
::cv::instr::getCurrentNode()->m_payload.m_funError = true;\
|
||||
CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit");\
|
||||
throw;\
|
||||
}\
|
||||
}else{\
|
||||
return ((FUN)(__VA_ARGS__));\
|
||||
}\
|
||||
}())
|
||||
// Instrument functions with void return type
|
||||
#define CV_INSTRUMENT_FUN_RV_META(TYPE, IMPL, FUN, ...) ([&]()\
|
||||
{\
|
||||
if(::cv::instr::useInstrumentation()){\
|
||||
::cv::instr::IntrumentationRegion __instr__(#FUN, __FILE__, __LINE__, NULL, false, TYPE, IMPL);\
|
||||
try{\
|
||||
(FUN)(__VA_ARGS__);\
|
||||
}catch(...){\
|
||||
::cv::instr::getCurrentNode()->m_payload.m_funError = true;\
|
||||
CV_INSTRUMENT_MARK_META(IMPL, #FUN "- BadExit");\
|
||||
throw;\
|
||||
}\
|
||||
}else{\
|
||||
(FUN)(__VA_ARGS__);\
|
||||
}\
|
||||
}())
|
||||
// Instrumentation information marker
|
||||
#define CV_INSTRUMENT_MARK_META(IMPL, NAME, ...) {::cv::instr::IntrumentationRegion __instr_mark__(NAME, __FILE__, __LINE__, NULL, false, ::cv::instr::TYPE_MARKER, IMPL);}
|
||||
|
||||
///// General instrumentation
|
||||
// General OpenCV region instrumentation macro
|
||||
@@ -769,10 +720,6 @@ CV_EXPORTS InstrNode* getCurrentNode();
|
||||
///// IPP instrumentation
|
||||
// Wrapper region instrumentation macro
|
||||
#define CV_INSTRUMENT_REGION_IPP(); CV_INSTRUMENT_REGION_META(__FUNCTION__, false, ::cv::instr::TYPE_WRAPPER, ::cv::instr::IMPL_IPP)
|
||||
// Function instrumentation macro
|
||||
#define CV_INSTRUMENT_FUN_IPP(FUN, ...) CV_INSTRUMENT_FUN_RT_META(::cv::instr::TYPE_FUN, ::cv::instr::IMPL_IPP, instrStatus < 0, FUN, __VA_ARGS__)
|
||||
// Diagnostic markers
|
||||
#define CV_INSTRUMENT_MARK_IPP(NAME) CV_INSTRUMENT_MARK_META(::cv::instr::IMPL_IPP, NAME)
|
||||
|
||||
///// OpenCL instrumentation
|
||||
// Wrapper region instrumentation macro
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
// 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) 2026, Intel Corporation, all rights reserved.
|
||||
|
||||
#ifndef OPENCV_CORE_UTILS_INSTRUMENTATION_PRIVATE_HPP
|
||||
#define OPENCV_CORE_UTILS_INSTRUMENTATION_PRIVATE_HPP
|
||||
|
||||
#include "opencv2/core/utils/instrumentation.hpp"
|
||||
|
||||
// Region-based function-instrumentation primitives.
|
||||
//
|
||||
// Only meaningful when the build was configured with ENABLE_INSTRUMENTATION;
|
||||
// otherwise this header contributes nothing and each includer provides its own
|
||||
// no-op fallbacks. The IntrumentationRegion / getCurrentNode() definitions are
|
||||
// compiled into and exported (CV_EXPORTS) from the core library, so the HAL only
|
||||
// needs these declarations and resolves the symbols at link time.
|
||||
|
||||
#ifdef ENABLE_INSTRUMENTATION
|
||||
|
||||
namespace cv { namespace instr {
|
||||
|
||||
// Scoped region: records one instrumentation node on construction and closes it
|
||||
// on destruction. Defined in modules/core/src/system.cpp.
|
||||
class CV_EXPORTS IntrumentationRegion
|
||||
{
|
||||
public:
|
||||
IntrumentationRegion(const char* funName, const char* fileName, int lineNum, void *retAddress,
|
||||
bool alwaysExpand, TYPE instrType = TYPE_GENERAL, IMPL implType = IMPL_PLAIN);
|
||||
~IntrumentationRegion();
|
||||
|
||||
private:
|
||||
bool m_disabled; // region status
|
||||
uint64 m_regionTicks;
|
||||
};
|
||||
|
||||
CV_EXPORTS InstrNode* getCurrentNode();
|
||||
|
||||
}} // namespace cv::instr
|
||||
|
||||
// Instrumentation information marker
|
||||
#define CV_INSTRUMENT_MARK_META(IMPL, NAME, ...) {::cv::instr::IntrumentationRegion __instr_mark__(NAME, __FILE__, __LINE__, NULL, false, ::cv::instr::TYPE_MARKER, IMPL);}
|
||||
|
||||
// Instrument functions with non-void return type
|
||||
#define CV_INSTRUMENT_FUN_RT_META(TYPE, IMPL, ERROR_COND, FUN, ...) ([&]() \
|
||||
{ \
|
||||
if(::cv::instr::useInstrumentation()){ \
|
||||
::cv::instr::IntrumentationRegion __instr__(#FUN, __FILE__, __LINE__, NULL, false, TYPE, IMPL); \
|
||||
try{ \
|
||||
auto instrStatus = ((FUN)(__VA_ARGS__)); \
|
||||
if(ERROR_COND){ \
|
||||
::cv::instr::getCurrentNode()->m_payload.m_funError = true; \
|
||||
CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit"); \
|
||||
} \
|
||||
return instrStatus; \
|
||||
}catch(...){ \
|
||||
::cv::instr::getCurrentNode()->m_payload.m_funError = true; \
|
||||
CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit"); \
|
||||
throw; \
|
||||
} \
|
||||
}else{ \
|
||||
return ((FUN)(__VA_ARGS__)); \
|
||||
} \
|
||||
}())
|
||||
// Instrument functions with void return type
|
||||
#define CV_INSTRUMENT_FUN_RV_META(TYPE, IMPL, FUN, ...) ([&]() \
|
||||
{ \
|
||||
if(::cv::instr::useInstrumentation()){ \
|
||||
::cv::instr::IntrumentationRegion __instr__(#FUN, __FILE__, __LINE__, NULL, false, TYPE, IMPL); \
|
||||
try{ \
|
||||
(FUN)(__VA_ARGS__); \
|
||||
}catch(...){ \
|
||||
::cv::instr::getCurrentNode()->m_payload.m_funError = true; \
|
||||
CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit"); \
|
||||
throw; \
|
||||
} \
|
||||
}else{ \
|
||||
(FUN)(__VA_ARGS__); \
|
||||
} \
|
||||
}())
|
||||
|
||||
// IPP function instrumentation macros
|
||||
#define CV_INSTRUMENT_FUN_IPP(FUN, ...) CV_INSTRUMENT_FUN_RT_META(::cv::instr::TYPE_FUN, ::cv::instr::IMPL_IPP, instrStatus < 0, FUN, __VA_ARGS__)
|
||||
#define CV_INSTRUMENT_MARK_IPP(NAME) CV_INSTRUMENT_MARK_META(::cv::instr::IMPL_IPP, NAME)
|
||||
|
||||
#endif // ENABLE_INSTRUMENTATION
|
||||
|
||||
#endif // OPENCV_CORE_UTILS_INSTRUMENTATION_PRIVATE_HPP
|
||||
@@ -169,13 +169,13 @@ void icvCvt_Gray2BGR_16u_C1C3R( const ushort* gray, int gray_step,
|
||||
ushort* bgr, int bgr_step, Size size )
|
||||
{
|
||||
int i;
|
||||
for( ; size.height--; gray += gray_step/sizeof(gray[0]) )
|
||||
for( ; size.height--; gray += gray_step/(int)sizeof(gray[0]) )
|
||||
{
|
||||
for( i = 0; i < size.width; i++, bgr += 3 )
|
||||
{
|
||||
bgr[0] = bgr[1] = bgr[2] = gray[i];
|
||||
}
|
||||
bgr += bgr_step/sizeof(bgr[0]) - size.width*3;
|
||||
bgr += bgr_step/(int)sizeof(bgr[0]) - size.width*3;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,8 +214,8 @@ void icvCvt_BGRA2BGR_16u_C4C3R( const ushort* bgra, int bgra_step,
|
||||
bgr[0] = t0; bgr[1] = t1;
|
||||
t0 = bgra[swap_rb^2]; bgr[2] = t0;
|
||||
}
|
||||
bgr += bgr_step/sizeof(bgr[0]) - size.width*3;
|
||||
bgra += bgra_step/sizeof(bgra[0]) - size.width*4;
|
||||
bgr += bgr_step/(int)sizeof(bgr[0]) - size.width*3;
|
||||
bgra += bgra_step/(int)sizeof(bgra[0]) - size.width*4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,8 +252,8 @@ void icvCvt_BGRA2RGBA_16u_C4R( const ushort* bgra, int bgra_step,
|
||||
rgba[0] = t2; rgba[1] = t1;
|
||||
rgba[2] = t0; rgba[3] = t3;
|
||||
}
|
||||
bgra += bgra_step/sizeof(bgra[0]) - size.width*4;
|
||||
rgba += rgba_step/sizeof(rgba[0]) - size.width*4;
|
||||
bgra += bgra_step/(int)sizeof(bgra[0]) - size.width*4;
|
||||
rgba += rgba_step/(int)sizeof(rgba[0]) - size.width*4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -689,6 +689,28 @@ TEST(Imgcodecs_Tiff, readWrite_unsigned)
|
||||
EXPECT_EQ(0, remove(filenameOutput.c_str()));
|
||||
}
|
||||
|
||||
// See https://github.com/opencv/opencv/issues/29615
|
||||
// Decoding a 16-bit 4-channel TIFF used to form an out of range pointer in
|
||||
// icvCvt_BGRA2RGBA_16u_C4R because the byte step was divided by an unsigned
|
||||
// sizeof and then had size.width*4 subtracted, which wraps around for a zero
|
||||
// step. This just checks that a 16UC4 TIFF round-trips correctly; the value is
|
||||
// mainly that the sanitizer builds no longer report the pointer overflow.
|
||||
TEST(Imgcodecs_Tiff, regression_29615_16UC4)
|
||||
{
|
||||
Mat img(4, 3, CV_16UC4);
|
||||
randu(img, Scalar::all(0), Scalar::all(65535));
|
||||
|
||||
vector<uchar> buf;
|
||||
ASSERT_NO_THROW(ASSERT_TRUE(imencode(".tiff", img, buf)));
|
||||
|
||||
Mat decoded;
|
||||
ASSERT_NO_THROW(decoded = imdecode(buf, IMREAD_UNCHANGED));
|
||||
ASSERT_FALSE(decoded.empty());
|
||||
ASSERT_EQ(CV_16UC4, decoded.type());
|
||||
ASSERT_EQ(img.size(), decoded.size());
|
||||
EXPECT_EQ(0, cvtest::norm(img, decoded, NORM_INF));
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_Tiff, readWrite_32FC1)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
|
||||
@@ -1839,12 +1839,14 @@ int DTreesImpl::readSplit( const FileNode& fn )
|
||||
Split split;
|
||||
|
||||
int vi = (int)fn["var"];
|
||||
CV_Assert( 0 <= vi && vi <= (int)varType.size() );
|
||||
CV_Assert( 0 <= vi && vi < (int)varMapping.size() );
|
||||
vi = varMapping[vi]; // convert to varIdx if needed
|
||||
CV_Assert( 0 <= vi && vi < (int)varType.size() );
|
||||
split.varIdx = vi;
|
||||
|
||||
if( varType[vi] == VAR_CATEGORICAL ) // split on categorical var
|
||||
{
|
||||
CV_Assert( vi < (int)catOfs.size() );
|
||||
int i, val, ssize = getSubsetSize(vi);
|
||||
split.subsetOfs = (int)subsets.size();
|
||||
for( i = 0; i < ssize; i++ )
|
||||
@@ -1860,6 +1862,7 @@ int DTreesImpl::readSplit( const FileNode& fn )
|
||||
if( fns.isInt() )
|
||||
{
|
||||
val = (int)fns;
|
||||
CV_Assert( 0 <= val && (val >> 5) < ssize );
|
||||
subset[val >> 5] |= 1 << (val & 31);
|
||||
}
|
||||
else
|
||||
@@ -1869,6 +1872,7 @@ int DTreesImpl::readSplit( const FileNode& fn )
|
||||
for( i = 0; i < n; i++, ++it )
|
||||
{
|
||||
val = (int)*it;
|
||||
CV_Assert( 0 <= val && (val >> 5) < ssize );
|
||||
subset[val >> 5] |= 1 << (val & 31);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +96,61 @@ ML_Legacy_Param param_list[] = {
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, ML_Legacy_Params, testing::ValuesIn(param_list));
|
||||
|
||||
TEST(ML_DTrees, load_bad_categorical_split)
|
||||
{
|
||||
// Train a tree with a categorical input so the model carries a
|
||||
// categorical split serialized as an "in"/"not_in" value list.
|
||||
const int n = 40;
|
||||
Mat samples(n, 1, CV_32F);
|
||||
Mat responses(n, 1, CV_32S);
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
int cat = i % 4;
|
||||
samples.at<float>(i, 0) = (float)cat;
|
||||
responses.at<int>(i, 0) = (cat == 1 || cat == 2) ? 1 : 0;
|
||||
}
|
||||
Mat varType(2, 1, CV_8U);
|
||||
varType.at<uchar>(0) = ml::VAR_CATEGORICAL;
|
||||
varType.at<uchar>(1) = ml::VAR_CATEGORICAL;
|
||||
|
||||
Ptr<ml::TrainData> td = ml::TrainData::create(samples, ml::ROW_SAMPLE, responses,
|
||||
noArray(), noArray(), noArray(), varType);
|
||||
Ptr<ml::DTrees> dt = ml::DTrees::create();
|
||||
dt->setMaxDepth(4);
|
||||
dt->setCVFolds(0);
|
||||
dt->setMaxCategories(4);
|
||||
dt->setMinSampleCount(1);
|
||||
dt->train(td);
|
||||
|
||||
const string filename = cv::tempfile(".yml");
|
||||
dt->save(filename);
|
||||
|
||||
string model;
|
||||
{
|
||||
std::ifstream in(filename.c_str());
|
||||
std::stringstream ss;
|
||||
ss << in.rdbuf();
|
||||
model = ss.str();
|
||||
}
|
||||
|
||||
// Category values in the split list index a per-split subset bitmask.
|
||||
// Injecting a value larger than the number of categories used to write
|
||||
// past that bitmask; loading such a model must be rejected, not crash.
|
||||
size_t pos = model.find("in:");
|
||||
ASSERT_NE(pos, string::npos);
|
||||
size_t br = model.find('[', pos);
|
||||
ASSERT_NE(br, string::npos);
|
||||
model.insert(br + 1, "1000000,");
|
||||
{
|
||||
std::ofstream out(filename.c_str());
|
||||
out << model;
|
||||
}
|
||||
|
||||
Ptr<ml::DTrees> bad;
|
||||
EXPECT_THROW(bad = ml::DTrees::load(filename), Exception);
|
||||
remove(filename.c_str());
|
||||
}
|
||||
|
||||
/*TEST(ML_SVM, throw_exception_when_save_untrained_model)
|
||||
{
|
||||
Ptr<cv::ml::SVM> svm;
|
||||
|
||||
@@ -723,7 +723,7 @@ void HOGCache::init(const HOGDescriptor* _descriptor,
|
||||
#if CV_SIMD128
|
||||
idx = v_float32x4(0.0f, 1.0f, 2.0f, 3.0f);
|
||||
|
||||
for (; j <= blockSize.height - 4; j += 4)
|
||||
for (; j <= blockSize.width - 4; j += 4)
|
||||
{
|
||||
v_float32x4 t = v_sub(idx, _bw);
|
||||
t = v_mul(t, t);
|
||||
|
||||
@@ -1364,4 +1364,22 @@ TEST(Objdetect_CascadeDetector, small_img)
|
||||
}
|
||||
}
|
||||
|
||||
// See https://github.com/opencv/opencv/issues/23580
|
||||
// HOGDescriptor::compute() overflowed the gaussian weights buffer when the block
|
||||
// was taller than it was wide: the SIMD store loop for the width buffer (_dj) was
|
||||
// bounded by blockSize.height instead of blockSize.width. The block is chosen wide
|
||||
// enough that the buffer is heap allocated, so the overflow is a real out-of-bounds
|
||||
// write. "Done" is simply that compute() runs without crashing.
|
||||
TEST(Objdetect_HOGDescriptor, issue_23580_tall_block_no_overflow)
|
||||
{
|
||||
Size winSize(272, 2048); // height > width, width > AutoBuffer stack size
|
||||
HOGDescriptor hog(winSize, /*blockSize*/ winSize, /*blockStride*/ Size(8, 8),
|
||||
/*cellSize*/ Size(8, 8), /*nbins*/ 9);
|
||||
|
||||
Mat src(winSize, CV_8UC1, Scalar::all(0));
|
||||
std::vector<float> descriptors;
|
||||
ASSERT_NO_THROW(hog.compute(src, descriptors));
|
||||
EXPECT_FALSE(descriptors.empty());
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
Reference in New Issue
Block a user