From c44d03d8e134cfb840a76e246cbcfbf5a6147017 Mon Sep 17 00:00:00 2001 From: Abhishek Gola Date: Fri, 3 Apr 2026 17:39:37 +0530 Subject: [PATCH] added eyelike layer support --- .../dnn/include/opencv2/dnn/all_layers.hpp | 6 + modules/dnn/src/init.cpp | 1 + modules/dnn/src/layers/eyelike_layer.cpp | 117 ++++++++++++++++++ modules/dnn/src/onnx/onnx_importer2.cpp | 13 ++ ...conformance_layer_filter__openvino.inl.hpp | 6 +- ...yer_filter_opencv_classic_denylist.inl.hpp | 3 + ..._conformance_layer_parser_denylist.inl.hpp | 3 - 7 files changed, 143 insertions(+), 6 deletions(-) create mode 100644 modules/dnn/src/layers/eyelike_layer.cpp diff --git a/modules/dnn/include/opencv2/dnn/all_layers.hpp b/modules/dnn/include/opencv2/dnn/all_layers.hpp index 6b18f41518..c7ad885a1a 100644 --- a/modules/dnn/include/opencv2/dnn/all_layers.hpp +++ b/modules/dnn/include/opencv2/dnn/all_layers.hpp @@ -1557,6 +1557,12 @@ CV__DNN_INLINE_NS_BEGIN static Ptr create(const LayerParams ¶ms); }; + class CV_EXPORTS EyeLikeLayer : public Layer + { + public: + static Ptr create(const LayerParams ¶ms); + }; + class CV_EXPORTS CenterCropPadLayer : public Layer { public: diff --git a/modules/dnn/src/init.cpp b/modules/dnn/src/init.cpp index 8deae9ca5a..24a6051770 100644 --- a/modules/dnn/src/init.cpp +++ b/modules/dnn/src/init.cpp @@ -120,6 +120,7 @@ void initializeLayerFactory() CV_DNN_REGISTER_LAYER_CLASS(IsInf, IsInfLayer); CV_DNN_REGISTER_LAYER_CLASS(OneHot, OneHotLayer); CV_DNN_REGISTER_LAYER_CLASS(Det, DetLayer); + CV_DNN_REGISTER_LAYER_CLASS(EyeLike, EyeLikeLayer); CV_DNN_REGISTER_LAYER_CLASS(BlackmanWindow, BlackmanWindowLayer); CV_DNN_REGISTER_LAYER_CLASS(HannWindow, HannWindowLayer); CV_DNN_REGISTER_LAYER_CLASS(HammingWindow, HammingWindowLayer); diff --git a/modules/dnn/src/layers/eyelike_layer.cpp b/modules/dnn/src/layers/eyelike_layer.cpp new file mode 100644 index 0000000000..e43d733480 --- /dev/null +++ b/modules/dnn/src/layers/eyelike_layer.cpp @@ -0,0 +1,117 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// Copyright (C) 2026, BigVision LLC, all rights reserved. +// Third party copyrights are property of their respective owners. + +#include "../precomp.hpp" +#include "layers_common.hpp" +#include + +namespace cv { +namespace dnn { + +// ONNX EyeLike operator +// Spec: https://onnx.ai/onnx/operators/onnx__EyeLike.html +// Supported opsets: 9-22 + +class EyeLikeLayerImpl CV_FINAL : public EyeLikeLayer +{ +public: + int k; // diagonal offset + int outputDtype; // -1 means use input dtype + + EyeLikeLayerImpl(const LayerParams& params) + { + setParamsFrom(params); + k = params.get("k", 0); + outputDtype = params.get("dtype", -1); + } + + bool supportBackend(int backendId) CV_OVERRIDE + { + return backendId == DNN_BACKEND_OPENCV; + } + + bool getMemoryShapes(const std::vector& inputs, + const int /*requiredOutputs*/, + std::vector& outputs, + std::vector& /*internals*/) const CV_OVERRIDE + { + CV_Assert(inputs.size() == 1); + const MatShape& in = inputs[0]; + CV_Assert(in.size() == 2); + outputs.assign(1, in); + return false; + } + + void getTypes(const std::vector& inputs, + const int requiredOutputs, + const int requiredInternals, + std::vector& outputs, + std::vector& internals) const CV_OVERRIDE + { + CV_Assert(!inputs.empty()); + int t = (outputDtype >= 0) ? outputDtype : inputs[0]; + outputs.assign(requiredOutputs, MatType(t)); + internals.assign(requiredInternals, MatType(t)); + } + + void forward(InputArrayOfArrays inputs_arr, + OutputArrayOfArrays outputs_arr, + OutputArrayOfArrays /*internals_arr*/) CV_OVERRIDE + { + std::vector inputs, outputs; + inputs_arr.getMatVector(inputs); + outputs_arr.getMatVector(outputs); + + CV_Assert(inputs.size() == 1); + const Mat& X = inputs[0]; + CV_Assert(X.dims == 2); + + int rows = X.size[0]; + int cols = X.size[1]; + + int outType = (outputDtype >= 0) ? outputDtype : X.type(); + outputs[0].create(rows, cols, outType); + Mat& Y = outputs[0]; + Y.setTo(Scalar::all(0)); + + // Set ones on the k-th diagonal: Y[i, i+k] = 1 + int iStart = (k >= 0) ? 0 : -k; + int jStart = (k >= 0) ? k : 0; + int diagLen = std::min(rows - iStart, cols - jStart); + + switch (outType) + { + case CV_32F: fillDiag (Y, iStart, jStart, diagLen, 1.0f); break; + case CV_64F: fillDiag (Y, iStart, jStart, diagLen, 1.0); break; + case CV_32S: fillDiag (Y, iStart, jStart, diagLen, 1); break; + case CV_64S: fillDiag (Y, iStart, jStart, diagLen, 1); break; + case CV_8U: fillDiag (Y, iStart, jStart, diagLen, 1); break; + case CV_8S: fillDiag (Y, iStart, jStart, diagLen, 1); break; + case CV_16U: fillDiag(Y, iStart, jStart, diagLen, 1); break; + case CV_16S: fillDiag (Y, iStart, jStart, diagLen, 1); break; + case CV_16F: fillDiag (Y, iStart, jStart, diagLen, hfloat(1.0f)); break; + case CV_16BF: fillDiag (Y, iStart, jStart, diagLen, bfloat(1.0f)); break; + case CV_Bool: fillDiag (Y, iStart, jStart, diagLen, true); break; + default: + CV_Error(Error::BadDepth, "Unsupported output depth for EyeLikeLayer"); + } + } + +private: + template + static void fillDiag(Mat& Y, int iStart, int jStart, int diagLen, T one) + { + for (int d = 0; d < diagLen; ++d) + Y.at(iStart + d, jStart + d) = one; + } +}; + +Ptr EyeLikeLayer::create(const LayerParams& params) +{ + return Ptr(new EyeLikeLayerImpl(params)); +} + +}} diff --git a/modules/dnn/src/onnx/onnx_importer2.cpp b/modules/dnn/src/onnx/onnx_importer2.cpp index a03fae45dc..54a8604de6 100644 --- a/modules/dnn/src/onnx/onnx_importer2.cpp +++ b/modules/dnn/src/onnx/onnx_importer2.cpp @@ -221,6 +221,7 @@ protected: void parseOneHot (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseDFT (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseDet (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); + void parseEyeLike (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseBlackmanWindow (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseHannWindow (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseHammingWindow (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); @@ -1764,6 +1765,17 @@ void ONNXImporter2::parseDet(LayerParams& layerParams, const opencv_onnx::NodePr addLayer(layerParams, node_proto); } +void ONNXImporter2::parseEyeLike(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto) +{ + layerParams.type = "EyeLike"; + if (layerParams.has("dtype")) + { + int onnxDtype = layerParams.get("dtype"); + layerParams.set("dtype", dataType2cv((opencv_onnx::TensorProto_DataType)onnxDtype)); + } + addLayer(layerParams, node_proto); +} + void ONNXImporter2::parseBlackmanWindow(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto) { layerParams.type = "BlackmanWindow"; @@ -2731,6 +2743,7 @@ void ONNXImporter2::buildDispatchMap_ONNX_AI() dispatch["OneHot"] = &ONNXImporter2::parseOneHot; dispatch["DFT"] = &ONNXImporter2::parseDFT; dispatch["Det"] = &ONNXImporter2::parseDet; + dispatch["EyeLike"] = &ONNXImporter2::parseEyeLike; dispatch["BlackmanWindow"] = &ONNXImporter2::parseBlackmanWindow; dispatch["HannWindow"] = &ONNXImporter2::parseHannWindow; dispatch["HammingWindow"] = &ONNXImporter2::parseHammingWindow; 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 8380090602..b9fcad03f0 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 @@ -717,11 +717,11 @@ CASE(test_expand_dim_changed) CASE(test_expand_dim_unchanged) SKIP; CASE(test_eyelike_populate_off_main_diagonal) - // no filter + SKIP; CASE(test_eyelike_with_dtype) - // no filter + SKIP; CASE(test_eyelike_without_dtype) - // no filter + SKIP; CASE(test_flatten_axis0) // no filter CASE(test_flatten_axis1) 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 705c0207d6..de2ffc9bf5 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 @@ -735,3 +735,6 @@ "test_reduce_sum_square_empty_set_expanded", "test_reduce_log_sum_exp_empty_set_expanded", "test_loop11", +"test_eyelike_populate_off_main_diagonal", +"test_eyelike_with_dtype", +"test_eyelike_without_dtype", 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 31907751b8..8380828892 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 @@ -305,9 +305,6 @@ "test_einsum_scalar", "test_equal_string", "test_equal_string_broadcast", -"test_eyelike_populate_off_main_diagonal", // Issues::Layer::Can't create layer::Can't create layer "onnx_node_output_0!y" of type "EyeLike" in function 'getLayerInstance' -"test_eyelike_with_dtype", // ---- same as above --- -"test_eyelike_without_dtype", // ---- same as above --- "test_gridsample_bicubic", // ---- same as above --- "test_gridsample_bicubic_align_corners_0_additional_1", "test_gridsample_bicubic_align_corners_1_additional_1",