From b08d67c4e15ff44d1d875aab99da272ff1ce2a30 Mon Sep 17 00:00:00 2001 From: Liangda-w <66914151+Liangda-w@users.noreply.github.com> Date: Mon, 1 Feb 2021 10:17:54 +0100 Subject: [PATCH 1/7] Merge pull request #19419 from Liangda-w:patch-1 * Fix error in documentation for RGB->HSV convertion * Update colors.markdown --- modules/imgproc/doc/colors.markdown | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/imgproc/doc/colors.markdown b/modules/imgproc/doc/colors.markdown index f1023621ad..47d97a7263 100644 --- a/modules/imgproc/doc/colors.markdown +++ b/modules/imgproc/doc/colors.markdown @@ -56,7 +56,10 @@ scaled to fit the 0 to 1 range. \f[V \leftarrow max(R,G,B)\f] \f[S \leftarrow \fork{\frac{V-min(R,G,B)}{V}}{if \(V \neq 0\)}{0}{otherwise}\f] -\f[H \leftarrow \forkthree{{60(G - B)}/{(V-min(R,G,B))}}{if \(V=R\)}{{120+60(B - R)}/{(V-min(R,G,B))}}{if \(V=G\)}{{240+60(R - G)}/{(V-min(R,G,B))}}{if \(V=B\)}\f] +\f[H \leftarrow \forkfour{{60(G - B)}/{(V-min(R,G,B))}}{if \(V=R\)} + {{120+60(B - R)}/{(V-min(R,G,B))}}{if \(V=G\)} + {{240+60(R - G)}/{(V-min(R,G,B))}}{if \(V=B\)} + {0}{if \(R=G=B\)}\f] If \f$H<0\f$ then \f$H \leftarrow H+360\f$ . On output \f$0 \leq V \leq 1\f$, \f$0 \leq S \leq 1\f$, \f$0 \leq H \leq 360\f$ . @@ -78,9 +81,10 @@ scaled to fit the 0 to 1 range. \f[L \leftarrow \frac{V_{max} + V_{min}}{2}\f] \f[S \leftarrow \fork { \frac{V_{max} - V_{min}}{V_{max} + V_{min}} }{if \(L < 0.5\) } { \frac{V_{max} - V_{min}}{2 - (V_{max} + V_{min})} }{if \(L \ge 0.5\) }\f] -\f[H \leftarrow \forkthree {{60(G - B)}/{(V_{max}-V_{min})}}{if \(V_{max}=R\) } +\f[H \leftarrow \forkfour {{60(G - B)}/{(V_{max}-V_{min})}}{if \(V_{max}=R\) } {{120+60(B - R)}/{(V_{max}-V_{min})}}{if \(V_{max}=G\) } - {{240+60(R - G)}/{(V_{max}-V_{min})}}{if \(V_{max}=B\) }\f] + {{240+60(R - G)}/{(V_{max}-V_{min})}}{if \(V_{max}=B\) } + {0}{if \(R=G=B\) }\f] If \f$H<0\f$ then \f$H \leftarrow H+360\f$ . On output \f$0 \leq L \leq 1\f$, \f$0 \leq S \leq 1\f$, \f$0 \leq H \leq 360\f$ . From 68eb54dc13e88f86e72157be98efe208024f960c Mon Sep 17 00:00:00 2001 From: Liubov Batanina Date: Mon, 1 Feb 2021 12:38:33 +0300 Subject: [PATCH 2/7] Added ONNX NormalizeL2 subgraph --- .../dnn/src/onnx/onnx_graph_simplifier.cpp | 36 +++++++++++++++++++ modules/dnn/test/test_onnx_importer.cpp | 5 +++ 2 files changed, 41 insertions(+) diff --git a/modules/dnn/src/onnx/onnx_graph_simplifier.cpp b/modules/dnn/src/onnx/onnx_graph_simplifier.cpp index a1b60c52e8..b81ccf106c 100644 --- a/modules/dnn/src/onnx/onnx_graph_simplifier.cpp +++ b/modules/dnn/src/onnx/onnx_graph_simplifier.cpp @@ -249,6 +249,40 @@ public: } }; +class NormalizeSubgraph4 : public NormalizeSubgraphBase +{ +public: + NormalizeSubgraph4() : NormalizeSubgraphBase(1) + { + int input = addNodeToMatch(""); + int mul = addNodeToMatch("Mul", input, input); + int sum = addNodeToMatch("ReduceSum", mul); + int eps = addNodeToMatch(""); + int max = addNodeToMatch("Max", sum, eps); + int sqrt = addNodeToMatch("Sqrt", max); + int reciprocal = addNodeToMatch("Reciprocal", sqrt); + addNodeToMatch("Mul", input, reciprocal); + setFusedNode("Normalize", input); + } +}; + +class NormalizeSubgraph5 : public NormalizeSubgraphBase +{ +public: + NormalizeSubgraph5() : NormalizeSubgraphBase(1) + { + int input = addNodeToMatch(""); + int mul = addNodeToMatch("Mul", input, input); + int sum = addNodeToMatch("ReduceSum", mul); + int clip = addNodeToMatch("Clip", sum); + int sqrt = addNodeToMatch("Sqrt", clip); + int one = addNodeToMatch("Constant"); + int div = addNodeToMatch("Div", one, sqrt); + addNodeToMatch("Mul", input, div); + setFusedNode("Normalize", input); + } +}; + class GatherCastSubgraph : public Subgraph { public: @@ -526,6 +560,8 @@ void simplifySubgraphs(opencv_onnx::GraphProto& net) subgraphs.push_back(makePtr()); subgraphs.push_back(makePtr()); subgraphs.push_back(makePtr()); + subgraphs.push_back(makePtr()); + subgraphs.push_back(makePtr()); simplifySubgraphs(Ptr(new ONNXGraphWrapper(net)), subgraphs); } diff --git a/modules/dnn/test/test_onnx_importer.cpp b/modules/dnn/test/test_onnx_importer.cpp index 40d9803b5c..488f809b75 100644 --- a/modules/dnn/test/test_onnx_importer.cpp +++ b/modules/dnn/test/test_onnx_importer.cpp @@ -403,6 +403,11 @@ TEST_P(Test_ONNX_layers, BatchNormalizationSubgraph) testONNXModels("batch_norm_subgraph"); } +TEST_P(Test_ONNX_layers, NormalizeFusionSubgraph) +{ + testONNXModels("normalize_fusion"); +} + TEST_P(Test_ONNX_layers, Transpose) { if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019) From 0016c25b586ada88a810c44d04749fadb2a5dffc Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Tue, 2 Feb 2021 13:24:59 +0300 Subject: [PATCH 3/7] Guard non-free usage in stitching as contrib can be built without it. --- modules/stitching/test/test_matchers.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/stitching/test/test_matchers.cpp b/modules/stitching/test/test_matchers.cpp index a264c10915..730f541cca 100644 --- a/modules/stitching/test/test_matchers.cpp +++ b/modules/stitching/test/test_matchers.cpp @@ -44,7 +44,7 @@ namespace opencv_test { namespace { -#ifdef HAVE_OPENCV_XFEATURES2D +#if defined(HAVE_OPENCV_XFEATURES2D) && defined(OPENCV_ENABLE_NONFREE) TEST(SurfFeaturesFinder, CanFindInROIs) { @@ -74,7 +74,7 @@ TEST(SurfFeaturesFinder, CanFindInROIs) ASSERT_EQ(bad_count, 0); } -#endif // HAVE_OPENCV_XFEATURES2D +#endif // HAVE_OPENCV_XFEATURES2D && OPENCV_ENABLE_NONFREE TEST(ParallelFeaturesFinder, IsSameWithSerial) { From 6c1a433c4c6933ec1be1643df67197b00e225d97 Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Tue, 2 Feb 2021 02:49:19 +0100 Subject: [PATCH 4/7] python: also catch general c++ exceptions they might be thrown from third-party code (notably Ogre in the ovis module). While Linux is kind enough to print them, they cause instant termination on Windows. Arguably, they do not origin from OpenCV itself, but still this helps understanding what went wrong when calling an OpenCV function. --- modules/core/include/opencv2/core/bindings_utils.hpp | 8 ++++++++ modules/python/src2/cv2.cpp | 5 +++++ modules/python/test/test_misc.py | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/modules/core/include/opencv2/core/bindings_utils.hpp b/modules/core/include/opencv2/core/bindings_utils.hpp index bbcc3a88d0..179d60323f 100644 --- a/modules/core/include/opencv2/core/bindings_utils.hpp +++ b/modules/core/include/opencv2/core/bindings_utils.hpp @@ -8,6 +8,8 @@ #include #include +#include + namespace cv { namespace utils { //! @addtogroup core_utils //! @{ @@ -113,6 +115,12 @@ String dumpRange(const Range& argument) } } +CV_WRAP static inline +void testRaiseGeneralException() +{ + throw std::runtime_error("exception text"); +} + CV_WRAP static inline AsyncArray testAsyncArray(InputArray argument) { diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp index 8272513e64..8bb15cd43f 100644 --- a/modules/python/src2/cv2.cpp +++ b/modules/python/src2/cv2.cpp @@ -206,6 +206,11 @@ catch (const cv::Exception &e) \ { \ pyRaiseCVException(e); \ return 0; \ +} \ +catch (const std::exception &e) \ +{ \ + PyErr_SetString(opencv_error, e.what()); \ + return 0; \ } using namespace cv; diff --git a/modules/python/test/test_misc.py b/modules/python/test/test_misc.py index 5e23045e05..121e86a64c 100644 --- a/modules/python/test/test_misc.py +++ b/modules/python/test/test_misc.py @@ -47,6 +47,12 @@ class Bindings(NewOpenCVTests): boost.getMaxDepth() # from ml::DTrees boost.isClassifier() # from ml::StatModel + def test_raiseGeneralException(self): + with self.assertRaises((cv.error,), + msg='C++ exception is not propagated to Python in the right way') as cm: + cv.utils.testRaiseGeneralException() + self.assertEqual(str(cm.exception), 'exception text') + def test_redirectError(self): try: cv.imshow("", None) # This causes an assert From 83aa711346be7719934439769a9b0a818780bc3e Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Sat, 30 Jan 2021 12:02:47 +0000 Subject: [PATCH 5/7] dnn: rename clamp() => normalize_axis() --- .../dnn/include/opencv2/dnn/shape_utils.hpp | 26 ++++++++++++++----- modules/dnn/src/dnn.cpp | 2 +- modules/dnn/src/layers/concat_layer.cpp | 10 +++---- modules/dnn/src/layers/flatten_layer.cpp | 12 ++++----- .../dnn/src/layers/fully_connected_layer.cpp | 6 ++--- .../dnn/src/layers/normalize_bbox_layer.cpp | 8 +++--- modules/dnn/src/layers/reshape_layer.cpp | 9 +------ modules/dnn/src/layers/scale_layer.cpp | 2 +- modules/dnn/src/layers/slice_layer.cpp | 8 +++--- modules/dnn/src/layers/softmax_layer.cpp | 10 +++---- modules/dnn/src/onnx/onnx_importer.cpp | 16 ++++++------ 11 files changed, 57 insertions(+), 52 deletions(-) diff --git a/modules/dnn/include/opencv2/dnn/shape_utils.hpp b/modules/dnn/include/opencv2/dnn/shape_utils.hpp index c975fcff04..609809e110 100644 --- a/modules/dnn/include/opencv2/dnn/shape_utils.hpp +++ b/modules/dnn/include/opencv2/dnn/shape_utils.hpp @@ -205,21 +205,33 @@ static inline std::ostream& operator<<(std::ostream &out, const MatShape& shape) return out; } -inline int clamp(int ax, int dims) +/// @brief Converts axis from `[-dims; dims)` (similar to Python's slice notation) to `[0; dims)` range. +static inline +int normalize_axis(int axis, int dims) { - return ax < 0 ? ax + dims : ax; + CV_Check(axis, axis >= -dims && axis < dims, ""); + axis = (axis < 0) ? (dims + axis) : axis; + CV_DbgCheck(axis, axis >= 0 && axis < dims, ""); + return axis; } -inline int clamp(int ax, const MatShape& shape) +static inline +int normalize_axis(int axis, const MatShape& shape) { - return clamp(ax, (int)shape.size()); + return normalize_axis(axis, (int)shape.size()); } -inline Range clamp(const Range& r, int axisSize) +static inline +Range normalize_axis_range(const Range& r, int axisSize) { - Range clamped(std::max(r.start, 0), + if (r == Range::all()) + return Range(0, axisSize); + CV_CheckGE(r.start, 0, ""); + Range clamped(r.start, r.end > 0 ? std::min(r.end, axisSize) : axisSize + r.end + 1); - CV_Assert_N(clamped.start < clamped.end, clamped.end <= axisSize); + CV_DbgCheckGE(clamped.start, 0, ""); + CV_CheckLT(clamped.start, clamped.end, ""); + CV_CheckLE(clamped.end, axisSize, ""); return clamped; } diff --git a/modules/dnn/src/dnn.cpp b/modules/dnn/src/dnn.cpp index efafd5d325..34222b9547 100644 --- a/modules/dnn/src/dnn.cpp +++ b/modules/dnn/src/dnn.cpp @@ -2598,7 +2598,7 @@ struct Net::Impl : public detail::NetImplBase // the concatenation optimization is applied with batch_size > 1. // so, for now, we only apply this optimization in the most popular // case batch_size == 1. - int axis = clamp(concatLayer->axis, output.dims); + int axis = normalize_axis(concatLayer->axis, output.dims); if( output.total(0, axis) == 1 ) { size_t i, ninputs = ld.inputBlobsId.size(); diff --git a/modules/dnn/src/layers/concat_layer.cpp b/modules/dnn/src/layers/concat_layer.cpp index d85d9e4b01..2f92c69e05 100644 --- a/modules/dnn/src/layers/concat_layer.cpp +++ b/modules/dnn/src/layers/concat_layer.cpp @@ -72,7 +72,7 @@ public: { CV_Assert(inputs.size() > 0); outputs.resize(1, inputs[0]); - int cAxis = clamp(axis, inputs[0]); + int cAxis = normalize_axis(axis, inputs[0]); int axisSum = 0; for (size_t i = 0; i < inputs.size(); i++) @@ -192,7 +192,7 @@ public: inps.getUMatVector(inputs); outs.getUMatVector(outputs); - int cAxis = clamp(axis, inputs[0].dims); + int cAxis = normalize_axis(axis, inputs[0].dims); if (padding) return false; @@ -246,7 +246,7 @@ public: inputs_arr.getMatVector(inputs); outputs_arr.getMatVector(outputs); - int cAxis = clamp(axis, inputs[0].dims); + int cAxis = normalize_axis(axis, inputs[0].dims); Mat& outMat = outputs[0]; if (padding) @@ -306,7 +306,7 @@ public: InferenceEngine::DataPtr input = infEngineDataNode(inputs[0]); InferenceEngine::Builder::ConcatLayer ieLayer(name); - ieLayer.setAxis(clamp(axis, input->getDims().size())); + ieLayer.setAxis(normalize_axis(axis, input->getDims().size())); ieLayer.setInputPorts(std::vector(inputs.size())); return Ptr(new InfEngineBackendNode(ieLayer)); } @@ -319,7 +319,7 @@ public: { InferenceEngine::DataPtr data = ngraphDataNode(inputs[0]); const int numDims = data->getDims().size(); - const int cAxis = clamp(axis, numDims); + const int cAxis = normalize_axis(axis, numDims); std::vector maxDims(numDims, 0); CV_Assert(inputs.size() == nodes.size()); diff --git a/modules/dnn/src/layers/flatten_layer.cpp b/modules/dnn/src/layers/flatten_layer.cpp index f3434a5751..c59b71248e 100644 --- a/modules/dnn/src/layers/flatten_layer.cpp +++ b/modules/dnn/src/layers/flatten_layer.cpp @@ -82,8 +82,8 @@ public: } int numAxes = inputs[0].size(); - int startAxis = clamp(_startAxis, numAxes); - int endAxis = clamp(_endAxis, numAxes); + int startAxis = normalize_axis(_startAxis, numAxes); + int endAxis = normalize_axis(_endAxis, numAxes); CV_Assert(startAxis >= 0); CV_Assert(endAxis >= startAxis && endAxis < (int)numAxes); @@ -113,8 +113,8 @@ public: inputs_arr.getMatVector(inputs); int numAxes = inputs[0].dims; - _startAxis = clamp(_startAxis, numAxes); - _endAxis = clamp(_endAxis, numAxes); + _startAxis = normalize_axis(_startAxis, numAxes); + _endAxis = normalize_axis(_endAxis, numAxes); } #ifdef HAVE_OPENCL @@ -186,8 +186,8 @@ virtual Ptr initNgraph(const std::vector >& inp std::vector dims = ieInpNode->get_shape(); int numAxes = dims.size(); - int startAxis = clamp(_startAxis, numAxes); - int endAxis = clamp(_endAxis, numAxes); + int startAxis = normalize_axis(_startAxis, numAxes); + int endAxis = normalize_axis(_endAxis, numAxes); CV_Assert(startAxis >= 0); CV_Assert(endAxis >= startAxis && endAxis < numAxes); diff --git a/modules/dnn/src/layers/fully_connected_layer.cpp b/modules/dnn/src/layers/fully_connected_layer.cpp index d9c6f6edb1..e25ca5a68f 100644 --- a/modules/dnn/src/layers/fully_connected_layer.cpp +++ b/modules/dnn/src/layers/fully_connected_layer.cpp @@ -129,7 +129,7 @@ public: CV_CheckEQ(blobs[0].dims, 2, ""); numOutput = blobs[0].size[0]; CV_Assert(!bias || (size_t)numOutput == blobs[1].total()); - cAxis = clamp(axis, inputs[0]); + cAxis = normalize_axis(axis, inputs[0]); } MatShape outShape(cAxis + 1); @@ -352,7 +352,7 @@ public: return true; } - int axisCan = clamp(axis, inputs[0].dims); + int axisCan = normalize_axis(axis, inputs[0].dims); int numOutput = blobs[0].size[0]; int innerSize = blobs[0].size[1]; int outerSize = total(shape(inputs[0]), 0, axisCan); @@ -473,7 +473,7 @@ public: if (!blobs.empty()) { - int axisCan = clamp(axis, input[0].dims); + int axisCan = normalize_axis(axis, input[0].dims); int outerSize = input[0].total(0, axisCan); for (size_t i = 0; i < input.size(); i++) diff --git a/modules/dnn/src/layers/normalize_bbox_layer.cpp b/modules/dnn/src/layers/normalize_bbox_layer.cpp index 7ce7b37d1e..5def78f221 100644 --- a/modules/dnn/src/layers/normalize_bbox_layer.cpp +++ b/modules/dnn/src/layers/normalize_bbox_layer.cpp @@ -118,8 +118,8 @@ public: const UMat& inp0 = inputs[0]; UMat& buffer = internals[0]; - startAxis = clamp(startAxis, inp0.dims); - endAxis = clamp(endAxis, inp0.dims); + startAxis = normalize_axis(startAxis, inp0.dims); + endAxis = normalize_axis(endAxis, inp0.dims); size_t num = total(shape(inp0.size), 0, startAxis); size_t numPlanes = total(shape(inp0.size), startAxis, endAxis + 1); @@ -203,8 +203,8 @@ public: const Mat& inp0 = inputs[0]; Mat& buffer = internals[0]; - startAxis = clamp(startAxis, inp0.dims); - endAxis = clamp(endAxis, inp0.dims); + startAxis = normalize_axis(startAxis, inp0.dims); + endAxis = normalize_axis(endAxis, inp0.dims); const float* inpData = inp0.ptr(); float* outData = outputs[0].ptr(); diff --git a/modules/dnn/src/layers/reshape_layer.cpp b/modules/dnn/src/layers/reshape_layer.cpp index 642e7c52f6..2b7cb40eb5 100644 --- a/modules/dnn/src/layers/reshape_layer.cpp +++ b/modules/dnn/src/layers/reshape_layer.cpp @@ -60,14 +60,7 @@ static void computeShapeByReshapeMask(const MatShape &srcShape, int srcShapeSize = (int)srcShape.size(); int maskShapeSize = (int)maskShape.size(); - if (srcRange == Range::all()) - srcRange = Range(0, srcShapeSize); - else - { - int sz = srcRange.size(); - srcRange.start = clamp(srcRange.start, srcShapeSize); - srcRange.end = srcRange.end == INT_MAX ? srcShapeSize : srcRange.start + sz; - } + srcRange = normalize_axis_range(srcRange, srcShapeSize); bool explicitMask = !maskShape.empty(); // All mask values are positive. for (int i = 0, n = maskShape.size(); i < n && explicitMask; ++i) diff --git a/modules/dnn/src/layers/scale_layer.cpp b/modules/dnn/src/layers/scale_layer.cpp index 9452e4e85e..058140235b 100644 --- a/modules/dnn/src/layers/scale_layer.cpp +++ b/modules/dnn/src/layers/scale_layer.cpp @@ -240,7 +240,7 @@ public: numChannels = blobs[0].total(); std::vector shape(ieInpNode0->get_shape().size(), 1); - int cAxis = clamp(axis, shape.size()); + int cAxis = normalize_axis(axis, shape.size()); shape[cAxis] = numChannels; auto node = ieInpNode0; diff --git a/modules/dnn/src/layers/slice_layer.cpp b/modules/dnn/src/layers/slice_layer.cpp index fd314b7c57..52236015d2 100644 --- a/modules/dnn/src/layers/slice_layer.cpp +++ b/modules/dnn/src/layers/slice_layer.cpp @@ -146,7 +146,7 @@ public: for (int j = 0; j < sliceRanges[i].size(); ++j) { if (shapesInitialized || inpShape[j] > 0) - outputs[i][j] = clamp(sliceRanges[i][j], inpShape[j]).size(); + outputs[i][j] = normalize_axis_range(sliceRanges[i][j], inpShape[j]).size(); } } } @@ -209,7 +209,7 @@ public: // Clamp. for (int j = 0; j < finalSliceRanges[i].size(); ++j) { - finalSliceRanges[i][j] = clamp(finalSliceRanges[i][j], inpShape[j]); + finalSliceRanges[i][j] = normalize_axis_range(finalSliceRanges[i][j], inpShape[j]); } } @@ -601,7 +601,7 @@ public: CV_Assert(inputs.size() == 2); MatShape dstShape = inputs[0]; - int start = clamp(axis, dstShape); + int start = normalize_axis(axis, dstShape); for (int i = start; i < dstShape.size(); i++) { dstShape[i] = inputs[1][i]; @@ -620,7 +620,7 @@ public: const Mat &inpSzBlob = inputs[1]; int dims = inpBlob.dims; - int start_axis = clamp(axis, dims); + int start_axis = normalize_axis(axis, dims); std::vector offset_final(dims, 0); if (offset.size() == 1) diff --git a/modules/dnn/src/layers/softmax_layer.cpp b/modules/dnn/src/layers/softmax_layer.cpp index a0e2b42020..29acd06402 100644 --- a/modules/dnn/src/layers/softmax_layer.cpp +++ b/modules/dnn/src/layers/softmax_layer.cpp @@ -82,7 +82,7 @@ public: { bool inplace = Layer::getMemoryShapes(inputs, requiredOutputs, outputs, internals); MatShape shape = inputs[0]; - int cAxis = clamp(axisRaw, shape.size()); + int cAxis = normalize_axis(axisRaw, shape.size()); shape[cAxis] = 1; internals.assign(1, shape); return inplace; @@ -115,7 +115,7 @@ public: UMat& src = inputs[0]; UMat& dstMat = outputs[0]; - int axis = clamp(axisRaw, src.dims); + int axis = normalize_axis(axisRaw, src.dims); if (softmaxOp.empty()) { @@ -207,7 +207,7 @@ public: const Mat &src = inputs[0]; Mat &dst = outputs[0]; - int axis = clamp(axisRaw, src.dims); + int axis = normalize_axis(axisRaw, src.dims); size_t outerSize = src.total(0, axis), channels = src.size[axis], innerSize = src.total(axis + 1); @@ -318,7 +318,7 @@ public: InferenceEngine::DataPtr input = infEngineDataNode(inputs[0]); InferenceEngine::Builder::SoftMaxLayer ieLayer(name); - ieLayer.setAxis(clamp(axisRaw, input->getDims().size())); + ieLayer.setAxis(normalize_axis(axisRaw, input->getDims().size())); return Ptr(new InfEngineBackendNode(ieLayer)); } @@ -329,7 +329,7 @@ public: const std::vector >& nodes) CV_OVERRIDE { auto& ieInpNode = nodes[0].dynamicCast()->node; - int axis = clamp(axisRaw, ieInpNode->get_shape().size()); + int axis = normalize_axis(axisRaw, ieInpNode->get_shape().size()); auto softmax = std::make_shared(ieInpNode, axis); if (logSoftMax) return Ptr(new InfEngineNgraphNode(std::make_shared(softmax))); diff --git a/modules/dnn/src/onnx/onnx_importer.cpp b/modules/dnn/src/onnx/onnx_importer.cpp index 76058ccb24..eae7e3ba25 100644 --- a/modules/dnn/src/onnx/onnx_importer.cpp +++ b/modules/dnn/src/onnx/onnx_importer.cpp @@ -503,7 +503,7 @@ void ONNXImporter::handleNode(const opencv_onnx::NodeProto& node_proto_) MatShape targetShape; std::vector shouldDelete(inpShape.size(), false); for (int i = 0; i < axes.size(); i++) { - int axis = clamp(axes.get(i), inpShape.size()); + int axis = normalize_axis(axes.get(i), inpShape.size()); shouldDelete[axis] = true; } for (int axis = 0; axis < inpShape.size(); ++axis){ @@ -515,7 +515,7 @@ void ONNXImporter::handleNode(const opencv_onnx::NodeProto& node_proto_) if (inpShape.size() == 3 && axes.size() <= 2) { - int axis = clamp(axes.get(0), inpShape.size()); + int axis = normalize_axis(axes.get(0), inpShape.size()); CV_CheckNE(axis, 0, ""); LayerParams reshapeLp; @@ -539,8 +539,8 @@ void ONNXImporter::handleNode(const opencv_onnx::NodeProto& node_proto_) avgLp.set("pool", pool); if (axes.size() == 2) { - CV_CheckEQ(clamp(axes.get(0), inpShape.size()), 1, "Unsupported mode"); - CV_CheckEQ(clamp(axes.get(1), inpShape.size()), 2, "Unsupported mode"); + CV_CheckEQ(normalize_axis(axes.get(0), inpShape.size()), 1, "Unsupported mode"); + CV_CheckEQ(normalize_axis(axes.get(1), inpShape.size()), 2, "Unsupported mode"); avgLp.set("global_pooling", true); } else @@ -560,9 +560,9 @@ void ONNXImporter::handleNode(const opencv_onnx::NodeProto& node_proto_) CV_Assert(axes.size() <= inpShape.size() - 2); std::vector kernel_size(inpShape.size() - 2, 1); - if (axes.size() == 1 && (clamp(axes.get(0), inpShape.size()) <= 1)) + if (axes.size() == 1 && (normalize_axis(axes.get(0), inpShape.size()) <= 1)) { - int axis = clamp(axes.get(0), inpShape.size()); + int axis = normalize_axis(axes.get(0), inpShape.size()); MatShape newShape = inpShape; newShape[axis + 1] = total(newShape, axis + 1); newShape.resize(axis + 2); @@ -584,7 +584,7 @@ void ONNXImporter::handleNode(const opencv_onnx::NodeProto& node_proto_) else { for (int i = 0; i < axes.size(); i++) { - int axis = clamp(axes.get(i), inpShape.size()); + int axis = normalize_axis(axes.get(i), inpShape.size()); CV_Assert_N(axis >= 2 + i, axis < inpShape.size()); kernel_size[axis - 2] = inpShape[axis]; } @@ -1343,7 +1343,7 @@ void ONNXImporter::handleNode(const opencv_onnx::NodeProto& node_proto_) if (constBlobs.find(node_proto.input(0)) != constBlobs.end()) { Mat input = getBlob(node_proto, 0); - int axis = clamp(layerParams.get("axis", 1), input.dims); + int axis = normalize_axis(layerParams.get("axis", 1), input.dims); std::vector out_size(&input.size[0], &input.size[0] + axis); out_size.push_back(input.total(axis)); From 09d2ca17cfc39e64c406e26cd247ff8cc786814c Mon Sep 17 00:00:00 2001 From: Jebastin Nadar Date: Thu, 4 Feb 2021 14:20:08 +0530 Subject: [PATCH 6/7] Merge pull request #19449 from SamFC10:tf-leakyrelu * add LeakyRelu to tf-importer * fix whitespace error * added test for leakyrelu --- modules/dnn/src/tensorflow/tf_importer.cpp | 10 ++++++++++ modules/dnn/test/test_tf_importer.cpp | 1 + 2 files changed, 11 insertions(+) diff --git a/modules/dnn/src/tensorflow/tf_importer.cpp b/modules/dnn/src/tensorflow/tf_importer.cpp index 057dc11289..cbe6418b77 100644 --- a/modules/dnn/src/tensorflow/tf_importer.cpp +++ b/modules/dnn/src/tensorflow/tf_importer.cpp @@ -2414,6 +2414,16 @@ void TFImporter::parseNode(const tensorflow::NodeDef& layer_) connect(layer_id, dstNet, parsePin(layer.input(0)), id, 0); } + else if (type == "LeakyRelu") + { + CV_CheckGT(num_inputs, 0, ""); + CV_Assert(hasLayerAttr(layer, "alpha")); + layerParams.set("negative_slope", getLayerAttr(layer, "alpha").f()); + + int id = dstNet.addLayer(name, "ReLU", layerParams); + layer_id[name] = id; + connectToAllBlobs(layer_id, dstNet, parsePin(layer.input(0)), id, num_inputs); + } else if (type == "Abs" || type == "Tanh" || type == "Sigmoid" || type == "Relu" || type == "Elu" || type == "Identity" || type == "Relu6") diff --git a/modules/dnn/test/test_tf_importer.cpp b/modules/dnn/test/test_tf_importer.cpp index f8b09047c8..6163e89fa7 100644 --- a/modules/dnn/test/test_tf_importer.cpp +++ b/modules/dnn/test/test_tf_importer.cpp @@ -463,6 +463,7 @@ TEST_P(Test_TensorFlow_layers, leaky_relu) if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && target == DNN_TARGET_OPENCL) applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_OPENCL, CV_TEST_TAG_DNN_SKIP_IE_NN_BUILDER, CV_TEST_TAG_DNN_SKIP_IE_VERSION); #endif + runTensorFlowNet("leaky_relu"); runTensorFlowNet("leaky_relu_order1"); runTensorFlowNet("leaky_relu_order2"); runTensorFlowNet("leaky_relu_order3"); From 0be18f5cb0aa6e45febde51ea7c8af253d03f144 Mon Sep 17 00:00:00 2001 From: Polina Smolnikova <43805563+rayonnant14@users.noreply.github.com> Date: Sat, 6 Feb 2021 00:24:27 +0300 Subject: [PATCH 7/7] Merge pull request #19407 from rayonnant14:issue_19363 QRCodeDetector::decodeMulti() fixed invalid usage fixedType() * fixed invalid usage fixedType() changed default barcode type to CV_8UC1 added tests added assert in case multi channel straight barcode input * deleted extra wrap into OutputArray * fix warnings * objdetect(qr): remove unnecessary checks Co-authored-by: Alexander Alekhin --- modules/objdetect/src/qrcode.cpp | 37 ++++++++++++++------------ modules/objdetect/test/test_qrcode.cpp | 37 ++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/modules/objdetect/src/qrcode.cpp b/modules/objdetect/src/qrcode.cpp index 449e6e6d32..063c7a9a6d 100644 --- a/modules/objdetect/src/qrcode.cpp +++ b/modules/objdetect/src/qrcode.cpp @@ -2491,12 +2491,13 @@ cv::String QRCodeDetector::decode(InputArray in, InputArray points, bool ok = qrdec.straightDecodingProcess(); std::string decoded_info = qrdec.getDecodeInformation(); - - if (ok && straight_qrcode.needed()) + if (!ok && straight_qrcode.needed()) { - qrdec.getStraightBarcode().convertTo(straight_qrcode, - straight_qrcode.fixedType() ? - straight_qrcode.type() : CV_32FC2); + straight_qrcode.release(); + } + else if (straight_qrcode.needed()) + { + qrdec.getStraightBarcode().convertTo(straight_qrcode, CV_8UC1); } return ok ? decoded_info : std::string(); @@ -2520,11 +2521,13 @@ cv::String QRCodeDetector::decodeCurved(InputArray in, InputArray points, std::string decoded_info = qrdec.getDecodeInformation(); - if (ok && straight_qrcode.needed()) + if (!ok && straight_qrcode.needed()) { - qrdec.getStraightBarcode().convertTo(straight_qrcode, - straight_qrcode.fixedType() ? - straight_qrcode.type() : CV_32FC2); + straight_qrcode.release(); + } + else if (straight_qrcode.needed()) + { + qrdec.getStraightBarcode().convertTo(straight_qrcode, CV_8UC1); } return ok ? decoded_info : std::string(); @@ -3615,18 +3618,18 @@ bool QRCodeDetector::decodeMulti( for_copy.push_back(straight_barcode[i]); } straight_barcode = for_copy; - vector tmp_straight_qrcodes; - if (straight_qrcode.needed()) + if (straight_qrcode.needed() && straight_barcode.size() == 0) { + straight_qrcode.release(); + } + else if (straight_qrcode.needed()) + { + straight_qrcode.create(Size((int)straight_barcode.size(), 1), CV_8UC1); + vector tmp_straight_qrcodes(straight_barcode.size()); for (size_t i = 0; i < straight_barcode.size(); i++) { - Mat tmp_straight_qrcode; - tmp_straight_qrcodes.push_back(tmp_straight_qrcode); - straight_barcode[i].convertTo(((OutputArray)tmp_straight_qrcodes[i]), - ((OutputArray)tmp_straight_qrcodes[i]).fixedType() ? - ((OutputArray)tmp_straight_qrcodes[i]).type() : CV_32FC2); + straight_barcode[i].convertTo(tmp_straight_qrcodes[i], CV_8UC1); } - straight_qrcode.createSameSize(tmp_straight_qrcodes, CV_32FC2); straight_qrcode.assign(tmp_straight_qrcodes); } decoded_info.clear(); diff --git a/modules/objdetect/test/test_qrcode.cpp b/modules/objdetect/test/test_qrcode.cpp index c26cd8a4f2..fc55498740 100644 --- a/modules/objdetect/test/test_qrcode.cpp +++ b/modules/objdetect/test/test_qrcode.cpp @@ -252,6 +252,8 @@ TEST_P(Objdetect_QRCode, regression) decoded_info = qrcode.detectAndDecode(src, corners, straight_barcode); ASSERT_FALSE(corners.empty()); ASSERT_FALSE(decoded_info.empty()); + int expected_barcode_type = CV_8UC1; + EXPECT_EQ(expected_barcode_type, straight_barcode.type()); #else ASSERT_TRUE(qrcode.detect(src, corners)); #endif @@ -317,6 +319,8 @@ TEST_P(Objdetect_QRCode_Close, regression) decoded_info = qrcode.detectAndDecode(barcode, corners, straight_barcode); ASSERT_FALSE(corners.empty()); ASSERT_FALSE(decoded_info.empty()); + int expected_barcode_type = CV_8UC1; + EXPECT_EQ(expected_barcode_type, straight_barcode.type()); #else ASSERT_TRUE(qrcode.detect(barcode, corners)); #endif @@ -382,6 +386,8 @@ TEST_P(Objdetect_QRCode_Monitor, regression) decoded_info = qrcode.detectAndDecode(barcode, corners, straight_barcode); ASSERT_FALSE(corners.empty()); ASSERT_FALSE(decoded_info.empty()); + int expected_barcode_type = CV_8UC1; + EXPECT_EQ(expected_barcode_type, straight_barcode.type()); #else ASSERT_TRUE(qrcode.detect(barcode, corners)); #endif @@ -442,6 +448,8 @@ TEST_P(Objdetect_QRCode_Curved, regression) decoded_info = qrcode.detectAndDecodeCurved(src, corners, straight_barcode); ASSERT_FALSE(corners.empty()); ASSERT_FALSE(decoded_info.empty()); + int expected_barcode_type = CV_8UC1; + EXPECT_EQ(expected_barcode_type, straight_barcode.type()); #else ASSERT_TRUE(qrcode.detect(src, corners)); #endif @@ -502,6 +510,9 @@ TEST_P(Objdetect_QRCode_Multi, regression) EXPECT_TRUE(qrcode.detectAndDecodeMulti(src, decoded_info, corners, straight_barcode)); ASSERT_FALSE(corners.empty()); ASSERT_FALSE(decoded_info.empty()); + int expected_barcode_type = CV_8UC1; + for(size_t i = 0; i < straight_barcode.size(); i++) + EXPECT_EQ(expected_barcode_type, straight_barcode[i].type()); #else ASSERT_TRUE(qrcode.detectMulti(src, corners)); #endif @@ -612,6 +623,32 @@ TEST(Objdetect_QRCode_detectMulti, detect_regression_16961) EXPECT_EQ(corners.size(), expect_corners_size); } +TEST(Objdetect_QRCode_decodeMulti, check_output_parameters_type_19363) +{ + const std::string name_current_image = "9_qrcodes.jpg"; + const std::string root = "qrcode/multiple/"; + + std::string image_path = findDataFile(root + name_current_image); + Mat src = imread(image_path); + ASSERT_FALSE(src.empty()) << "Can't read image: " << image_path; +#ifdef HAVE_QUIRC + QRCodeDetector qrcode; + std::vector corners; + std::vector decoded_info; +#if 0 // FIXIT: OutputArray::create() type check + std::vector straight_barcode_nchannels; + EXPECT_ANY_THROW(qrcode.detectAndDecodeMulti(src, decoded_info, corners, straight_barcode_nchannels)); +#endif + + int expected_barcode_type = CV_8UC1; + std::vector straight_barcode; + EXPECT_TRUE(qrcode.detectAndDecodeMulti(src, decoded_info, corners, straight_barcode)); + ASSERT_FALSE(corners.empty()); + for(size_t i = 0; i < straight_barcode.size(); i++) + EXPECT_EQ(expected_barcode_type, straight_barcode[i].type()); +#endif +} + TEST(Objdetect_QRCode_basic, not_found_qrcode) { std::vector corners;