1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-21 19:33:03 +04:00

Added support to clip layer

This commit is contained in:
Abhishek Gola
2025-08-01 16:59:27 +05:30
parent 3f1402e081
commit 094430c8f0
7 changed files with 182 additions and 36 deletions
@@ -1360,6 +1360,11 @@ CV__DNN_INLINE_NS_BEGIN
static Ptr<CastLayer> create(const LayerParams &params);
};
class CV_EXPORTS ClipLayer : public Layer {
public:
static Ptr<ClipLayer> create(const LayerParams &params);
};
class CV_EXPORTS DepthToSpaceLayer : public Layer {
public:
static Ptr<DepthToSpaceLayer> create(const LayerParams &params);
+1
View File
@@ -125,6 +125,7 @@ void initializeLayerFactory()
CV_DNN_REGISTER_LAYER_CLASS(ReLU, ReLULayer);
CV_DNN_REGISTER_LAYER_CLASS(ReLU6, ReLU6Layer);
CV_DNN_REGISTER_LAYER_CLASS(Clip, ClipLayer);
CV_DNN_REGISTER_LAYER_CLASS(ChannelsPReLU, ChannelsPReLULayer);
CV_DNN_REGISTER_LAYER_CLASS(PReLU, ChannelsPReLULayer);
CV_DNN_REGISTER_LAYER_CLASS(Sigmoid, SigmoidLayer);
+136
View File
@@ -0,0 +1,136 @@
// 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) 2025, BigVision LLC, all rights reserved.
// Third party copyrights are property of their respective owners.
#include "../precomp.hpp"
#include "layers_common.hpp"
#include <opencv2/dnn/shape_utils.hpp>
#include <opencv2/core/hal/interface.h>
#include <limits>
#include <cfloat>
#include <algorithm>
namespace cv {
namespace dnn {
static double typeMin(int depth)
{
switch (depth)
{
case CV_8U: return std::numeric_limits<uchar>::lowest();
case CV_8S: return std::numeric_limits<schar>::lowest();
case CV_16U: return std::numeric_limits<ushort>::lowest();
case CV_16S: return std::numeric_limits<short>::lowest();
case CV_32S: return std::numeric_limits<int>::lowest();
case CV_32F: return -FLT_MAX;
case CV_64F: return -DBL_MAX;
default: CV_Error(Error::StsUnsupportedFormat, "Clip: unsupported depth");
}
}
static double typeMax(int depth)
{
switch (depth)
{
case CV_8U: return std::numeric_limits<uchar>::max();
case CV_8S: return std::numeric_limits<schar>::max();
case CV_16U: return std::numeric_limits<ushort>::max();
case CV_16S: return std::numeric_limits<short>::max();
case CV_32S: return std::numeric_limits<int>::max();
case CV_32F: return FLT_MAX;
case CV_64F: return DBL_MAX;
default: CV_Error(Error::StsUnsupportedFormat, "Clip: unsupported depth");
}
}
class ClipLayerImpl CV_FINAL : public ClipLayer
{
public:
float minValue, maxValue;
bool hasMin, hasMax;
ClipLayerImpl(const LayerParams& params)
{
setParamsFrom(params);
hasMin = params.has("min");
hasMax = params.has("max");
if (hasMin) minValue = params.get<float>("min");
if (hasMax) maxValue = params.get<float>("max");
if (hasMin && hasMax)
CV_Assert(minValue <= maxValue);
}
virtual bool supportBackend(int backendId) CV_OVERRIDE
{
return backendId == DNN_BACKEND_OPENCV;
}
bool getMemoryShapes(const std::vector<MatShape> &inputs,
const int requiredOutputs,
std::vector<MatShape> &outputs,
std::vector<MatShape> &internals) const CV_OVERRIDE
{
CV_Assert(!inputs.empty());
outputs.assign(1, inputs[0]);
return false;
}
void getTypes(const std::vector<MatType>& inputs,
const int requiredOutputs,
const int requiredInternals,
std::vector<MatType>& outputs,
std::vector<MatType>& internals) const CV_OVERRIDE
{
CV_Assert(!inputs.empty());
outputs.assign(requiredOutputs, inputs[0]);
internals.assign(requiredInternals, inputs[0]);
}
void forward(InputArrayOfArrays inputs_arr,
OutputArrayOfArrays outputs_arr,
OutputArrayOfArrays internals_arr) CV_OVERRIDE
{
CV_TRACE_FUNCTION();
CV_TRACE_ARG_VALUE(name, "name", name.c_str());
if (inputs_arr.depth() == CV_16F)
{
forward_fallback(inputs_arr, outputs_arr, internals_arr);
return;
}
std::vector<Mat> inputs, outputs;
inputs_arr.getMatVector(inputs);
outputs_arr.getMatVector(outputs);
CV_Assert(!inputs.empty());
const Mat& data = inputs[0];
Mat& dst = outputs[0];
bool dynMin = inputs.size() >= 2 && !inputs[1].empty();
bool dynMax = inputs.size() >= 3 && !inputs[2].empty();
auto getScalar = [](const Mat& m)->double {
CV_Assert(m.total()==1);
Mat tmp;
m.convertTo(tmp, CV_64F);
return tmp.at<double>(0);
};
double actualMin = dynMin ? getScalar(inputs[1]) : (hasMin ? minValue : typeMin(data.depth()));
double actualMax = dynMax ? getScalar(inputs[2]) : (hasMax ? maxValue : typeMax(data.depth()));
CV_Assert(actualMin <= actualMax);
Scalar lowS = Scalar::all(actualMin);
Scalar highS = Scalar::all(actualMax);
cv::max(data, lowS, dst);
cv::min(dst, highS, dst);
}
};
Ptr<ClipLayer> ClipLayer::create(const LayerParams& params)
{
return Ptr<ClipLayer>(new ClipLayerImpl(params));
}
}}
+18 -14
View File
@@ -1187,32 +1187,36 @@ void ONNXImporter2::parseImageScaler(LayerParams& layerParams, const opencv_onnx
void ONNXImporter2::parseClip(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto)
{
layerParams.type = "ReLU6";
layerParams.type = "Clip";
float min_value = -FLT_MAX, max_value = FLT_MAX;
int input_size = node_proto.input_size();
CV_Check(input_size, 1 <= input_size && input_size <= 3, "");
if (input_size >= 2 && !node_proto.input(1).empty())
{
Mat m;
CV_Assert(net.isConstArg(node_inputs[1]));
net.argTensor(node_inputs[1]).convertTo(m, CV_32F);
CV_Assert(m.total() == 1);
min_value = m.at<float>(0);
if (net.isConstArg(node_inputs[1]))
{
Mat m = net.argTensor(node_inputs[1]);
m.convertTo(m, CV_32F);
CV_Assert(m.total() == 1);
min_value = m.at<float>(0);
layerParams.set("min", min_value);
}
}
if (input_size == 3 && !node_proto.input(2).empty())
{
Mat m;
CV_Assert(net.isConstArg(node_inputs[2]));
net.argTensor(node_inputs[2]).convertTo(m, CV_32F);
CV_Assert(m.total() == 1);
max_value = m.at<float>(0);
if (net.isConstArg(node_inputs[2]))
{
Mat m = net.argTensor(node_inputs[2]);
m.convertTo(m, CV_32F);
CV_Assert(m.total() == 1);
max_value = m.at<float>(0);
layerParams.set("max", max_value);
}
}
layerParams.set("min_value", layerParams.get<float>("min", min_value));
layerParams.set("max_value", layerParams.get<float>("max", max_value));
addLayer(layerParams, node_proto, 1);
addLayer(layerParams, node_proto);
}
void ONNXImporter2::parseLeakyRelu(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto)
@@ -355,27 +355,27 @@ CASE(test_celu)
CASE(test_celu_expanded)
// no filter
CASE(test_clip)
// no filter
SKIP;
CASE(test_clip_default_inbounds)
// no filter
SKIP;
CASE(test_clip_default_int8_inbounds)
// no filter
SKIP;
CASE(test_clip_default_int8_max)
// no filter
SKIP;
CASE(test_clip_default_int8_min)
// no filter
SKIP;
CASE(test_clip_default_max)
// no filter
SKIP;
CASE(test_clip_default_min)
// no filter
SKIP;
CASE(test_clip_example)
// no filter
SKIP;
CASE(test_clip_inbounds)
// no filter
SKIP;
CASE(test_clip_outbounds)
// no filter
SKIP;
CASE(test_clip_splitbounds)
// no filter
SKIP;
CASE(test_compress_0)
// no filter
CASE(test_compress_1)
@@ -55,3 +55,14 @@
"test_unsqueeze_three_axes",
"test_unsqueeze_two_axes",
"test_unsqueeze_unsorted_axes",
"test_clip",
"test_clip_default_inbounds",
"test_clip_default_int8_inbounds",
"test_clip_default_int8_max",
"test_clip_default_int8_min",
"test_clip_default_max",
"test_clip_default_min",
"test_clip_example",
"test_clip_inbounds",
"test_clip_outbounds",
"test_clip_splitbounds",
@@ -48,17 +48,6 @@
"test_castlike_FLOAT_to_FLOAT16_expanded", // Issues::Layer::mismatch in input and output shapes inputs.size() == requiredOutputs in function 'getMemoryShapes'
"test_castlike_FLOAT_to_STRING",
"test_castlike_STRING_to_FLOAT", // Issues::Layer::Can't create layer "onnx_node_output_0!output" of type "CastLike" in function 'getLayerInstance'
"test_clip", // Issue:: Unkonwn error
"test_clip_default_inbounds", // ---- same as above ---
"test_clip_default_int8_inbounds", // ---- same as above ---
"test_clip_default_int8_max", // ---- same as above ---
"test_clip_default_int8_min", // ---- same as above ---
"test_clip_default_max", // ---- same as above ---
"test_clip_default_min", // ---- same as above ---
"test_clip_example", // ---- same as above ---
"test_clip_inbounds", // ---- same as above ---
"test_clip_outbounds", // ---- same as above ---
"test_clip_splitbounds", // ---- same as above ---
"test_compress_0", // Issue::Can't create layer "onnx_node_output_0!output" of type "Compress" in function 'getLayerInstance'
"test_compress_1", // ---- same as above ---
"test_compress_default_axis", // ---- same as above ---