Merge remote-tracking branch 'upstream/3.4' into merge-3.4

This commit is contained in:
Alexander Alekhin 2019-12-12 13:02:19 +03:00
commit 92b9888837
34 changed files with 1109 additions and 202 deletions

View File

@ -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,

View File

@ -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()

View File

@ -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

View File

@ -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) \

View File

@ -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;
}

View File

@ -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
}
};

View File

@ -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)
)

View File

@ -508,6 +508,13 @@ CV__DNN_INLINE_NS_BEGIN
static Ptr<Layer> create(const LayerParams &params);
};
/** @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:

View File

@ -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()

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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)
{

View File

@ -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

View File

@ -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)

View File

@ -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);
}
}
};

View File

@ -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()

View File

@ -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,

View File

@ -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;

View File

@ -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));

View File

@ -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:

View File

@ -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;

View File

@ -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];

View File

@ -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))
{

View File

@ -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

View File

@ -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 */

View 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

View File

@ -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:

View File

@ -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',

View File

@ -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};

View File

@ -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