mirror of
https://github.com/opencv/opencv.git
synced 2026-07-21 19:33:03 +04:00
Merge pull request #27624 from abhishek-gola:clip_layer_add
Added Clip layer to new DNN engine
This commit is contained in:
@@ -1360,6 +1360,11 @@ CV__DNN_INLINE_NS_BEGIN
|
||||
static Ptr<CastLayer> create(const LayerParams ¶ms);
|
||||
};
|
||||
|
||||
class CV_EXPORTS ClipLayer : public Layer {
|
||||
public:
|
||||
static Ptr<ClipLayer> create(const LayerParams ¶ms);
|
||||
};
|
||||
|
||||
class CV_EXPORTS DepthToSpaceLayer : public Layer {
|
||||
public:
|
||||
static Ptr<DepthToSpaceLayer> create(const LayerParams ¶ms);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}}
|
||||
@@ -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 ---
|
||||
|
||||
Reference in New Issue
Block a user