mirror of
https://github.com/opencv/opencv.git
synced 2024-11-24 03:00:14 +08:00
Merge remote-tracking branch 'upstream/3.4' into merge-3.4
This commit is contained in:
commit
92b9888837
1
LICENSE
1
LICENSE
@ -13,6 +13,7 @@ Copyright (C) 2009-2016, NVIDIA Corporation, all rights reserved.
|
||||
Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
|
||||
Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved.
|
||||
Copyright (C) 2015-2016, Itseez Inc., all rights reserved.
|
||||
Copyright (C) 2019, Xperience AI, all rights reserved.
|
||||
Third party copyrights are property of their respective owners.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
|
@ -125,11 +125,11 @@ MACRO(_PCH_GET_COMPILE_COMMAND out_command _input _output)
|
||||
STRING(REGEX REPLACE "^ +" "" pchsupport_compiler_cxx_arg1 ${CMAKE_CXX_COMPILER_ARG1})
|
||||
|
||||
SET(${out_command}
|
||||
${CMAKE_CXX_COMPILER} ${pchsupport_compiler_cxx_arg1} ${_compile_FLAGS} -x c++-header -o ${_output} ${_input}
|
||||
${CMAKE_CXX_COMPILER} ${pchsupport_compiler_cxx_arg1} ${_compile_FLAGS} -x c++-header -o ${_output} -c ${_input}
|
||||
)
|
||||
ELSE(CMAKE_CXX_COMPILER_ARG1)
|
||||
SET(${out_command}
|
||||
${CMAKE_CXX_COMPILER} ${_compile_FLAGS} -x c++-header -o ${_output} ${_input}
|
||||
${CMAKE_CXX_COMPILER} ${_compile_FLAGS} -x c++-header -o ${_output} -c ${_input}
|
||||
)
|
||||
ENDIF(CMAKE_CXX_COMPILER_ARG1)
|
||||
ELSE()
|
||||
|
@ -48,6 +48,10 @@
|
||||
//! @addtogroup core_utils
|
||||
//! @{
|
||||
|
||||
#ifdef OPENCV_INCLUDE_PORT_FILE // User-provided header file with custom platform configuration
|
||||
#include OPENCV_INCLUDE_PORT_FILE
|
||||
#endif
|
||||
|
||||
#if !defined CV_DOXYGEN && !defined CV_IGNORE_DEBUG_BUILD_GUARD
|
||||
#if (defined(_MSC_VER) && (defined(DEBUG) || defined(_DEBUG))) || \
|
||||
(defined(_GLIBCXX_DEBUG) || defined(_GLIBCXX_DEBUG_PEDANTIC))
|
||||
@ -118,9 +122,11 @@ namespace cv { namespace debug_build_guard { } using namespace debug_build_guard
|
||||
# if !defined(__clang__) && defined(__GNUC__) && (__GNUC__*100 + __GNUC_MINOR__ > 302)
|
||||
# define CV_StaticAssert(condition, reason) ({ extern int __attribute__((error("CV_StaticAssert: " reason " " #condition))) CV_StaticAssert(); ((condition) ? 0 : CV_StaticAssert()); })
|
||||
# else
|
||||
namespace cv {
|
||||
template <bool x> struct CV_StaticAssert_failed;
|
||||
template <> struct CV_StaticAssert_failed<true> { enum { val = 1 }; };
|
||||
template<int x> struct CV_StaticAssert_test {};
|
||||
}
|
||||
# define CV_StaticAssert(condition, reason)\
|
||||
typedef cv::CV_StaticAssert_test< sizeof(cv::CV_StaticAssert_failed< static_cast<bool>(condition) >) > CVAUX_CONCAT(CV_StaticAssert_failed_at_, __LINE__)
|
||||
# endif
|
||||
@ -641,7 +647,11 @@ __CV_ENUM_FLAGS_BITWISE_XOR_EQ (EnumType, EnumType)
|
||||
# include <intrin.h>
|
||||
# define CV_XADD(addr, delta) (int)_InterlockedExchangeAdd((long volatile*)addr, delta)
|
||||
#else
|
||||
CV_INLINE CV_XADD(int* addr, int delta) { int tmp = *addr; *addr += delta; return tmp; }
|
||||
#ifdef OPENCV_FORCE_UNSAFE_XADD
|
||||
CV_INLINE CV_XADD(int* addr, int delta) { int tmp = *addr; *addr += delta; return tmp; }
|
||||
#else
|
||||
#error "OpenCV: can't define safe CV_XADD macro for current platform (unsupported). Define CV_XADD macro through custom port header (see OPENCV_INCLUDE_PORT_FILE)"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -346,11 +346,37 @@ OPENCV_HAL_IMPL_VSX_EXPAND(v_int16x8, v_int32x4, short, vec_unpackl, vec_unpackh
|
||||
OPENCV_HAL_IMPL_VSX_EXPAND(v_uint32x4, v_uint64x2, uint, vec_unpacklu, vec_unpackhu)
|
||||
OPENCV_HAL_IMPL_VSX_EXPAND(v_int32x4, v_int64x2, int, vec_unpackl, vec_unpackh)
|
||||
|
||||
/* Load and zero expand a 4 byte value into the second dword, first is don't care. */
|
||||
#if !defined(CV_COMPILER_VSX_BROKEN_ASM)
|
||||
#define _LXSIWZX(out, ptr, T) __asm__ ("lxsiwzx %x0, 0, %1\r\n" : "=wa"(out) : "r" (ptr) : "memory");
|
||||
#else
|
||||
/* This is compiler-agnostic, but will introduce an unneeded splat on the critical path. */
|
||||
#define _LXSIWZX(out, ptr, T) out = (T)vec_udword2_sp(*(uint32_t*)(ptr));
|
||||
#endif
|
||||
|
||||
inline v_uint32x4 v_load_expand_q(const uchar* ptr)
|
||||
{ return v_uint32x4(vec_uint4_set(ptr[0], ptr[1], ptr[2], ptr[3])); }
|
||||
{
|
||||
// Zero-extend the extra 24B instead of unpacking. Usually faster in small kernel
|
||||
// Likewise note, value is zero extended and upper 4 bytes are zero'ed.
|
||||
vec_uchar16 pmu = {8, 12, 12, 12, 9, 12, 12, 12, 10, 12, 12, 12, 11, 12, 12, 12};
|
||||
vec_uchar16 out;
|
||||
|
||||
_LXSIWZX(out, ptr, vec_uchar16);
|
||||
out = vec_perm(out, out, pmu);
|
||||
return v_uint32x4((vec_uint4)out);
|
||||
}
|
||||
|
||||
inline v_int32x4 v_load_expand_q(const schar* ptr)
|
||||
{ return v_int32x4(vec_int4_set(ptr[0], ptr[1], ptr[2], ptr[3])); }
|
||||
{
|
||||
vec_char16 out;
|
||||
vec_short8 outs;
|
||||
vec_int4 outw;
|
||||
|
||||
_LXSIWZX(out, ptr, vec_char16);
|
||||
outs = vec_unpackl(out);
|
||||
outw = vec_unpackh(outs);
|
||||
return v_int32x4(outw);
|
||||
}
|
||||
|
||||
/* pack */
|
||||
#define OPENCV_HAL_IMPL_VSX_PACK(_Tpvec, _Tp, _Tpwvec, _Tpvn, _Tpdel, sfnc, pkfnc, addfnc, pack) \
|
||||
|
@ -16,6 +16,8 @@
|
||||
//#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE + 1
|
||||
#include <opencv2/core/utils/logger.hpp>
|
||||
|
||||
#include <opencv2/core/utils/trace.private.hpp>
|
||||
|
||||
//#define CV_PROFILE_THREADS 64
|
||||
//#define getTickCount getCPUTickCount // use this if getTickCount() calls are expensive (and getCPUTickCount() is accurate)
|
||||
|
||||
@ -264,6 +266,9 @@ public:
|
||||
void thread_body();
|
||||
static void* thread_loop_wrapper(void* thread_object)
|
||||
{
|
||||
#ifdef OPENCV_WITH_ITT
|
||||
__itt_thread_set_name(cv::format("OpenCVThread-%03d", cv::utils::getThreadID()).c_str());
|
||||
#endif
|
||||
((WorkerThread*)thread_object)->thread_body();
|
||||
return 0;
|
||||
}
|
||||
|
@ -1815,6 +1815,15 @@ BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID lpReserved)
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
#ifdef OPENCV_WITH_ITT
|
||||
bool overrideThreadName()
|
||||
{
|
||||
static bool param = utils::getConfigurationParameterBool("OPENCV_TRACE_ITT_SET_THREAD_NAME", false);
|
||||
return param;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int g_threadNum = 0;
|
||||
class ThreadID {
|
||||
public:
|
||||
@ -1823,7 +1832,8 @@ public:
|
||||
id(CV_XADD(&g_threadNum, 1))
|
||||
{
|
||||
#ifdef OPENCV_WITH_ITT
|
||||
__itt_thread_set_name(cv::format("OpenCVThread-%03d", id).c_str());
|
||||
if (overrideThreadName())
|
||||
__itt_thread_set_name(cv::format("OpenCVThread-%03d", id).c_str());
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
@ -64,6 +64,7 @@ ocv_warnings_disable(CMAKE_CXX_FLAGS
|
||||
/wd4456 /wd4510 /wd4610 /wd4800
|
||||
/wd4701 /wd4703 # potentially uninitialized local/pointer variable 'value' used
|
||||
/wd4505 # unreferenced local function has been removed
|
||||
/wd4458 # declaration of 'x' hides class member. GCC still works, MSVC bug is here: https://developercommunity.visualstudio.com/content/problem/219311/c-c4458-declaration-hides-class-member-warning-iss.html
|
||||
-wd858 -wd2196
|
||||
-Winvalid-offsetof # Apple Clang (attr_value.pb.cc)
|
||||
)
|
||||
|
@ -508,6 +508,13 @@ CV__DNN_INLINE_NS_BEGIN
|
||||
static Ptr<Layer> create(const LayerParams ¶ms);
|
||||
};
|
||||
|
||||
/** @brief Element wise operation on inputs
|
||||
|
||||
Extra optional parameters:
|
||||
- "operation" as string. Values are "sum" (default), "prod", "max", "div"
|
||||
- "coeff" as float array. Specify weights of inputs for SUM operation
|
||||
- "output_channels_mode" as string. Values are "same" (default, all input must have the same layout), "input_0", "input_0_truncate", "max_input_channels"
|
||||
*/
|
||||
class CV_EXPORTS EltwiseLayer : public Layer
|
||||
{
|
||||
public:
|
||||
|
@ -275,6 +275,74 @@ class dnn_test(NewOpenCVTests):
|
||||
self.assertTrue(ret)
|
||||
normAssert(self, refs[i], result, 'Index: %d' % i, 1e-10)
|
||||
|
||||
def test_custom_layer(self):
|
||||
class CropLayer(object):
|
||||
def __init__(self, params, blobs):
|
||||
self.xstart = 0
|
||||
self.xend = 0
|
||||
self.ystart = 0
|
||||
self.yend = 0
|
||||
# Our layer receives two inputs. We need to crop the first input blob
|
||||
# to match a shape of the second one (keeping batch size and number of channels)
|
||||
def getMemoryShapes(self, inputs):
|
||||
inputShape, targetShape = inputs[0], inputs[1]
|
||||
batchSize, numChannels = inputShape[0], inputShape[1]
|
||||
height, width = targetShape[2], targetShape[3]
|
||||
self.ystart = (inputShape[2] - targetShape[2]) // 2
|
||||
self.xstart = (inputShape[3] - targetShape[3]) // 2
|
||||
self.yend = self.ystart + height
|
||||
self.xend = self.xstart + width
|
||||
return [[batchSize, numChannels, height, width]]
|
||||
def forward(self, inputs):
|
||||
return [inputs[0][:,:,self.ystart:self.yend,self.xstart:self.xend]]
|
||||
|
||||
cv.dnn_registerLayer('CropCaffe', CropLayer)
|
||||
proto = '''
|
||||
name: "TestCrop"
|
||||
input: "input"
|
||||
input_shape
|
||||
{
|
||||
dim: 1
|
||||
dim: 2
|
||||
dim: 5
|
||||
dim: 5
|
||||
}
|
||||
input: "roi"
|
||||
input_shape
|
||||
{
|
||||
dim: 1
|
||||
dim: 2
|
||||
dim: 3
|
||||
dim: 3
|
||||
}
|
||||
layer {
|
||||
name: "Crop"
|
||||
type: "CropCaffe"
|
||||
bottom: "input"
|
||||
bottom: "roi"
|
||||
top: "Crop"
|
||||
}'''
|
||||
|
||||
net = cv.dnn.readNetFromCaffe(bytearray(proto.encode()))
|
||||
for backend, target in self.dnnBackendsAndTargets:
|
||||
if backend != cv.dnn.DNN_BACKEND_OPENCV:
|
||||
continue
|
||||
|
||||
printParams(backend, target)
|
||||
|
||||
net.setPreferableBackend(backend)
|
||||
net.setPreferableTarget(target)
|
||||
src_shape = [1, 2, 5, 5]
|
||||
dst_shape = [1, 2, 3, 3]
|
||||
inp = np.arange(0, np.prod(src_shape), dtype=np.float32).reshape(src_shape)
|
||||
roi = np.empty(dst_shape, dtype=np.float32)
|
||||
net.setInput(inp, "input")
|
||||
net.setInput(roi, "roi")
|
||||
out = net.forward()
|
||||
ref = inp[:, :, 1:4, 1:4]
|
||||
normAssert(self, out, ref)
|
||||
|
||||
cv.dnn_unregisterLayer('CropCaffe')
|
||||
|
||||
if __name__ == '__main__':
|
||||
NewOpenCVTests.bootstrap()
|
||||
|
@ -425,6 +425,7 @@ namespace cv {
|
||||
}
|
||||
|
||||
shortcut_param.set<std::string>("op", "sum");
|
||||
shortcut_param.set<std::string>("output_channels_mode", "input_0_truncate");
|
||||
|
||||
darknet::LayerParameter lp;
|
||||
std::string layer_name = cv::format("shortcut_%d", layer_id);
|
||||
|
@ -3040,8 +3040,29 @@ struct Net::Impl
|
||||
ShapesVec& os = inOutShapes[id].out;
|
||||
ShapesVec& ints = inOutShapes[id].internal;
|
||||
int requiredOutputs = layers[id].requiredOutputs.size();
|
||||
inOutShapes[id].supportInPlace =
|
||||
layers[id].getLayerInstance()->getMemoryShapes(is, requiredOutputs, os, ints);
|
||||
Ptr<Layer> l = layers[id].getLayerInstance();
|
||||
CV_Assert(l);
|
||||
bool layerSupportInPlace = false;
|
||||
try
|
||||
{
|
||||
layerSupportInPlace = l->getMemoryShapes(is, requiredOutputs, os, ints);
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, "OPENCV/DNN: [" << l->type << "]:(" << l->name << "): getMemoryShapes() throws exception." <<
|
||||
" inputs=" << is.size() << " outputs=" << os.size() << "/" << requiredOutputs);
|
||||
for (size_t i = 0; i < is.size(); ++i)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, " input[" << i << "] = " << toString(is[i]));
|
||||
}
|
||||
for (size_t i = 0; i < os.size(); ++i)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, " output[" << i << "] = " << toString(os[i]));
|
||||
}
|
||||
CV_LOG_ERROR(NULL, "Exception message: " << e.what());
|
||||
throw;
|
||||
}
|
||||
inOutShapes[id].supportInPlace = layerSupportInPlace;
|
||||
|
||||
for (int i = 0; i < ints.size(); i++)
|
||||
CV_Assert(total(ints[i]) > 0);
|
||||
|
@ -634,6 +634,12 @@ public:
|
||||
const int group = inpCn / inpGroupCn;
|
||||
|
||||
std::vector<size_t> kernel_shape = getShape<size_t>(blobs[0]);
|
||||
if (group != 1)
|
||||
{
|
||||
kernel_shape[0] /= group;
|
||||
kernel_shape.insert(kernel_shape.begin(), group);
|
||||
}
|
||||
|
||||
auto ieWeights = std::make_shared<ngraph::op::Constant>(ngraph::element::f32, kernel_shape, blobs[0].data);
|
||||
if (fusedWeights)
|
||||
{
|
||||
@ -643,10 +649,10 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
Mat newWeights = blobs[0].reshape(1, outCn);
|
||||
Mat cvWeights = weightsMat.colRange(0, newWeights.cols);
|
||||
Mat newWeights;
|
||||
Mat cvWeights = weightsMat.colRange(0, blobs[0].total() / outCn);
|
||||
cvWeights.copyTo(newWeights);
|
||||
ieWeights = std::make_shared<ngraph::op::Constant>(ngraph::element::f32, kernel_shape, blobs[0].data);
|
||||
ieWeights = std::make_shared<ngraph::op::Constant>(ngraph::element::f32, kernel_shape, newWeights.data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -656,14 +662,12 @@ public:
|
||||
|
||||
std::shared_ptr<ngraph::Node> conv_node;
|
||||
if (group != 1) {
|
||||
conv_node = std::make_shared<ngraph::op::GroupConvolution>(
|
||||
conv_node = std::make_shared<ngraph::op::v1::GroupConvolution>(
|
||||
ieInpNode, ieWeights,
|
||||
ngraph::Strides(strides),
|
||||
ngraph::Strides(dilations),
|
||||
ngraph::CoordinateDiff(std::vector<std::ptrdiff_t>(pads_begin.begin(), pads_begin.end())),
|
||||
ngraph::CoordinateDiff(std::vector<std::ptrdiff_t>(pads_end.begin(), pads_end.end())),
|
||||
ngraph::Strides{},
|
||||
group,
|
||||
ngraph::Strides(dilations),
|
||||
pad_type);
|
||||
} else {
|
||||
conv_node = std::make_shared<ngraph::op::v1::Convolution>(
|
||||
@ -2254,41 +2258,33 @@ public:
|
||||
|
||||
if (fusedWeights)
|
||||
{
|
||||
int inpCn = blobs[0].size[0];
|
||||
Mat newWeights = blobs[0].reshape(1, inpCn);
|
||||
Mat newWeights;
|
||||
transpose(weightsMat, newWeights);
|
||||
ieWeights = std::make_shared<ngraph::op::Constant>(ngraph::element::f32, kernel_shape, newWeights.data);
|
||||
}
|
||||
size_t batch = ieInpNode->get_shape()[0];
|
||||
std::vector<size_t> out_shape = {batch, (size_t)numOutput};
|
||||
std::vector<size_t> paddings_end;
|
||||
std::vector<size_t> inpShape = ieInpNode->get_shape();
|
||||
if (padMode.empty())
|
||||
{
|
||||
for (int i = 0; i < pads_end.size(); i++) {
|
||||
out_shape.push_back(strides[i] * (inpShape[2 + i] - 1) +
|
||||
kernel_size[i] - pads_begin[i] - pads_end[i] + adjust_pads[i]);
|
||||
paddings_end.push_back(pads_end[i] - adjust_pads[i]);
|
||||
}
|
||||
}
|
||||
else if (padMode == "SAME")
|
||||
{
|
||||
for (int i = 0; i < pads_begin.size(); i++) {
|
||||
out_shape.push_back(strides[i] * (inpShape[2 + i] - 1) + 1 + adjust_pads[i]);
|
||||
paddings_end.push_back(kernel_size[i] - pads_begin[i] - 1 - adjust_pads[i]);
|
||||
}
|
||||
} else {
|
||||
paddings_end = pads_end;
|
||||
}
|
||||
|
||||
auto deconv = std::make_shared<ngraph::op::ConvolutionBackpropData>(
|
||||
ngraph::Shape{out_shape},
|
||||
ieWeights,
|
||||
auto deconv = std::make_shared<ngraph::op::v1::ConvolutionBackpropData>(
|
||||
ieInpNode,
|
||||
ieWeights,
|
||||
ngraph::Strides(strides),
|
||||
ngraph::Strides(dilations),
|
||||
ngraph::CoordinateDiff(std::vector<std::ptrdiff_t>(pads_begin.begin(), pads_begin.end())),
|
||||
ngraph::CoordinateDiff(std::vector<std::ptrdiff_t>(paddings_end.begin(), paddings_end.end())),
|
||||
(strides.size() == 2 ? ngraph::Strides{1, 1} : ngraph::Strides{1, 1, 1}));
|
||||
ngraph::Strides(dilations));
|
||||
if (hasBias() || fusedBias)
|
||||
{
|
||||
std::vector<size_t> shape(deconv->get_shape().size(), 1);
|
||||
|
@ -55,36 +55,6 @@
|
||||
#ifdef HAVE_DNN_NGRAPH
|
||||
#include "../ie_ngraph.hpp"
|
||||
#include <ngraph/op/experimental/layers/detection_output.hpp>
|
||||
|
||||
namespace ngraph {
|
||||
namespace op {
|
||||
|
||||
class Dummy : public Op {
|
||||
public:
|
||||
Dummy() : Op("Dummy", {}) {
|
||||
constructor_validate_and_infer_types();
|
||||
}
|
||||
|
||||
void validate_and_infer_types() override {
|
||||
set_output_type(0, ngraph::element::Type(), {});
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> copy_with_new_args(const NodeVector& new_args) const override {
|
||||
if (!new_args.empty())
|
||||
throw ngraph_error("Incorrect number of new arguments");
|
||||
return std::make_shared<Dummy>();
|
||||
}
|
||||
|
||||
static constexpr NodeTypeInfo type_info{"Dummy", 1};
|
||||
const NodeTypeInfo& get_type_info() const override {
|
||||
return type_info;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr NodeTypeInfo Dummy::type_info;
|
||||
|
||||
} // namespace op
|
||||
} // namespace ngraph
|
||||
#endif
|
||||
|
||||
namespace cv
|
||||
@ -1000,10 +970,8 @@ public:
|
||||
attrs.code_type = std::string{"caffe.PriorBoxParameter." + _codeType};
|
||||
attrs.normalized = true;
|
||||
|
||||
auto aux_class_preds = std::make_shared<ngraph::op::Dummy>();
|
||||
auto aux_box_preds = std::make_shared<ngraph::op::Dummy>();
|
||||
auto det_out = std::make_shared<ngraph::op::DetectionOutput>(box_logits, class_preds,
|
||||
proposals, aux_class_preds, aux_box_preds, attrs);
|
||||
proposals, attrs);
|
||||
return Ptr<BackendNode>(new InfEngineNgraphNode(det_out));
|
||||
}
|
||||
#endif // HAVE_DNN_NGRAPH
|
||||
|
@ -659,7 +659,7 @@ struct SwishFunctor
|
||||
{
|
||||
return backendId == DNN_BACKEND_OPENCV ||
|
||||
backendId == DNN_BACKEND_CUDA ||
|
||||
backendId == DNN_BACKEND_HALIDE;
|
||||
backendId == DNN_BACKEND_HALIDE || backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH;;
|
||||
}
|
||||
|
||||
void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
|
||||
@ -727,7 +727,8 @@ struct SwishFunctor
|
||||
#ifdef HAVE_DNN_NGRAPH
|
||||
std::shared_ptr<ngraph::Node> initNgraphAPI(const std::shared_ptr<ngraph::Node>& node)
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented, "");
|
||||
auto sigmoid = std::make_shared<ngraph::op::Sigmoid>(node);
|
||||
return std::make_shared<ngraph::op::v1::Multiply>(node, sigmoid);
|
||||
}
|
||||
#endif // HAVE_DNN_NGRAPH
|
||||
|
||||
@ -755,7 +756,7 @@ struct MishFunctor
|
||||
{
|
||||
return backendId == DNN_BACKEND_OPENCV ||
|
||||
backendId == DNN_BACKEND_CUDA ||
|
||||
backendId == DNN_BACKEND_HALIDE;
|
||||
backendId == DNN_BACKEND_HALIDE || backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH;
|
||||
}
|
||||
|
||||
void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
|
||||
@ -823,7 +824,13 @@ struct MishFunctor
|
||||
#ifdef HAVE_DNN_NGRAPH
|
||||
std::shared_ptr<ngraph::Node> initNgraphAPI(const std::shared_ptr<ngraph::Node>& node)
|
||||
{
|
||||
CV_Error(Error::StsNotImplemented, "");
|
||||
float one = 1.0f;
|
||||
auto constant = std::make_shared<ngraph::op::Constant>(ngraph::element::f32, ngraph::Shape{1}, &one);
|
||||
auto exp_node = std::make_shared<ngraph::op::v0::Exp>(node);
|
||||
auto sum = std::make_shared<ngraph::op::v1::Add>(constant, exp_node, ngraph::op::AutoBroadcastType::NUMPY);
|
||||
auto log_node = std::make_shared<ngraph::op::v0::Log>(sum);
|
||||
auto tanh_node = std::make_shared<ngraph::op::Tanh>(log_node);
|
||||
return std::make_shared<ngraph::op::v1::Multiply>(node, tanh_node);
|
||||
}
|
||||
#endif // HAVE_DNN_NGRAPH
|
||||
|
||||
|
@ -72,9 +72,28 @@ public:
|
||||
DIV = 3
|
||||
} op;
|
||||
std::vector<float> coeffs;
|
||||
bool variableChannels;
|
||||
|
||||
enum OutputChannelsMode
|
||||
{
|
||||
ELTWISE_CHANNNELS_SAME = 0, //!< number of channels from inputs must be the same and equal to output's number of channels
|
||||
ELTWISE_CHANNNELS_INPUT_0, //!< number of channels from inputs may be different,
|
||||
//!< output's number of channels is equal to number of channels of first input
|
||||
//!< number of channels of other inputs should not be greater than number of channels of first input
|
||||
ELTWISE_CHANNNELS_INPUT_0_TRUNCATE, //!< number of channels from inputs may be different,
|
||||
//!< output's number of channels is equal to number of channels of first input
|
||||
//!< there is restriction on number of channels of other inputs
|
||||
//!< extra channels of other inputs is ignored
|
||||
ELTWISE_CHANNNELS_USE_MAX, //!< number of channels from inputs may be different,
|
||||
//!< output's number of channels is equal to maximal number of input channels
|
||||
//!< @note supported operation: `SUM`
|
||||
} channelsModeInput;
|
||||
|
||||
|
||||
mutable OutputChannelsMode channelsMode; //!< "optimized" channels mode (switch to ELTWISE_CHANNNELS_SAME if number of input channels are equal)
|
||||
mutable /*size_t*/int outputChannels;
|
||||
|
||||
EltwiseLayerImpl(const LayerParams& params)
|
||||
: outputChannels(0)
|
||||
{
|
||||
setParamsFrom(params);
|
||||
op = SUM;
|
||||
@ -103,6 +122,35 @@ public:
|
||||
coeffs[i] = paramCoeff.get<float>(i);
|
||||
}
|
||||
}
|
||||
|
||||
channelsModeInput = ELTWISE_CHANNNELS_SAME;
|
||||
if (params.has("output_channels_mode"))
|
||||
{
|
||||
String v = toLowerCase(params.get<String>("output_channels_mode"));
|
||||
if (v == "same")
|
||||
{
|
||||
channelsModeInput = ELTWISE_CHANNNELS_SAME;
|
||||
}
|
||||
else if (v == "input_0")
|
||||
{
|
||||
channelsModeInput = ELTWISE_CHANNNELS_INPUT_0;
|
||||
}
|
||||
else if (v == "input_0_truncate")
|
||||
{
|
||||
channelsModeInput = ELTWISE_CHANNNELS_INPUT_0_TRUNCATE;
|
||||
}
|
||||
else if (v == "max_input_channels")
|
||||
{
|
||||
channelsModeInput = ELTWISE_CHANNNELS_USE_MAX;
|
||||
if (op != SUM)
|
||||
CV_Error(cv::Error::StsBadArg, "[" + type + "]:(" + name + ") 'max' channels mode is limited to SUM operation only");
|
||||
}
|
||||
else
|
||||
CV_Error(cv::Error::StsBadArg, "[" + type + "]:(" + name + ") unknown channels mode: \"" + v + "\"");
|
||||
}
|
||||
channelsMode = channelsModeInput;
|
||||
|
||||
// TODO Must have checks for other unknown options
|
||||
}
|
||||
|
||||
virtual bool supportBackend(int backendId) CV_OVERRIDE
|
||||
@ -111,7 +159,7 @@ public:
|
||||
backendId == DNN_BACKEND_CUDA ||
|
||||
(backendId == DNN_BACKEND_HALIDE && op != DIV) || // TODO: not implemented, see PR #15811
|
||||
((((backendId == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && (preferableTarget != DNN_TARGET_OPENCL || coeffs.empty()))
|
||||
|| backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) && !variableChannels));
|
||||
|| backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) && channelsMode == ELTWISE_CHANNNELS_SAME));
|
||||
}
|
||||
|
||||
bool getMemoryShapes(const std::vector<MatShape> &inputs,
|
||||
@ -126,212 +174,320 @@ public:
|
||||
|
||||
int dims = inputs[0].size();
|
||||
// Number of channels in output shape is determined by the first input tensor.
|
||||
bool variableChannels = false;
|
||||
int numChannels = inputs[0][1];
|
||||
for (int i = 1; i < inputs.size(); i++)
|
||||
for (size_t i = 1; i < inputs.size(); i++)
|
||||
{
|
||||
CV_Assert(inputs[0][0] == inputs[i][0]);
|
||||
CV_Assert(inputs[0][0] == inputs[i][0]); // batch sizes are equal
|
||||
|
||||
// It's allowed for channels axis to be different.
|
||||
for (int j = 2; j < dims; j++)
|
||||
int input_channels = inputs[i][1];
|
||||
if (numChannels != input_channels)
|
||||
variableChannels = true;
|
||||
|
||||
if (channelsModeInput == ELTWISE_CHANNNELS_SAME)
|
||||
{
|
||||
CV_Assert(numChannels == input_channels);
|
||||
}
|
||||
else if (channelsModeInput == ELTWISE_CHANNNELS_INPUT_0)
|
||||
{
|
||||
CV_Assert(numChannels >= input_channels);
|
||||
}
|
||||
else if (channelsModeInput == ELTWISE_CHANNNELS_INPUT_0_TRUNCATE)
|
||||
{
|
||||
// nothing to check
|
||||
}
|
||||
else if (channelsModeInput == ELTWISE_CHANNNELS_USE_MAX)
|
||||
{
|
||||
numChannels = std::max(numChannels, input_channels);
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_Assert(0 && "Internal error");
|
||||
}
|
||||
|
||||
for (size_t j = 2; j < dims; j++)
|
||||
CV_Assert(inputs[0][j] == inputs[i][j]);
|
||||
}
|
||||
|
||||
channelsMode = variableChannels ? channelsModeInput : ELTWISE_CHANNNELS_SAME;
|
||||
outputChannels = numChannels;
|
||||
|
||||
outputs.assign(1, inputs[0]);
|
||||
outputs[0][1] = numChannels;
|
||||
return false;
|
||||
}
|
||||
|
||||
void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays) CV_OVERRIDE
|
||||
{
|
||||
std::vector<Mat> inputs;
|
||||
inputs_arr.getMatVector(inputs);
|
||||
variableChannels = false;
|
||||
for (int i = 1; i < inputs.size(); ++i)
|
||||
{
|
||||
if (inputs[i].size[1] != inputs[0].size[1])
|
||||
{
|
||||
variableChannels = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class EltwiseInvoker : public ParallelLoopBody
|
||||
{
|
||||
public:
|
||||
EltwiseLayerImpl& self;
|
||||
std::vector<const Mat*> srcs;
|
||||
std::vector<int> srcNumChannels;
|
||||
int nsrcs;
|
||||
Mat* dst;
|
||||
std::vector<float> coeffs;
|
||||
EltwiseOp op;
|
||||
int nstripes;
|
||||
const ActivationLayer* activ;
|
||||
int channels;
|
||||
size_t planeSize;
|
||||
|
||||
EltwiseInvoker() : nsrcs(0), dst(0), op(PROD), nstripes(0), activ(0), channels(0), planeSize(0) {}
|
||||
EltwiseInvoker(EltwiseLayerImpl& self_)
|
||||
: self(self_)
|
||||
, nsrcs(0), dst(0), nstripes(0), activ(0), channels(0)
|
||||
, planeSize(0)
|
||||
{}
|
||||
|
||||
static void run(const Mat* srcs, int nsrcs, Mat& dst,
|
||||
const std::vector<float>& coeffs, EltwiseOp op,
|
||||
const ActivationLayer* activ, int nstripes)
|
||||
public:
|
||||
static void run(EltwiseLayerImpl& self,
|
||||
const Mat* srcs, int nsrcs, Mat& dst,
|
||||
int nstripes)
|
||||
{
|
||||
const EltwiseOp op = self.op;
|
||||
CV_Check(dst.dims, 1 < dst.dims && dst.dims <= 5, ""); CV_CheckTypeEQ(dst.type(), CV_32FC1, ""); CV_Assert(dst.isContinuous());
|
||||
CV_Assert(coeffs.empty() || coeffs.size() == (size_t)nsrcs);
|
||||
CV_Assert(self.coeffs.empty() || self.coeffs.size() == (size_t)nsrcs);
|
||||
CV_CheckGE(nsrcs, 2, "");
|
||||
|
||||
EltwiseInvoker p;
|
||||
CV_Assert(self.outputChannels == dst.size[1]);
|
||||
|
||||
EltwiseInvoker p(self);
|
||||
p.srcs.resize(nsrcs);
|
||||
p.coeffs = coeffs;
|
||||
p.srcNumChannels.resize(nsrcs);
|
||||
p.coeffs = self.coeffs; // can be sorted
|
||||
|
||||
bool sortInputs = false;
|
||||
for( int i = 0; i < nsrcs; i++ )
|
||||
{
|
||||
p.srcs[i] = srcs + i;
|
||||
CV_Assert(srcs[i].type() == dst.type() &&
|
||||
srcs[i].isContinuous());
|
||||
// Sort srcs and coefficients in the order by number of channels
|
||||
for( int j = i; j >= 1 && p.srcs[j - 1]->size[1] < p.srcs[j]->size[1]; j-- )
|
||||
p.srcs[i] = &srcs[i];
|
||||
CV_CheckEQ(srcs[i].dims, dst.dims, "");
|
||||
CV_Assert(srcs[i].isContinuous());
|
||||
CV_Assert(srcs[i].type() == dst.type());
|
||||
p.srcNumChannels[i] = (srcs[i].dims >= 4) ? srcs[i].size[1] : 1;
|
||||
|
||||
if (self.channelsMode == ELTWISE_CHANNNELS_SAME)
|
||||
{
|
||||
std::swap(p.srcs[j - 1], p.srcs[j]);
|
||||
if (!p.coeffs.empty())
|
||||
std::swap(p.coeffs[j - 1], p.coeffs[j]);
|
||||
CV_Assert(srcs[i].size == dst.size);
|
||||
}
|
||||
else if (self.channelsMode == ELTWISE_CHANNNELS_INPUT_0)
|
||||
{
|
||||
if (i == 0)
|
||||
CV_Assert(srcs[0].size == dst.size);
|
||||
CV_Assert(self.outputChannels >= p.srcNumChannels[i]);
|
||||
sortInputs = true;
|
||||
}
|
||||
else if (self.channelsMode == ELTWISE_CHANNNELS_INPUT_0_TRUNCATE)
|
||||
{
|
||||
if (i == 0)
|
||||
CV_Assert(srcs[0].size == dst.size);
|
||||
sortInputs = true;
|
||||
}
|
||||
else if (self.channelsMode == ELTWISE_CHANNNELS_USE_MAX)
|
||||
{
|
||||
CV_Assert(op == SUM);
|
||||
CV_Assert(self.outputChannels >= p.srcNumChannels[i]);
|
||||
sortInputs = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_Assert(0 && "Internal error");
|
||||
}
|
||||
|
||||
if (sortInputs)
|
||||
{
|
||||
// Sort srcs and coefficients in the desc order by number of channels
|
||||
for (int j = i; j >= 1; j--)
|
||||
{
|
||||
if (std::min(self.outputChannels, p.srcs[j - 1]->size[1]) < std::min(self.outputChannels, p.srcs[j]->size[1]))
|
||||
{
|
||||
std::swap(p.srcs[j - 1], p.srcs[j]);
|
||||
std::swap(p.srcNumChannels[j - 1], p.srcNumChannels[j]);
|
||||
if (!p.coeffs.empty())
|
||||
std::swap(p.coeffs[j - 1], p.coeffs[j]);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p.nsrcs = nsrcs;
|
||||
p.dst = &dst;
|
||||
p.op = op;
|
||||
p.nstripes = nstripes;
|
||||
p.channels = (dst.dims >= 4 ? dst.size[1] : 1);
|
||||
|
||||
p.planeSize = dst.total(dst.dims >= 4 ? 2 : 1);
|
||||
CV_Assert(dst.total() == dst.size[0] * p.channels * p.planeSize);
|
||||
CV_CheckEQ(dst.total(), dst.size[0] * p.channels * p.planeSize, "");
|
||||
|
||||
bool simpleCoeffs = true;
|
||||
if( op == SUM && !coeffs.empty() )
|
||||
if (op == SUM && !p.coeffs.empty())
|
||||
{
|
||||
CV_Assert( coeffs.size() == (size_t)nsrcs );
|
||||
CV_CheckEQ(p.coeffs.size(), (size_t)nsrcs, "");
|
||||
|
||||
for( size_t i = 0; i < coeffs.size(); i++ )
|
||||
if( coeffs[i] != 1 )
|
||||
for (size_t i = 0; i < p.coeffs.size(); i++)
|
||||
{
|
||||
if (p.coeffs[i] != 1)
|
||||
{
|
||||
simpleCoeffs = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (simpleCoeffs)
|
||||
p.coeffs.clear();
|
||||
p.activ = activ;
|
||||
p.activ = self.activ.get();
|
||||
|
||||
parallel_for_(Range(0, nstripes), p, nstripes);
|
||||
}
|
||||
|
||||
void operator()(const Range& r) const CV_OVERRIDE
|
||||
{
|
||||
const EltwiseOp op = self.op;
|
||||
size_t total = dst->size[0]*planeSize;
|
||||
size_t stripeSize = (total + nstripes - 1)/nstripes;
|
||||
size_t stripeStart = r.start*stripeSize;
|
||||
size_t stripeEnd = std::min(r.end*stripeSize, total);
|
||||
int c, j, k, n;
|
||||
const float* coeffsptr = !coeffs.empty() ? &coeffs[0] : 0;
|
||||
float* dstptr0 = dst->ptr<float>();
|
||||
int blockSize0 = 1 << 12, blockSize;
|
||||
int blockSize0 = 1 << 12;
|
||||
|
||||
for( size_t ofs = stripeStart; ofs < stripeEnd; ofs += blockSize )
|
||||
for (size_t ofs = stripeStart; ofs < stripeEnd; )
|
||||
{
|
||||
int sampleIdx = (int)(ofs / planeSize);
|
||||
int delta = (int)ofs - sampleIdx * planeSize;
|
||||
blockSize = std::min(blockSize0, std::min((int)(stripeEnd - ofs), (int)planeSize - delta));
|
||||
int blockSize = std::min(blockSize0, std::min((int)(stripeEnd - ofs), (int)planeSize - delta));
|
||||
if( blockSize <= 0 )
|
||||
break;
|
||||
ofs += blockSize;
|
||||
|
||||
for( c = 0; c < channels; c++ )
|
||||
for (int c = 0; c < channels; c++)
|
||||
{
|
||||
size_t globalDelta = delta + (sampleIdx*channels + c)*planeSize;
|
||||
const float* srcptr0 = srcs[0]->ptr<float>() + globalDelta;
|
||||
float* dstptr = dstptr0 + globalDelta;
|
||||
size_t dstIdx = delta + (sampleIdx*channels + c)*planeSize;
|
||||
float* dstptr = dstptr0 + dstIdx;
|
||||
|
||||
// This code assumes that srcs are sorted in descending order by channels.
|
||||
for (n = 1; n < nsrcs && c < srcs[n]->size[1]; ++n) {}
|
||||
|
||||
if (n == 1)
|
||||
// process first two inputs
|
||||
{
|
||||
if( !coeffsptr )
|
||||
const float* srcptr0 = srcs[0]->ptr<float>() + dstIdx;
|
||||
|
||||
const int inputIdx = 1;
|
||||
int src1_channels = srcNumChannels[inputIdx];
|
||||
if (c >= src1_channels)
|
||||
{
|
||||
for( j = 0; j < blockSize; j++ )
|
||||
// no data from second input
|
||||
if (!coeffsptr || coeffsptr[0] == 1.0f)
|
||||
{
|
||||
dstptr[j] = srcptr0[j];
|
||||
for (int j = 0; j < blockSize; j++)
|
||||
{
|
||||
dstptr[j] = srcptr0[j];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float c0 = coeffsptr[0];
|
||||
for (int j = 0; j < blockSize; j++)
|
||||
{
|
||||
dstptr[j] = c0*srcptr0[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float c0 = coeffsptr[0];
|
||||
for( j = 0; j < blockSize; j++ )
|
||||
size_t srcIdx = delta + (sampleIdx * src1_channels + c) * planeSize;
|
||||
const float* srcptrI = srcs[inputIdx]->ptr<float>() + srcIdx;
|
||||
|
||||
if (op == PROD)
|
||||
{
|
||||
dstptr[j] = c0*srcptr0[j];
|
||||
for (int j = 0; j < blockSize; j++)
|
||||
{
|
||||
dstptr[j] = srcptr0[j] * srcptrI[j];
|
||||
}
|
||||
}
|
||||
else if (op == DIV)
|
||||
{
|
||||
for (int j = 0; j < blockSize; j++)
|
||||
{
|
||||
dstptr[j] = srcptr0[j] / srcptrI[j];
|
||||
}
|
||||
}
|
||||
else if (op == MAX)
|
||||
{
|
||||
for (int j = 0; j < blockSize; j++)
|
||||
{
|
||||
dstptr[j] = std::max(srcptr0[j], srcptrI[j]);
|
||||
}
|
||||
}
|
||||
else if (op == SUM)
|
||||
{
|
||||
if (!coeffsptr || (coeffsptr[0] == 1.0f && coeffsptr[1] == 1.0f))
|
||||
{
|
||||
for (int j = 0; j < blockSize; j++)
|
||||
{
|
||||
dstptr[j] = srcptr0[j] + srcptrI[j];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float c0 = coeffsptr[0];
|
||||
float c1 = coeffsptr[1];
|
||||
for (int j = 0; j < blockSize; j++)
|
||||
{
|
||||
dstptr[j] = c0*srcptr0[j] + c1*srcptrI[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
CV_Error(Error::StsInternal, "");
|
||||
}
|
||||
}
|
||||
else if( op == PROD )
|
||||
|
||||
// aggregate other inputs (3+)
|
||||
for (size_t inputIdx = 2; inputIdx < nsrcs; inputIdx++)
|
||||
{
|
||||
for( k = 1; k < n; k++ )
|
||||
int srcI_channels = srcNumChannels[inputIdx];
|
||||
if (c >= srcI_channels)
|
||||
continue; // no data from second input
|
||||
size_t srcIdx = delta + (sampleIdx * srcI_channels + c) * planeSize;
|
||||
const float* srcptrI = srcs[inputIdx]->ptr<float>() + srcIdx;
|
||||
|
||||
if (op == PROD)
|
||||
{
|
||||
const float* srcptr1 = srcs[k]->ptr<float>() + globalDelta;
|
||||
for( j = 0; j < blockSize; j++ )
|
||||
for (int j = 0; j < blockSize; j++)
|
||||
{
|
||||
dstptr[j] = srcptr0[j]*srcptr1[j];
|
||||
dstptr[j] *= srcptrI[j];
|
||||
}
|
||||
srcptr0 = (const float*)dstptr;
|
||||
}
|
||||
}
|
||||
else if( op == DIV )
|
||||
{
|
||||
for( k = 1; k < n; k++ )
|
||||
else if (op == DIV)
|
||||
{
|
||||
const float* srcptr1 = srcs[k]->ptr<float>() + globalDelta;
|
||||
for( j = 0; j < blockSize; j++ )
|
||||
for (int j = 0; j < blockSize; j++)
|
||||
{
|
||||
dstptr[j] = srcptr0[j]/srcptr1[j];
|
||||
dstptr[j] /= srcptrI[j];
|
||||
}
|
||||
srcptr0 = (const float*)dstptr;
|
||||
}
|
||||
}
|
||||
else if( op == MAX )
|
||||
{
|
||||
for( k = 1; k < n; k++ )
|
||||
else if (op == MAX)
|
||||
{
|
||||
const float* srcptr1 = srcs[k]->ptr<float>() + globalDelta;
|
||||
for( j = 0; j < blockSize; j++ )
|
||||
for (int j = 0; j < blockSize; j++)
|
||||
{
|
||||
dstptr[j] = std::max(srcptr0[j], srcptr1[j]);
|
||||
dstptr[j] = std::max(dstptr[j], srcptrI[j]);
|
||||
}
|
||||
srcptr0 = (const float*)dstptr;
|
||||
}
|
||||
}
|
||||
else if( !coeffsptr )
|
||||
{
|
||||
for( k = 1; k < n; k++ )
|
||||
else if (op == SUM)
|
||||
{
|
||||
const float* srcptr1 = srcs[k]->ptr<float>() + globalDelta;
|
||||
for( j = 0; j < blockSize; j++ )
|
||||
if (!coeffsptr || coeffsptr[inputIdx] == 1.0f)
|
||||
{
|
||||
dstptr[j] = srcptr0[j] + srcptr1[j];
|
||||
for (int j = 0; j < blockSize; j++)
|
||||
{
|
||||
dstptr[j] += srcptrI[j];
|
||||
}
|
||||
}
|
||||
srcptr0 = (const float*)dstptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float c0 = coeffsptr[0];
|
||||
for( k = 1; k < n; k++ )
|
||||
{
|
||||
const float* srcptr1 = srcs[k]->ptr<float>() + globalDelta;
|
||||
float c1 = coeffsptr[k];
|
||||
for( j = 0; j < blockSize; j++ )
|
||||
else
|
||||
{
|
||||
dstptr[j] = c0*srcptr0[j] + c1*srcptr1[j];
|
||||
float cI = coeffsptr[inputIdx];
|
||||
for (int j = 0; j < blockSize; j++)
|
||||
{
|
||||
dstptr[j] += cI * srcptrI[j];
|
||||
}
|
||||
}
|
||||
srcptr0 = (const float*)dstptr;
|
||||
c0 = 1;
|
||||
}
|
||||
else
|
||||
CV_Error(Error::StsInternal, "");
|
||||
}
|
||||
}
|
||||
|
||||
@ -350,7 +506,7 @@ public:
|
||||
std::vector<UMat> inputs;
|
||||
std::vector<UMat> outputs;
|
||||
|
||||
if ((inputs_.depth() == CV_16S && op != SUM) || variableChannels)
|
||||
if ((inputs_.depth() == CV_16S && op != SUM) || (channelsMode != ELTWISE_CHANNNELS_SAME))
|
||||
return false;
|
||||
|
||||
inputs_.getUMatVector(inputs);
|
||||
@ -453,8 +609,9 @@ public:
|
||||
|
||||
CV_Assert(outputs.size() == 1);
|
||||
const int nstripes = getNumThreads();
|
||||
EltwiseInvoker::run(&inputs[0], (int)inputs.size(), outputs[0],
|
||||
coeffs, op, activ.get(), nstripes);
|
||||
EltwiseInvoker::run(*this,
|
||||
&inputs[0], (int)inputs.size(), outputs[0],
|
||||
nstripes);
|
||||
}
|
||||
|
||||
#ifdef HAVE_CUDA
|
||||
@ -588,6 +745,7 @@ public:
|
||||
CV_UNUSED(outputs); // suppress unused variable warning
|
||||
CV_Assert(inputs.size());
|
||||
|
||||
// FIXIT: handle inputs with different number of channels
|
||||
long flops = inputs.size() * total(inputs[0]);
|
||||
|
||||
return flops;
|
||||
|
@ -630,8 +630,10 @@ public:
|
||||
auto upper_bounds = std::make_shared<ngraph::op::Constant>(ngraph::element::i64, ngraph::Shape{1}, std::vector<int64_t>{4});
|
||||
auto strides = std::make_shared<ngraph::op::Constant>(ngraph::element::i64, ngraph::Shape{1}, std::vector<int64_t>{1});
|
||||
|
||||
auto slice_layer = std::make_shared<ngraph::op::DynSlice>(layer_shape, lower_bounds, upper_bounds, strides);
|
||||
auto slice_image = std::make_shared<ngraph::op::DynSlice>(image_shape, lower_bounds, upper_bounds, strides);
|
||||
auto slice_layer = std::make_shared<ngraph::op::v1::StridedSlice>(layer_shape,
|
||||
lower_bounds, upper_bounds, strides, std::vector<int64_t>{}, std::vector<int64_t>{});
|
||||
auto slice_image = std::make_shared<ngraph::op::v1::StridedSlice>(image_shape,
|
||||
lower_bounds, upper_bounds, strides, std::vector<int64_t>{}, std::vector<int64_t>{});
|
||||
|
||||
if (_explicitSizes)
|
||||
{
|
||||
|
@ -370,8 +370,9 @@ public:
|
||||
auto strides = std::make_shared<ngraph::op::Constant>(ngraph::element::i64,
|
||||
ngraph::Shape{dims.size()}, std::vector<int64_t>((int64_t)dims.size(), 1));
|
||||
|
||||
auto slice = std::make_shared<ngraph::op::DynSlice>(ieInpNode, lower_bounds, upper_bounds,
|
||||
strides, ngraph::AxisSet{}, ngraph::AxisSet{});
|
||||
auto slice = std::make_shared<ngraph::op::v1::StridedSlice>(ieInpNode,
|
||||
lower_bounds, upper_bounds, strides, std::vector<int64_t>{}, std::vector<int64_t>{});
|
||||
|
||||
return Ptr<BackendNode>(new InfEngineNgraphNode(slice));
|
||||
}
|
||||
#endif // HAVE_DNN_NGRAPH
|
||||
|
@ -751,11 +751,16 @@ void InfEngineBackendNet::initPlugin(InferenceEngine::CNNNetwork& net)
|
||||
{
|
||||
if (layer->type == kOpenCVLayersType)
|
||||
{
|
||||
layer->affinity = "CPU";
|
||||
isHetero = true;
|
||||
#if INF_ENGINE_VER_MAJOR_LT(INF_ENGINE_RELEASE_2019R3)
|
||||
// Not sure about lower versions but in 2019R3 we do not need this
|
||||
layer->affinity = "CPU";
|
||||
}
|
||||
else
|
||||
{
|
||||
layer->affinity = device_name;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isHetero)
|
||||
|
@ -99,6 +99,7 @@ class Test_Darknet_layers : public DNNTestLayer
|
||||
public:
|
||||
void testDarknetLayer(const std::string& name, bool hasWeights = false)
|
||||
{
|
||||
SCOPED_TRACE(name);
|
||||
Mat inp = blobFromNPY(findDataFile("dnn/darknet/" + name + "_in.npy"));
|
||||
Mat ref = blobFromNPY(findDataFile("dnn/darknet/" + name + "_out.npy"));
|
||||
|
||||
@ -115,6 +116,47 @@ public:
|
||||
net.setInput(inp);
|
||||
Mat out = net.forward();
|
||||
normAssert(out, ref, "", default_l1, default_lInf);
|
||||
|
||||
if (inp.size[0] == 1) // test handling of batch size
|
||||
{
|
||||
SCOPED_TRACE("batch size 2");
|
||||
|
||||
#if defined(INF_ENGINE_RELEASE)
|
||||
if (target == DNN_TARGET_MYRIAD && name == "shortcut")
|
||||
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD);
|
||||
#endif
|
||||
|
||||
std::vector<int> sz2 = shape(inp);
|
||||
sz2[0] = 2;
|
||||
|
||||
Net net2 = readNet(cfg, model);
|
||||
net2.setPreferableBackend(backend);
|
||||
net2.setPreferableTarget(target);
|
||||
Range ranges0[4] = { Range(0, 1), Range::all(), Range::all(), Range::all() };
|
||||
Range ranges1[4] = { Range(1, 2), Range::all(), Range::all(), Range::all() };
|
||||
Mat inp2(sz2, inp.type(), Scalar::all(0));
|
||||
inp.copyTo(inp2(ranges0));
|
||||
inp.copyTo(inp2(ranges1));
|
||||
net2.setInput(inp2);
|
||||
Mat out2 = net2.forward();
|
||||
EXPECT_EQ(0, cv::norm(out2(ranges0), out2(ranges1), NORM_INF)) << "Batch result is not equal: " << name;
|
||||
|
||||
Mat ref2 = ref;
|
||||
if (ref.dims == 2 && out2.dims == 3)
|
||||
{
|
||||
int ref_3d_sizes[3] = {1, ref.rows, ref.cols};
|
||||
ref2 = Mat(3, ref_3d_sizes, ref.type(), (void*)ref.data);
|
||||
}
|
||||
/*else if (ref.dims == 3 && out2.dims == 4)
|
||||
{
|
||||
int ref_4d_sizes[4] = {1, ref.size[0], ref.size[1], ref.size[2]};
|
||||
ref2 = Mat(4, ref_4d_sizes, ref.type(), (void*)ref.data);
|
||||
}*/
|
||||
ASSERT_EQ(out2.dims, ref2.dims) << ref.dims;
|
||||
|
||||
normAssert(out2(ranges0), ref2, "", default_l1, default_lInf);
|
||||
normAssert(out2(ranges1), ref2, "", default_l1, default_lInf);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1587,30 +1587,28 @@ TEST(Layer_Test_Convolution, relu_fusion)
|
||||
}
|
||||
|
||||
typedef testing::TestWithParam<tuple<bool, tuple<Backend, Target> > > Layer_Test_Eltwise_unequal;
|
||||
TEST_P(Layer_Test_Eltwise_unequal, Accuracy)
|
||||
TEST_P(Layer_Test_Eltwise_unequal, accuracy_input_0_truncate)
|
||||
{
|
||||
bool weighted = get<0>(GetParam());
|
||||
int backendId = get<0>(get<1>(GetParam()));
|
||||
int targetId = get<1>(get<1>(GetParam()));
|
||||
|
||||
if (backendId == DNN_BACKEND_OPENCV && targetId == DNN_TARGET_OPENCL_FP16)
|
||||
applyTestTag(CV_TEST_TAG_DNN_SKIP_OPENCL_FP16);
|
||||
|
||||
Net net;
|
||||
LayerParams lp;
|
||||
lp.type = "Eltwise";
|
||||
lp.name = "testLayer";
|
||||
lp.set<std::string>("output_channels_mode", "input_0_truncate");
|
||||
|
||||
const int inpShapes[][4] = {{1, 4, 2, 2}, {1, 5, 2, 2}, {1, 3, 2, 2}};
|
||||
const int out_channels = inpShapes[0][1];
|
||||
std::vector<String> inpNames(3);
|
||||
std::vector<Mat> inputs(3);
|
||||
size_t numOutValues = 1*4*2*2; // By the first input
|
||||
|
||||
std::vector<float> weights(3, 1);
|
||||
if (weighted)
|
||||
{
|
||||
for (int i = 0; i < inputs.size(); ++i)
|
||||
randu(Mat(1, 1, CV_32F, &weights[i]), -1, 1);
|
||||
weights[i] = -0.125f + i * 0.25f;
|
||||
lp.set("coeff", DictValue::arrayReal<float*>(&weights[0], weights.size()));
|
||||
}
|
||||
|
||||
@ -1618,27 +1616,103 @@ TEST_P(Layer_Test_Eltwise_unequal, Accuracy)
|
||||
for (int i = 0; i < inputs.size(); ++i)
|
||||
{
|
||||
inputs[i].create(4, inpShapes[i], CV_32F);
|
||||
randu(inputs[i], 0, 255);
|
||||
size_t total = inputs[i].total();
|
||||
for (size_t j = 0; j < total; j++)
|
||||
inputs[i].ptr<float>()[j] = j + i * 100;
|
||||
inpNames[i] = format("input_%d", i);
|
||||
net.connect(0, i, eltwiseId, i);
|
||||
}
|
||||
Mat ref(1, numOutValues, CV_32F, Scalar(0));
|
||||
Mat ref(4, inpShapes[0], CV_32F, Scalar(0));
|
||||
|
||||
net.setInputsNames(inpNames);
|
||||
for (int i = 0; i < inputs.size(); ++i)
|
||||
{
|
||||
//std::cout << ref.reshape(1,1) << endl;
|
||||
net.setInput(inputs[i], inpNames[i]);
|
||||
if (numOutValues >= inputs[i].total())
|
||||
ref.colRange(0, inputs[i].total()) += weights[i] * inputs[i].reshape(1, 1);
|
||||
else
|
||||
ref += weights[i] * inputs[i].reshape(1, 1).colRange(0, numOutValues);
|
||||
for (size_t batchId = 0; batchId < ref.size[0]; batchId++)
|
||||
{
|
||||
int input_channels = inputs[i].size[1];
|
||||
Range ranges[4] = { Range(batchId, batchId + 1), Range(0, std::min(out_channels, input_channels)), Range::all(), Range::all() };
|
||||
Mat ref_slice = ref(ranges);
|
||||
Mat input_slice = inputs[i](ranges);
|
||||
ref_slice += weights[i] * input_slice;
|
||||
}
|
||||
}
|
||||
|
||||
net.setPreferableBackend(backendId);
|
||||
net.setPreferableTarget(targetId);
|
||||
Mat out = net.forward();
|
||||
normAssert(out.reshape(1, 1), ref);
|
||||
normAssert(out, ref);
|
||||
if (testing::Test::HasFailure())
|
||||
{
|
||||
std::cout << out.reshape(1,1) << endl;
|
||||
std::cout << ref.reshape(1,1) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(Layer_Test_Eltwise_unequal, accuracy_input_0)
|
||||
{
|
||||
bool weighted = get<0>(GetParam());
|
||||
int backendId = get<0>(get<1>(GetParam()));
|
||||
int targetId = get<1>(get<1>(GetParam()));
|
||||
|
||||
Net net;
|
||||
LayerParams lp;
|
||||
lp.type = "Eltwise";
|
||||
lp.name = "testLayer";
|
||||
lp.set<std::string>("output_channels_mode", "input_0");
|
||||
|
||||
const int inpShapes[][4] = {{1, 4, 2, 2}, {1, 2, 2, 2}, {1, 3, 2, 2}};
|
||||
const int out_channels = inpShapes[0][1];
|
||||
std::vector<String> inpNames(3);
|
||||
std::vector<Mat> inputs(3);
|
||||
|
||||
std::vector<float> weights(3, 1);
|
||||
if (weighted)
|
||||
{
|
||||
for (int i = 0; i < inputs.size(); ++i)
|
||||
weights[i] = -0.125f + i * 0.25f;
|
||||
lp.set("coeff", DictValue::arrayReal<float*>(&weights[0], weights.size()));
|
||||
}
|
||||
|
||||
int eltwiseId = net.addLayer(lp.name, lp.type, lp);
|
||||
for (int i = 0; i < inputs.size(); ++i)
|
||||
{
|
||||
inputs[i].create(4, inpShapes[i], CV_32F);
|
||||
size_t total = inputs[i].total();
|
||||
for (size_t j = 0; j < total; j++)
|
||||
inputs[i].ptr<float>()[j] = j + i * 100;
|
||||
inpNames[i] = format("input_%d", i);
|
||||
net.connect(0, i, eltwiseId, i);
|
||||
}
|
||||
Mat ref(4, inpShapes[0], CV_32F, Scalar(0));
|
||||
|
||||
net.setInputsNames(inpNames);
|
||||
for (int i = 0; i < inputs.size(); ++i)
|
||||
{
|
||||
//std::cout << ref.reshape(1,1) << endl;
|
||||
net.setInput(inputs[i], inpNames[i]);
|
||||
for (size_t batchId = 0; batchId < ref.size[0]; batchId++)
|
||||
{
|
||||
int input_channels = inputs[i].size[1];
|
||||
Range ranges[4] = { Range(batchId, batchId + 1), Range(0, std::min(out_channels, input_channels)), Range::all(), Range::all() };
|
||||
Mat ref_slice = ref(ranges);
|
||||
Mat input_slice = inputs[i](ranges);
|
||||
ref_slice += weights[i] * input_slice;
|
||||
}
|
||||
}
|
||||
|
||||
net.setPreferableBackend(backendId);
|
||||
net.setPreferableTarget(targetId);
|
||||
Mat out = net.forward();
|
||||
normAssert(out, ref);
|
||||
if (testing::Test::HasFailure())
|
||||
{
|
||||
std::cout << out.reshape(1,1) << endl;
|
||||
std::cout << ref.reshape(1,1) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Layer_Test_Eltwise_unequal, Combine(
|
||||
testing::Bool(),
|
||||
dnnBackendsAndTargets()
|
||||
|
@ -1113,11 +1113,11 @@ public:
|
||||
*/
|
||||
CV_WRAP void getTriangleList(CV_OUT std::vector<Vec6f>& triangleList) const;
|
||||
|
||||
/** @brief Returns a list of all Voroni facets.
|
||||
/** @brief Returns a list of all Voronoi facets.
|
||||
|
||||
@param idx Vector of vertices IDs to consider. For all vertices you can pass empty vector.
|
||||
@param facetList Output vector of the Voroni facets.
|
||||
@param facetCenters Output vector of the Voroni facets center points.
|
||||
@param facetList Output vector of the Voronoi facets.
|
||||
@param facetCenters Output vector of the Voronoi facets center points.
|
||||
|
||||
*/
|
||||
CV_WRAP void getVoronoiFacetList(const std::vector<int>& idx, CV_OUT std::vector<std::vector<Point2f> >& facetList,
|
||||
|
@ -7,6 +7,31 @@ namespace opencv_test {
|
||||
|
||||
typedef tuple<MatType, Size, Size> MatInfo_Size_Size_t;
|
||||
typedef TestBaseWithParam<MatInfo_Size_Size_t> MatInfo_Size_Size;
|
||||
typedef tuple<Size,Size> Size_Size_t;
|
||||
typedef tuple<MatType, Size_Size_t> MatInfo_SizePair_t;
|
||||
typedef TestBaseWithParam<MatInfo_SizePair_t> MatInfo_SizePair;
|
||||
|
||||
#define MATTYPE_NE_VALUES CV_8UC1, CV_8UC2, CV_8UC3, CV_8UC4, \
|
||||
CV_16UC1, CV_16UC2, CV_16UC3, CV_16UC4, \
|
||||
CV_32FC1, CV_32FC2, CV_32FC3, CV_32FC4
|
||||
|
||||
// For gradient-ish testing of the other matrix formats
|
||||
template<typename T>
|
||||
static void fillFPGradient(Mat& img)
|
||||
{
|
||||
const int ch = img.channels();
|
||||
|
||||
int r, c, i;
|
||||
for(r=0; r<img.rows; r++)
|
||||
{
|
||||
for(c=0; c<img.cols; c++)
|
||||
{
|
||||
T vals[] = {(T)r, (T)c, (T)(r*c), (T)(r*c/(r+c+1))};
|
||||
T *p = (T*)img.ptr(r, c);
|
||||
for(i=0; i<ch; i++) p[i] = (T)vals[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PERF_TEST_P(MatInfo_Size_Size, resizeUpLinear,
|
||||
testing::Values(
|
||||
@ -38,6 +63,33 @@ PERF_TEST_P(MatInfo_Size_Size, resizeUpLinear,
|
||||
#endif
|
||||
}
|
||||
|
||||
PERF_TEST_P(MatInfo_SizePair, resizeUpLinearNonExact,
|
||||
testing::Combine
|
||||
(
|
||||
testing::Values( MATTYPE_NE_VALUES ),
|
||||
testing::Values( Size_Size_t(szVGA, szqHD), Size_Size_t(szVGA, sz720p) )
|
||||
)
|
||||
)
|
||||
{
|
||||
int matType = get<0>(GetParam());
|
||||
Size_Size_t sizes = get<1>(GetParam());
|
||||
Size from = get<0>(sizes);
|
||||
Size to = get<1>(sizes);
|
||||
|
||||
cv::Mat src(from, matType), dst(to, matType);
|
||||
switch(src.depth())
|
||||
{
|
||||
case CV_8U: cvtest::fillGradient(src); break;
|
||||
case CV_16U: fillFPGradient<ushort>(src); break;
|
||||
case CV_32F: fillFPGradient<float>(src); break;
|
||||
}
|
||||
declare.in(src).out(dst);
|
||||
|
||||
TEST_CYCLE_MULTIRUN(10) resize(src, dst, to, 0, 0, INTER_LINEAR);
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST_P(MatInfo_Size_Size, resizeDownLinear,
|
||||
testing::Values(
|
||||
MatInfo_Size_Size_t(CV_8UC1, szVGA, szQVGA),
|
||||
@ -80,6 +132,40 @@ PERF_TEST_P(MatInfo_Size_Size, resizeDownLinear,
|
||||
#endif
|
||||
}
|
||||
|
||||
PERF_TEST_P(MatInfo_SizePair, resizeDownLinearNonExact,
|
||||
testing::Combine
|
||||
(
|
||||
testing::Values( MATTYPE_NE_VALUES ),
|
||||
testing::Values
|
||||
(
|
||||
Size_Size_t(szVGA, szQVGA),
|
||||
Size_Size_t(szqHD, szVGA),
|
||||
Size_Size_t(sz720p, Size(120 * sz720p.width / sz720p.height, 120)),
|
||||
Size_Size_t(sz720p, szVGA),
|
||||
Size_Size_t(sz720p, szQVGA)
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
int matType = get<0>(GetParam());
|
||||
Size_Size_t sizes = get<1>(GetParam());
|
||||
Size from = get<0>(sizes);
|
||||
Size to = get<1>(sizes);
|
||||
|
||||
cv::Mat src(from, matType), dst(to, matType);
|
||||
switch(src.depth())
|
||||
{
|
||||
case CV_8U: cvtest::fillGradient(src); break;
|
||||
case CV_16U: fillFPGradient<ushort>(src); break;
|
||||
case CV_32F: fillFPGradient<float>(src); break;
|
||||
}
|
||||
declare.in(src).out(dst);
|
||||
|
||||
TEST_CYCLE_MULTIRUN(10) resize(src, dst, to, 0, 0, INTER_LINEAR);
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
|
||||
typedef tuple<MatType, Size, int> MatInfo_Size_Scale_t;
|
||||
typedef TestBaseWithParam<MatInfo_Size_Scale_t> MatInfo_Size_Scale;
|
||||
|
@ -677,6 +677,13 @@ void cv::approxPolyDP( InputArray _curve, OutputArray _approxCurve,
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
//Prevent unreasonable error values (Douglas-Peucker algorithm)
|
||||
//from being used.
|
||||
if (epsilon < 0.0 || !(epsilon < 1e30))
|
||||
{
|
||||
CV_Error(CV_StsOutOfRange, "Epsilon not valid.");
|
||||
}
|
||||
|
||||
Mat curve = _curve.getMat();
|
||||
int npoints = curve.checkVector(2), depth = curve.depth();
|
||||
CV_Assert( npoints >= 0 && (depth == CV_32S || depth == CV_32F));
|
||||
|
@ -224,7 +224,10 @@ struct OclHelper
|
||||
int scn = src.channels();
|
||||
int depth = src.depth();
|
||||
|
||||
CV_Assert( VScn::contains(scn) && VDcn::contains(dcn) && VDepth::contains(depth) );
|
||||
CV_Check(scn, VScn::contains(scn), "Invalid number of channels in input image");
|
||||
CV_Check(dcn, VDcn::contains(dcn), "Invalid number of channels in output image");
|
||||
CV_CheckDepth(depth, VDepth::contains(depth), "Unsupported depth of input image");
|
||||
|
||||
switch (sizePolicy)
|
||||
{
|
||||
case TO_YUV:
|
||||
|
@ -75,8 +75,8 @@ calcHistLookupTables_8u( const Mat& hist, const SparseMat& shist,
|
||||
int sz = !issparse ? hist.size[i] : shist.size(i);
|
||||
size_t step = !issparse ? hist.step[i] : 1;
|
||||
|
||||
double v_lo = ranges[i][0];
|
||||
double v_hi = ranges[i][1];
|
||||
double v_lo = ranges ? ranges[i][0] : 0;
|
||||
double v_hi = ranges ? ranges[i][1] : 256;
|
||||
|
||||
for( j = low; j < high; j++ )
|
||||
{
|
||||
@ -183,7 +183,7 @@ static void histPrepareImages( const Mat* images, int nimages, const int* channe
|
||||
imsize.height = 1;
|
||||
}
|
||||
|
||||
if( !ranges )
|
||||
if( !ranges ) // implicit uniform ranges for 8U
|
||||
{
|
||||
CV_Assert( depth == CV_8U );
|
||||
|
||||
@ -951,6 +951,8 @@ void cv::calcHist( const Mat* images, int nimages, const int* channels,
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
CV_Assert(images && nimages > 0);
|
||||
|
||||
CV_OVX_RUN(
|
||||
images && histSize &&
|
||||
nimages == 1 && images[0].type() == CV_8UC1 && dims == 1 && _mask.getMat().empty() &&
|
||||
@ -1261,6 +1263,8 @@ void cv::calcHist( const Mat* images, int nimages, const int* channels,
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
CV_Assert(images && nimages > 0);
|
||||
|
||||
Mat mask = _mask.getMat();
|
||||
calcHist( images, nimages, channels, mask, hist, dims, histSize,
|
||||
ranges, uniform, accumulate, false );
|
||||
@ -1608,6 +1612,8 @@ void cv::calcBackProject( const Mat* images, int nimages, const int* channels,
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
CV_Assert(images && nimages > 0);
|
||||
|
||||
Mat hist = _hist.getMat();
|
||||
std::vector<uchar*> ptrs;
|
||||
std::vector<int> deltas;
|
||||
@ -1777,6 +1783,8 @@ void cv::calcBackProject( const Mat* images, int nimages, const int* channels,
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
CV_Assert(images && nimages > 0);
|
||||
|
||||
std::vector<uchar*> ptrs;
|
||||
std::vector<int> deltas;
|
||||
std::vector<double> uniranges;
|
||||
|
@ -1481,10 +1481,330 @@ typedef VResizeNoVec VResizeLanczos4Vec_32f;
|
||||
|
||||
#endif
|
||||
|
||||
#if CV_SIMD128
|
||||
|
||||
template<typename ST, typename DT, typename AT, typename DVT>
|
||||
struct HResizeLinearVec_X4
|
||||
{
|
||||
int operator()(const uchar** _src, uchar** _dst, int count, const int* xofs,
|
||||
const uchar* _alpha, int, int, int cn, int, int xmax) const
|
||||
{
|
||||
const ST **src = (const ST**)_src;
|
||||
const AT *alpha = (const AT*)_alpha;
|
||||
DT **dst = (DT**)_dst;
|
||||
const int nlanes = 4;
|
||||
const int len0 = xmax & -nlanes;
|
||||
int dx = 0, k = 0;
|
||||
|
||||
for( ; k <= (count - 2); k+=2 )
|
||||
{
|
||||
const ST *S0 = src[k];
|
||||
DT *D0 = dst[k];
|
||||
const ST *S1 = src[k+1];
|
||||
DT *D1 = dst[k+1];
|
||||
|
||||
for( dx = 0; dx < len0; dx += nlanes )
|
||||
{
|
||||
int sx0 = xofs[dx+0];
|
||||
int sx1 = xofs[dx+1];
|
||||
int sx2 = xofs[dx+2];
|
||||
int sx3 = xofs[dx+3];
|
||||
DVT a_even;
|
||||
DVT a_odd;
|
||||
|
||||
v_load_deinterleave(&alpha[dx*2], a_even, a_odd);
|
||||
DVT s0(S0[sx0], S0[sx1], S0[sx2], S0[sx3]);
|
||||
DVT s1(S0[sx0+cn], S0[sx1+cn], S0[sx2+cn], S0[sx3+cn]);
|
||||
DVT s0_u(S1[sx0], S1[sx1], S1[sx2], S1[sx3]);
|
||||
DVT s1_u(S1[sx0+cn], S1[sx1+cn], S1[sx2+cn], S1[sx3+cn]);
|
||||
v_store(&D1[dx], s0_u * a_even + s1_u * a_odd);
|
||||
v_store(&D0[dx], s0 * a_even + s1 * a_odd);
|
||||
}
|
||||
}
|
||||
for( ; k < count; k++ )
|
||||
{
|
||||
const ST *S = src[k];
|
||||
DT *D = dst[k];
|
||||
for( dx = 0; dx < len0; dx += nlanes )
|
||||
{
|
||||
int sx0 = xofs[dx+0];
|
||||
int sx1 = xofs[dx+1];
|
||||
int sx2 = xofs[dx+2];
|
||||
int sx3 = xofs[dx+3];
|
||||
DVT a_even;
|
||||
DVT a_odd;
|
||||
|
||||
v_load_deinterleave(&alpha[dx*2], a_even, a_odd);
|
||||
DVT s0(S[sx0], S[sx1], S[sx2], S[sx3]);
|
||||
DVT s1(S[sx0+cn], S[sx1+cn], S[sx2+cn], S[sx3+cn]);
|
||||
v_store(&D[dx], s0 * a_even + s1 * a_odd);
|
||||
}
|
||||
}
|
||||
return dx;
|
||||
}
|
||||
};
|
||||
|
||||
struct HResizeLinearVecU8_X4
|
||||
{
|
||||
int operator()(const uchar** src, uchar** _dst, int count, const int* xofs,
|
||||
const uchar* _alpha, int smax, int, int cn, int, int xmax) const
|
||||
{
|
||||
const short *alpha = (const short*)_alpha;
|
||||
int **dst = (int**)_dst;
|
||||
int dx = 0, k = 0;
|
||||
|
||||
if(cn == 1)
|
||||
{
|
||||
const int step = 8;
|
||||
const int len0 = xmax & -step;
|
||||
for( ; k <= (count - 2); k+=2 )
|
||||
{
|
||||
const uchar *S0 = src[k];
|
||||
int *D0 = dst[k];
|
||||
const uchar *S1 = src[k+1];
|
||||
int *D1 = dst[k+1];
|
||||
|
||||
for( dx = 0; dx < len0; dx += step )
|
||||
{
|
||||
v_int16x8 al = v_load(alpha+dx*2);
|
||||
v_int16x8 ah = v_load(alpha+dx*2+8);
|
||||
v_uint16x8 sl, sh;
|
||||
v_expand(v_lut_pairs(S0, xofs+dx), sl, sh);
|
||||
v_store(&D0[dx], v_dotprod(v_reinterpret_as_s16(sl), al));
|
||||
v_store(&D0[dx+4], v_dotprod(v_reinterpret_as_s16(sh), ah));
|
||||
v_expand(v_lut_pairs(S1, xofs+dx), sl, sh);
|
||||
v_store(&D1[dx], v_dotprod(v_reinterpret_as_s16(sl), al));
|
||||
v_store(&D1[dx+4], v_dotprod(v_reinterpret_as_s16(sh), ah));
|
||||
}
|
||||
}
|
||||
for( ; k < count; k++ )
|
||||
{
|
||||
const uchar *S = src[k];
|
||||
int *D = dst[k];
|
||||
for( dx = 0; dx < len0; dx += step )
|
||||
{
|
||||
v_int16x8 al = v_load(alpha+dx*2);
|
||||
v_int16x8 ah = v_load(alpha+dx*2+8);
|
||||
v_uint16x8 sl, sh;
|
||||
v_expand(v_lut_pairs(S, xofs+dx), sl, sh);
|
||||
v_store(&D[dx], v_dotprod(v_reinterpret_as_s16(sl), al));
|
||||
v_store(&D[dx+4], v_dotprod(v_reinterpret_as_s16(sh), ah));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(cn == 2)
|
||||
{
|
||||
const int step = 8;
|
||||
const int len0 = xmax & -step;
|
||||
for( ; k <= (count - 2); k+=2 )
|
||||
{
|
||||
const uchar *S0 = src[k];
|
||||
int *D0 = dst[k];
|
||||
const uchar *S1 = src[k+1];
|
||||
int *D1 = dst[k+1];
|
||||
|
||||
for( dx = 0; dx < len0; dx += step )
|
||||
{
|
||||
v_int16x8 al = v_load(alpha+dx*2);
|
||||
v_int16x8 ah = v_load(alpha+dx*2+8);
|
||||
v_uint16x8 sl, sh;
|
||||
v_expand(v_interleave_pairs(v_lut_quads(S0, xofs+dx)), sl, sh);
|
||||
v_store(&D0[dx], v_dotprod(v_reinterpret_as_s16(sl), al));
|
||||
v_store(&D0[dx+4], v_dotprod(v_reinterpret_as_s16(sh), ah));
|
||||
v_expand(v_interleave_pairs(v_lut_pairs(S1, xofs+dx)), sl, sh);
|
||||
v_store(&D1[dx], v_dotprod(v_reinterpret_as_s16(sl), al));
|
||||
v_store(&D1[dx+4], v_dotprod(v_reinterpret_as_s16(sh), ah));
|
||||
}
|
||||
}
|
||||
for( ; k < count; k++ )
|
||||
{
|
||||
const uchar *S = src[k];
|
||||
int *D = dst[k];
|
||||
for( dx = 0; dx < len0; dx += step )
|
||||
{
|
||||
v_int16x8 al = v_load(alpha+dx*2);
|
||||
v_int16x8 ah = v_load(alpha+dx*2+8);
|
||||
v_uint16x8 sl, sh;
|
||||
v_expand(v_interleave_pairs(v_lut_quads(S, xofs+dx)), sl, sh);
|
||||
v_store(&D[dx], v_dotprod(v_reinterpret_as_s16(sl), al));
|
||||
v_store(&D[dx+4], v_dotprod(v_reinterpret_as_s16(sh), ah));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(cn == 3)
|
||||
{
|
||||
int len0 = xmax - cn;
|
||||
|
||||
/* This may need to trim 1 or more extra units depending on the amount of
|
||||
scaling. Test until we find the first value which we know cannot overrun. */
|
||||
while (len0 >= cn &&
|
||||
xofs[len0 - cn] + cn >= smax - cn // check access: v_load_expand_q(S+xofs[dx]+cn)
|
||||
)
|
||||
{
|
||||
len0 -= cn;
|
||||
}
|
||||
CV_DbgAssert(len0 <= 0 || len0 >= cn);
|
||||
|
||||
for( ; k <= (count - 2); k+=2 )
|
||||
{
|
||||
const uchar *S0 = src[k];
|
||||
int *D0 = dst[k];
|
||||
const uchar *S1 = src[k+1];
|
||||
int *D1 = dst[k+1];
|
||||
|
||||
for( dx = 0; dx < len0; dx += cn )
|
||||
{
|
||||
v_int16x8 a = v_load(alpha+dx*2);
|
||||
v_store(&D0[dx], v_dotprod(v_reinterpret_as_s16(v_load_expand_q(S0+xofs[dx]) | (v_load_expand_q(S0+xofs[dx]+cn)<<16)), a));
|
||||
v_store(&D1[dx], v_dotprod(v_reinterpret_as_s16(v_load_expand_q(S1+xofs[dx]) | (v_load_expand_q(S1+xofs[dx]+cn)<<16)), a));
|
||||
}
|
||||
}
|
||||
for( ; k < count; k++ )
|
||||
{
|
||||
const uchar *S = src[k];
|
||||
int *D = dst[k];
|
||||
for( dx = 0; dx < len0; dx += cn )
|
||||
{
|
||||
v_int16x8 a = v_load(alpha+dx*2);
|
||||
v_store(&D[dx], v_dotprod(v_reinterpret_as_s16(v_load_expand_q(S+xofs[dx]) | (v_load_expand_q(S+xofs[dx]+cn)<<16)), a));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(cn == 4)
|
||||
{
|
||||
const int step = 4;
|
||||
const int len0 = xmax & -step;
|
||||
for( ; k <= (count - 2); k+=2 )
|
||||
{
|
||||
const uchar *S0 = src[k];
|
||||
int *D0 = dst[k];
|
||||
const uchar *S1 = src[k+1];
|
||||
int *D1 = dst[k+1];
|
||||
|
||||
for( dx = 0; dx < len0; dx += step )
|
||||
{
|
||||
v_int16x8 a = v_load(alpha+dx*2);
|
||||
v_store(&D0[dx], v_dotprod(v_reinterpret_as_s16(v_interleave_quads(v_load_expand(S0+xofs[dx]))), a));
|
||||
v_store(&D1[dx], v_dotprod(v_reinterpret_as_s16(v_interleave_quads(v_load_expand(S1+xofs[dx]))), a));
|
||||
}
|
||||
}
|
||||
for( ; k < count; k++ )
|
||||
{
|
||||
const uchar *S = src[k];
|
||||
int *D = dst[k];
|
||||
for( dx = 0; dx < len0; dx += step )
|
||||
{
|
||||
v_int16x8 a = v_load(alpha+dx*2);
|
||||
v_store(&D[dx], v_dotprod(v_reinterpret_as_s16(v_interleave_quads(v_load_expand(S+xofs[dx]))), a));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(cn < 9)
|
||||
{
|
||||
const int step = 8;
|
||||
const int len0 = xmax & -step;
|
||||
for( ; k <= (count - 2); k+=2 )
|
||||
{
|
||||
const uchar *S0 = src[k];
|
||||
int *D0 = dst[k];
|
||||
const uchar *S1 = src[k+1];
|
||||
int *D1 = dst[k+1];
|
||||
|
||||
for( dx = 0; dx < len0; dx += cn )
|
||||
{
|
||||
v_int16x8 a0 = v_load(alpha+dx*2);
|
||||
v_int16x8 a1 = v_load(alpha+dx*2 + 8);
|
||||
v_uint16x8 s0, s1;
|
||||
v_zip(v_load_expand(S0+xofs[dx]), v_load_expand(S0+xofs[dx]+cn), s0, s1);
|
||||
v_store(&D0[dx], v_dotprod(v_reinterpret_as_s16(s0), a0));
|
||||
v_store(&D0[dx+4], v_dotprod(v_reinterpret_as_s16(s1), a1));
|
||||
v_zip(v_load_expand(S1+xofs[dx]), v_load_expand(S1+xofs[dx]+cn), s0, s1);
|
||||
v_store(&D1[dx], v_dotprod(v_reinterpret_as_s16(s0), a0));
|
||||
v_store(&D1[dx+4], v_dotprod(v_reinterpret_as_s16(s1), a1));
|
||||
}
|
||||
}
|
||||
for( ; k < count; k++ )
|
||||
{
|
||||
const uchar *S = src[k];
|
||||
int *D = dst[k];
|
||||
for( dx = 0; dx < len0; dx += cn )
|
||||
{
|
||||
v_int16x8 a0 = v_load(alpha+dx*2);
|
||||
v_int16x8 a1 = v_load(alpha+dx*2 + 8);
|
||||
v_uint16x8 s0, s1;
|
||||
v_zip(v_load_expand(S+xofs[dx]), v_load_expand(S+xofs[dx]+cn), s0, s1);
|
||||
v_store(&D[dx], v_dotprod(v_reinterpret_as_s16(s0), a0));
|
||||
v_store(&D[dx+4], v_dotprod(v_reinterpret_as_s16(s1), a1));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const int step = 16;
|
||||
const int len0 = (xmax - cn) & -step;
|
||||
for( ; k <= (count - 2); k+=2 )
|
||||
{
|
||||
const uchar *S0 = src[k];
|
||||
int *D0 = dst[k];
|
||||
const uchar *S1 = src[k+1];
|
||||
int *D1 = dst[k+1];
|
||||
|
||||
for( dx = 0; dx < len0; dx += step )
|
||||
{
|
||||
v_int16x8 a0 = v_load(alpha+dx*2);
|
||||
v_int16x8 a1 = v_load(alpha+dx*2 + 8);
|
||||
v_int16x8 a2 = v_load(alpha+dx*2 + 16);
|
||||
v_int16x8 a3 = v_load(alpha+dx*2 + 24);
|
||||
v_uint8x16 s01, s23;
|
||||
v_zip(v_lut(S0, xofs+dx), v_lut(S0+cn, xofs+dx), s01, s23);
|
||||
v_store(&D0[dx], v_dotprod(v_reinterpret_as_s16(v_expand_low(s01)), a0));
|
||||
v_store(&D0[dx+4], v_dotprod(v_reinterpret_as_s16(v_expand_high(s01)), a1));
|
||||
v_store(&D0[dx+8], v_dotprod(v_reinterpret_as_s16(v_expand_low(s23)), a2));
|
||||
v_store(&D0[dx+12], v_dotprod(v_reinterpret_as_s16(v_expand_high(s23)), a3));
|
||||
v_zip(v_lut(S1, xofs+dx), v_lut(S1+cn, xofs+dx), s01, s23);
|
||||
v_store(&D1[dx], v_dotprod(v_reinterpret_as_s16(v_expand_low(s01)), a0));
|
||||
v_store(&D1[dx+4], v_dotprod(v_reinterpret_as_s16(v_expand_high(s01)), a1));
|
||||
v_store(&D1[dx+8], v_dotprod(v_reinterpret_as_s16(v_expand_low(s23)), a2));
|
||||
v_store(&D1[dx+12], v_dotprod(v_reinterpret_as_s16(v_expand_high(s23)), a3));
|
||||
}
|
||||
}
|
||||
for( ; k < count; k++ )
|
||||
{
|
||||
const uchar *S = src[k];
|
||||
int *D = dst[k];
|
||||
for( dx = 0; dx < len0; dx += step )
|
||||
{
|
||||
v_int16x8 a0 = v_load(alpha+dx*2);
|
||||
v_int16x8 a1 = v_load(alpha+dx*2 + 8);
|
||||
v_int16x8 a2 = v_load(alpha+dx*2 + 16);
|
||||
v_int16x8 a3 = v_load(alpha+dx*2 + 24);
|
||||
v_uint8x16 s01, s23;
|
||||
v_zip(v_lut(S, xofs+dx), v_lut(S+cn, xofs+dx), s01, s23);
|
||||
v_store(&D[dx], v_dotprod(v_reinterpret_as_s16(v_expand_low(s01)), a0));
|
||||
v_store(&D[dx+4], v_dotprod(v_reinterpret_as_s16(v_expand_high(s01)), a1));
|
||||
v_store(&D[dx+8], v_dotprod(v_reinterpret_as_s16(v_expand_low(s23)), a2));
|
||||
v_store(&D[dx+12], v_dotprod(v_reinterpret_as_s16(v_expand_high(s23)), a3));
|
||||
}
|
||||
}
|
||||
}
|
||||
return dx;
|
||||
}
|
||||
};
|
||||
|
||||
typedef HResizeLinearVec_X4<float,float,float,v_float32x4> HResizeLinearVec_32f;
|
||||
typedef HResizeLinearVec_X4<ushort,float,float,v_float32x4> HResizeLinearVec_16u32f;
|
||||
typedef HResizeLinearVec_X4<short,float,float,v_float32x4> HResizeLinearVec_16s32f;
|
||||
typedef HResizeLinearVecU8_X4 HResizeLinearVec_8u32s;
|
||||
|
||||
#else
|
||||
|
||||
typedef HResizeNoVec HResizeLinearVec_8u32s;
|
||||
typedef HResizeNoVec HResizeLinearVec_16u32f;
|
||||
typedef HResizeNoVec HResizeLinearVec_16s32f;
|
||||
typedef HResizeNoVec HResizeLinearVec_32f;
|
||||
|
||||
#endif
|
||||
|
||||
typedef HResizeNoVec HResizeLinearVec_64f;
|
||||
|
||||
|
||||
@ -1505,7 +1825,7 @@ struct HResizeLinear
|
||||
int dx0 = vecOp((const uchar**)src, (uchar**)dst, count,
|
||||
xofs, (const uchar*)alpha, swidth, dwidth, cn, xmin, xmax );
|
||||
|
||||
for( k = 0; k <= count - 2; k++ )
|
||||
for( k = 0; k <= count - 2; k+=2 )
|
||||
{
|
||||
const T *S0 = src[k], *S1 = src[k+1];
|
||||
WT *D0 = dst[k], *D1 = dst[k+1];
|
||||
@ -1529,7 +1849,7 @@ struct HResizeLinear
|
||||
{
|
||||
const T *S = src[k];
|
||||
WT *D = dst[k];
|
||||
for( dx = 0; dx < xmax; dx++ )
|
||||
for( dx = dx0; dx < xmax; dx++ )
|
||||
{
|
||||
int sx = xofs[dx];
|
||||
D[dx] = S[sx]*alpha[dx*2] + S[sx+cn]*alpha[dx*2+1];
|
||||
|
@ -757,6 +757,7 @@ thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type )
|
||||
}
|
||||
setIppErrorStatus();
|
||||
break;
|
||||
#if 0 // details: https://github.com/opencv/opencv/pull/16085
|
||||
case THRESH_TOZERO:
|
||||
if (0 <= CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_32f_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh + FLT_EPSILON, 0))
|
||||
{
|
||||
@ -765,6 +766,7 @@ thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type )
|
||||
}
|
||||
setIppErrorStatus();
|
||||
break;
|
||||
#endif
|
||||
case THRESH_TOZERO_INV:
|
||||
if (0 <= CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_32f_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh, 0))
|
||||
{
|
||||
|
@ -355,4 +355,25 @@ _exit_:
|
||||
|
||||
TEST(Imgproc_ApproxPoly, accuracy) { CV_ApproxPolyTest test; test.safe_run(); }
|
||||
|
||||
//Tests to make sure that unreasonable epsilon (error)
|
||||
//values never get passed to the Douglas-Peucker algorithm.
|
||||
TEST(Imgproc_ApproxPoly, bad_epsilon)
|
||||
{
|
||||
std::vector<Point2f> inputPoints;
|
||||
inputPoints.push_back(Point2f(0.0f, 0.0f));
|
||||
std::vector<Point2f> outputPoints;
|
||||
|
||||
double eps = std::numeric_limits<double>::infinity();
|
||||
ASSERT_ANY_THROW(approxPolyDP(inputPoints, outputPoints, eps, false));
|
||||
|
||||
eps = 9e99;
|
||||
ASSERT_ANY_THROW(approxPolyDP(inputPoints, outputPoints, eps, false));
|
||||
|
||||
eps = -1e-6;
|
||||
ASSERT_ANY_THROW(approxPolyDP(inputPoints, outputPoints, eps, false));
|
||||
|
||||
eps = NAN;
|
||||
ASSERT_ANY_THROW(approxPolyDP(inputPoints, outputPoints, eps, false));
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
@ -1957,5 +1957,42 @@ TEST(Imgproc_Hist_Calc, calcHist_regression_11544)
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Imgproc_Hist_Calc, badarg)
|
||||
{
|
||||
const int channels[] = {0};
|
||||
float range1[] = {0, 10};
|
||||
float range2[] = {10, 20};
|
||||
const float * ranges[] = {range1, range2};
|
||||
Mat img = cv::Mat::zeros(10, 10, CV_8UC1);
|
||||
Mat imgInt = cv::Mat::zeros(10, 10, CV_32SC1);
|
||||
Mat hist;
|
||||
const int hist_size[] = { 100 };
|
||||
// base run
|
||||
EXPECT_NO_THROW(cv::calcHist(&img, 1, channels, noArray(), hist, 1, hist_size, ranges, true));
|
||||
// bad parameters
|
||||
EXPECT_THROW(cv::calcHist(NULL, 1, channels, noArray(), hist, 1, hist_size, ranges, true), cv::Exception);
|
||||
EXPECT_THROW(cv::calcHist(&img, 0, channels, noArray(), hist, 1, hist_size, ranges, true), cv::Exception);
|
||||
EXPECT_THROW(cv::calcHist(&img, 1, NULL, noArray(), hist, 2, hist_size, ranges, true), cv::Exception);
|
||||
EXPECT_THROW(cv::calcHist(&img, 1, channels, noArray(), noArray(), 1, hist_size, ranges, true), cv::Exception);
|
||||
EXPECT_THROW(cv::calcHist(&img, 1, channels, noArray(), hist, -1, hist_size, ranges, true), cv::Exception);
|
||||
EXPECT_THROW(cv::calcHist(&img, 1, channels, noArray(), hist, 1, NULL, ranges, true), cv::Exception);
|
||||
EXPECT_THROW(cv::calcHist(&imgInt, 1, channels, noArray(), hist, 1, hist_size, NULL, true), cv::Exception);
|
||||
// special case
|
||||
EXPECT_NO_THROW(cv::calcHist(&img, 1, channels, noArray(), hist, 1, hist_size, NULL, true));
|
||||
|
||||
Mat backProj;
|
||||
// base run
|
||||
EXPECT_NO_THROW(cv::calcBackProject(&img, 1, channels, hist, backProj, ranges, 1, true));
|
||||
// bad parameters
|
||||
EXPECT_THROW(cv::calcBackProject(NULL, 1, channels, hist, backProj, ranges, 1, true), cv::Exception);
|
||||
EXPECT_THROW(cv::calcBackProject(&img, 0, channels, hist, backProj, ranges, 1, true), cv::Exception);
|
||||
EXPECT_THROW(cv::calcBackProject(&img, 1, channels, noArray(), backProj, ranges, 1, true), cv::Exception);
|
||||
EXPECT_THROW(cv::calcBackProject(&img, 1, channels, hist, noArray(), ranges, 1, true), cv::Exception);
|
||||
EXPECT_THROW(cv::calcBackProject(&imgInt, 1, channels, hist, backProj, NULL, 1, true), cv::Exception);
|
||||
// special case
|
||||
EXPECT_NO_THROW(cv::calcBackProject(&img, 1, channels, hist, backProj, NULL, 1, true));
|
||||
}
|
||||
|
||||
|
||||
}} // namespace
|
||||
/* End Of File */
|
||||
|
@ -434,4 +434,13 @@ BIGDATA_TEST(Imgproc_Threshold, huge)
|
||||
ASSERT_EQ((uint64)nz, n / 2);
|
||||
}
|
||||
|
||||
TEST(Imgproc_Threshold, regression_THRESH_TOZERO_IPP_16085)
|
||||
{
|
||||
Size sz(16, 16);
|
||||
Mat input(sz, CV_32F, Scalar::all(2));
|
||||
Mat result;
|
||||
cv::threshold(input, result, 2.0, 0.0, THRESH_TOZERO);
|
||||
EXPECT_EQ(0, cv::norm(result, NORM_INF));
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
@ -68,6 +68,13 @@ def bootstrap():
|
||||
sys.path.insert(1, p)
|
||||
|
||||
if os.name == 'nt':
|
||||
if sys.version_info[:2] >= (3, 8): # https://github.com/python/cpython/pull/12302
|
||||
for p in l_vars['BINARIES_PATHS']:
|
||||
try:
|
||||
os.add_dll_directory(p)
|
||||
except Exception as e:
|
||||
if DEBUG: print('Failed os.add_dll_directory(): '+ str(e))
|
||||
pass
|
||||
os.environ['PATH'] = ';'.join(l_vars['BINARIES_PATHS']) + ';' + os.environ.get('PATH', '')
|
||||
if DEBUG: print('OpenCV loader: PATH={}'.format(str(os.environ['PATH'])))
|
||||
else:
|
||||
|
@ -44,6 +44,7 @@ def main():
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: C++',
|
||||
'Programming Language :: Python :: Implementation :: CPython',
|
||||
'Topic :: Scientific/Engineering',
|
||||
|
@ -1383,7 +1383,8 @@ double norm(InputArray _src1, InputArray _src2, int normType, InputArray _mask)
|
||||
int normType0 = normType;
|
||||
normType = normType == NORM_L2SQR ? NORM_L2 : normType;
|
||||
|
||||
CV_Assert( src1.type() == src2.type() && src1.size == src2.size );
|
||||
CV_CheckTypeEQ(src1.type(), src2.type(), "");
|
||||
CV_Assert(src1.size == src2.size);
|
||||
CV_Assert( mask.empty() || (src1.size == mask.size && mask.type() == CV_8U) );
|
||||
CV_Assert( normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2 );
|
||||
const Mat *arrays[]={&src1, &src2, &mask, 0};
|
||||
|
@ -15,6 +15,8 @@ IF %ERRORLEVEL% EQU 0 (
|
||||
GOTO :PYTHON_FOUND
|
||||
)
|
||||
|
||||
CALL :QUERY_PYTHON 3.8
|
||||
IF %ERRORLEVEL% EQU 0 GOTO :PYTHON_FOUND
|
||||
CALL :QUERY_PYTHON 3.7
|
||||
IF %ERRORLEVEL% EQU 0 GOTO :PYTHON_FOUND
|
||||
CALL :QUERY_PYTHON 3.6
|
||||
|
Loading…
Reference in New Issue
Block a user