From 457120bb94e6b1101a6e5d8f7b848c0036050e94 Mon Sep 17 00:00:00 2001 From: Om Navin Rope Date: Mon, 27 Apr 2026 13:25:45 +0530 Subject: [PATCH] Add LpNormalization Layer support --- modules/dnn/src/layers/normalize_bbox_layer.cpp | 16 +++++++++++++--- modules/dnn/src/onnx/onnx_importer2.cpp | 8 ++++++++ ...nx_conformance_layer_filter__openvino.inl.hpp | 2 ++ ..._layer_filter_opencv_classic_denylist.inl.hpp | 1 + ...nnx_conformance_layer_parser_denylist.inl.hpp | 1 - 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/modules/dnn/src/layers/normalize_bbox_layer.cpp b/modules/dnn/src/layers/normalize_bbox_layer.cpp index 1ed9f4421a..5e6e249a56 100644 --- a/modules/dnn/src/layers/normalize_bbox_layer.cpp +++ b/modules/dnn/src/layers/normalize_bbox_layer.cpp @@ -62,9 +62,19 @@ public: pnorm = params.get("p", 2); epsilon = params.get("eps", 1e-10f); acrossSpatial = params.get("across_spatial", true); - startAxis = params.get("start_axis", 1); - CV_Assert(!params.has("across_spatial") || !params.has("end_axis")); - endAxis = params.get("end_axis", acrossSpatial ? -1 : startAxis); + + if (!params.has("start_axis") && !params.has("across_spatial")) + { + int axis = params.get("axis", -1); + startAxis = axis; + endAxis = axis; + } + else + { + startAxis = params.get("start_axis", 1); + CV_Assert(!params.has("across_spatial") || !params.has("end_axis")); + endAxis = params.get("end_axis", acrossSpatial ? -1 : startAxis); + } CV_Assert(pnorm > 0); } diff --git a/modules/dnn/src/onnx/onnx_importer2.cpp b/modules/dnn/src/onnx/onnx_importer2.cpp index acbd1d4c85..3064c0d31b 100644 --- a/modules/dnn/src/onnx/onnx_importer2.cpp +++ b/modules/dnn/src/onnx/onnx_importer2.cpp @@ -203,6 +203,7 @@ protected: void parseInstanceNormalization(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseLayerNorm (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseLeakyRelu (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); + void parseLpNormalization (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseLRN (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseLSTM (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseMatMul (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); @@ -1310,6 +1311,12 @@ void ONNXImporter2::parsePRelu(LayerParams& layerParams, const opencv_onnx::Node addLayer(layerParams, node_proto, 1); } +void ONNXImporter2::parseLpNormalization(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto) +{ + layerParams.type = "NormalizeBBox"; + addLayer(layerParams, node_proto); +} + void ONNXImporter2::parseLRN(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto) { replaceLayerParam(layerParams, "size", "local_size"); @@ -2710,6 +2717,7 @@ void ONNXImporter2::buildDispatchMap_ONNX_AI() dispatch["Abs"] = &ONNXImporter2::parseAbs; dispatch["PRelu"] = &ONNXImporter2::parsePRelu; dispatch["NonZero"] = &ONNXImporter2::parseNonZero; + dispatch["LpNormalization"] = &ONNXImporter2::parseLpNormalization; dispatch["LRN"] = &ONNXImporter2::parseLRN; dispatch["InstanceNormalization"] = &ONNXImporter2::parseInstanceNormalization; dispatch["BatchNormalization"] = &ONNXImporter2::parseBatchNormalization; diff --git a/modules/dnn/test/test_onnx_conformance_layer_filter__openvino.inl.hpp b/modules/dnn/test/test_onnx_conformance_layer_filter__openvino.inl.hpp index b9fcad03f0..edefdccbbe 100644 --- a/modules/dnn/test/test_onnx_conformance_layer_filter__openvino.inl.hpp +++ b/modules/dnn/test/test_onnx_conformance_layer_filter__openvino.inl.hpp @@ -1314,6 +1314,8 @@ CASE(test_layer_normalization_default_axis_expanded) SKIP; CASE(test_layer_normalization_default_axis_expanded_ver18) SKIP; +CASE(test_lpnormalization_default) + SKIP; CASE(test_leakyrelu) // no filter CASE(test_leakyrelu_default) diff --git a/modules/dnn/test/test_onnx_conformance_layer_filter_opencv_classic_denylist.inl.hpp b/modules/dnn/test/test_onnx_conformance_layer_filter_opencv_classic_denylist.inl.hpp index de2ffc9bf5..5bcf9ec6f4 100644 --- a/modules/dnn/test/test_onnx_conformance_layer_filter_opencv_classic_denylist.inl.hpp +++ b/modules/dnn/test/test_onnx_conformance_layer_filter_opencv_classic_denylist.inl.hpp @@ -252,6 +252,7 @@ "test_less_uint32", "test_less_uint64", "test_less_uint8", +"test_lpnormalization_default", "test_resize_upsample_scales_nearest_axes_2_3", "test_resize_upsample_sizes_nearest_axes_2_3", "test_split_equal_parts_2d_opset13", 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 8380828892..d7a8ed1ff2 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 @@ -330,7 +330,6 @@ "test_l2normalization_axis_1", "test_loop13_seq", // Loop with tensor sequences output, not yet supported in OpenCV "test_loop16_seq_none", // Loop with optional tensor sequences, not yet supported in OpenCV -"test_lpnormalization_default", "test_lppool_1d_default", "test_lppool_2d_default", "test_lppool_2d_dilations",