diff --git a/modules/dnn/src/layers/padding_layer.cpp b/modules/dnn/src/layers/padding_layer.cpp index af3dacdd7a..9d7ca23714 100644 --- a/modules/dnn/src/layers/padding_layer.cpp +++ b/modules/dnn/src/layers/padding_layer.cpp @@ -130,12 +130,13 @@ public: outputs[0].setTo(paddingValue); inputs[0].copyTo(outputs[0](dstRanges)); } - else if (paddingType == "reflect") + else if (paddingType == "reflect" || paddingType == "edge") { CV_Assert(inputs.size() == 1); CV_Assert(outputs.size() == 1); CV_Assert(inputs[0].dims == 4); CV_Assert(outputs[0].dims == 4); + int borderType = paddingType == "reflect" ? BORDER_REFLECT_101 : BORDER_REPLICATE; if (inputs[0].size[0] != outputs[0].size[0] || inputs[0].size[1] != outputs[0].size[1]) CV_Error(Error::StsNotImplemented, "Only spatial reflection padding is supported."); @@ -148,8 +149,8 @@ public: const int padBottom = outHeight - dstRanges[2].end; const int padLeft = dstRanges[3].start; const int padRight = outWidth - dstRanges[3].end; - CV_CheckLT(padTop, inpHeight, ""); CV_CheckLT(padBottom, inpHeight, ""); - CV_CheckLT(padLeft, inpWidth, ""); CV_CheckLT(padRight, inpWidth, ""); + CV_CheckLE(padTop, inpHeight, ""); CV_CheckLE(padBottom, inpHeight, ""); + CV_CheckLE(padLeft, inpWidth, ""); CV_CheckLE(padRight, inpWidth, ""); for (size_t n = 0; n < inputs[0].size[0]; ++n) { @@ -158,7 +159,7 @@ public: copyMakeBorder(getPlane(inputs[0], n, ch), getPlane(outputs[0], n, ch), padTop, padBottom, padLeft, padRight, - BORDER_REFLECT_101); + borderType); } } } diff --git a/modules/dnn/src/onnx/onnx_importer.cpp b/modules/dnn/src/onnx/onnx_importer.cpp index 8ff91f5e44..052b1b8529 100644 --- a/modules/dnn/src/onnx/onnx_importer.cpp +++ b/modules/dnn/src/onnx/onnx_importer.cpp @@ -131,6 +131,7 @@ private: typedef void (ONNXImporter::*ONNXImporterNodeParser)(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); typedef std::map DispatchMap; + void parseMaxUnpool (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseMaxPool (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseAveragePool (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseReduce (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); @@ -625,6 +626,41 @@ void setCeilMode(LayerParams& layerParams) } } +void ONNXImporter::parseMaxUnpool(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto) +{ + layerParams.type = "MaxUnpool"; + + DictValue kernel_shape = layerParams.get("kernel_size"); + CV_Assert(kernel_shape.size() == 2); + layerParams.set("pool_k_w", kernel_shape.get(0)); + layerParams.set("pool_k_h", kernel_shape.get(1)); + + int pool_pad_w = 0, pool_pad_h = 0; + if (layerParams.has("pad")) + { + DictValue pads = layerParams.get("pad"); + CV_CheckEQ(pads.size(), 2, ""); + pool_pad_w = pads.get(0); + pool_pad_h = pads.get(1); + } + layerParams.set("pool_pad_w", pool_pad_w); + layerParams.set("pool_pad_h", pool_pad_h); + + + int pool_stride_w = 1, pool_stride_h = 1; + if (layerParams.has("stride")) + { + DictValue strides = layerParams.get("stride"); + CV_CheckEQ(strides.size(), 2, ""); + pool_stride_w = strides.get(0); + pool_stride_h = strides.get(1); + } + layerParams.set("pool_stride_w", pool_stride_w); + layerParams.set("pool_stride_h", pool_stride_h); + + addLayer(layerParams, node_proto); +} + void ONNXImporter::parseMaxPool(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto) { layerParams.type = "Pooling"; @@ -659,11 +695,11 @@ void ONNXImporter::parseReduce(LayerParams& layerParams, const opencv_onnx::Node pool = "AVE"; layerParams.set("pool", pool); layerParams.set("global_pooling", !layerParams.has("axes")); + bool keepdims = layerParams.get("keepdims", 1) == 1; if (layerParams.has("axes") && (layer_type == "ReduceMean" || layer_type == "ReduceSum" || layer_type == "ReduceMax")) { MatShape inpShape = outShapes[node_proto.input(0)]; DictValue axes = layerParams.get("axes"); - bool keepdims = layerParams.get("keepdims"); MatShape targetShape; std::vector shouldDelete(inpShape.size(), false); for (int i = 0; i < axes.size(); i++) { @@ -771,7 +807,10 @@ void ONNXImporter::parseReduce(LayerParams& layerParams, const opencv_onnx::Node } else if (!layerParams.has("axes") && (layer_type == "ReduceMean" || layer_type == "ReduceSum" || layer_type == "ReduceMax")) { - CV_CheckEQ(layerParams.get("keepdims"), 0, "layer only supports keepdims = false"); + IterShape_t shapeIt = outShapes.find(node_proto.input(0)); + CV_Assert(shapeIt != outShapes.end()); + const size_t dims = keepdims ? shapeIt->second.size() : 1; + LayerParams reshapeLp; reshapeLp.name = layerParams.name + "/reshape"; reshapeLp.type = "Reshape"; @@ -793,8 +832,8 @@ void ONNXImporter::parseReduce(LayerParams& layerParams, const opencv_onnx::Node addLayer(poolLp, node_proto); layerParams.type = "Reshape"; - int targetShape[] = {1}; - layerParams.set("dim", DictValue::arrayInt(&targetShape[0], 1)); + std::vector targetShape(dims, 1); + layerParams.set("dim", DictValue::arrayInt(targetShape.data(), targetShape.size())); node_proto.set_input(0, node_proto.output(0)); node_proto.set_output(0, layerParams.name); @@ -2341,6 +2380,7 @@ const ONNXImporter::DispatchMap ONNXImporter::buildDispatchMap() { DispatchMap dispatch; + dispatch["MaxUnpool"] = &ONNXImporter::parseMaxUnpool; dispatch["MaxPool"] = &ONNXImporter::parseMaxPool; dispatch["AveragePool"] = &ONNXImporter::parseAveragePool; dispatch["GlobalAveragePool"] = dispatch["GlobalMaxPool"] = dispatch["ReduceMean"] = dispatch["ReduceSum"] = diff --git a/modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp b/modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp index 5f1d99d4bb..2489105e91 100644 --- a/modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp +++ b/modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp @@ -277,7 +277,6 @@ "test_max_uint8", "test_maxpool_2d_uint8", "test_maxunpool_export_with_output_shape", -"test_maxunpool_export_without_output_shape", "test_mean_example", "test_mean_one_input", "test_mean_two_inputs", @@ -436,10 +435,6 @@ "test_reduce_log_sum_exp_negative_axes_keepdims_example", "test_reduce_log_sum_exp_negative_axes_keepdims_random", "test_reduce_log_sum_negative_axes", -"test_reduce_max_default_axes_keepdim_example", -"test_reduce_max_default_axes_keepdims_random", -"test_reduce_mean_default_axes_keepdims_example", -"test_reduce_mean_default_axes_keepdims_random", "test_reduce_min_default_axes_keepdims_example", "test_reduce_min_default_axes_keepdims_random", "test_reduce_min_do_not_keepdims_example",