5772aad91c398306befa67935e3af673f986f518
[platform/upstream/opencv.git] / modules / dnn / src / layers / normalize_bbox_layer.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
14 // Copyright (C) 2017, Intel Corporation, all rights reserved.
15 // Third party copyrights are property of their respective owners.
16 //
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
19 //
20 //   * Redistribution's of source code must retain the above copyright notice,
21 //     this list of conditions and the following disclaimer.
22 //
23 //   * Redistribution's in binary form must reproduce the above copyright notice,
24 //     this list of conditions and the following disclaimer in the documentation
25 //     and/or other materials provided with the distribution.
26 //
27 //   * The name of the copyright holders may not be used to endorse or promote products
28 //     derived from this software without specific prior written permission.
29 //
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
40 //
41 //M*/
42
43 #include "../precomp.hpp"
44 #include "layers_common.hpp"
45
46 namespace cv { namespace dnn {
47
48 class NormalizeBBoxLayerImpl CV_FINAL : public NormalizeBBoxLayer
49 {
50 public:
51     NormalizeBBoxLayerImpl(const LayerParams& params)
52     {
53         setParamsFrom(params);
54         pnorm = params.get<float>("p", 2);
55         epsilon = params.get<float>("eps", 1e-10f);
56         acrossSpatial = params.get<bool>("across_spatial", true);
57         CV_Assert(pnorm > 0);
58     }
59
60     bool getMemoryShapes(const std::vector<MatShape> &inputs,
61                          const int requiredOutputs,
62                          std::vector<MatShape> &outputs,
63                          std::vector<MatShape> &internals) const CV_OVERRIDE
64     {
65         CV_Assert(inputs.size() == 1);
66         Layer::getMemoryShapes(inputs, requiredOutputs, outputs, internals);
67         internals.resize(1, inputs[0]);
68         internals[0][0] = 1;  // Batch size.
69         return true;
70     }
71
72 #ifdef HAVE_OPENCL
73     bool forward_ocl(InputArrayOfArrays inputs_, OutputArrayOfArrays outputs_, OutputArrayOfArrays internals_)
74     {
75         std::vector<UMat> inputs;
76         std::vector<UMat> outputs;
77         std::vector<UMat> internals;
78
79         inputs_.getUMatVector(inputs);
80         outputs_.getUMatVector(outputs);
81         internals_.getUMatVector(internals);
82
83         CV_Assert(inputs.size() == 1 && outputs.size() == 1);
84         CV_Assert(inputs[0].total() == outputs[0].total());
85
86         const UMat& inp0 = inputs[0];
87         UMat& buffer = internals[0];
88         size_t num = inp0.size[0];
89         size_t channels = inp0.size[1];
90         size_t channelSize = inp0.total() / (num * channels);
91         for (size_t i = 0; i < num; ++i)
92         {
93             MatShape s = shape(channels, channelSize);
94             UMat src = inputs[i].reshape(1, s.size(), &s[0]);
95             UMat dst = outputs[i].reshape(1, s.size(), &s[0]);
96
97             UMat abs_mat;
98             absdiff(src, cv::Scalar::all(0), abs_mat);
99             pow(abs_mat, pnorm, buffer);
100
101             if (acrossSpatial)
102             {
103                 // add eps to avoid overflow
104                 float absSum = sum(buffer)[0] + epsilon;
105                 float norm = pow(absSum, 1.0f / pnorm);
106                 multiply(src, 1.0f / norm, dst);
107             }
108             else
109             {
110                 Mat norm;
111                 reduce(buffer, norm, 0, REDUCE_SUM);
112                 norm += epsilon;
113
114                 // compute inverted norm to call multiply instead divide
115                 cv::pow(norm, -1.0f / pnorm, norm);
116
117                 repeat(norm, channels, 1, buffer);
118                 multiply(src, buffer, dst);
119             }
120
121             if (!blobs.empty())
122             {
123                 // scale the output
124                 Mat scale = blobs[0];
125                 if (scale.total() == 1)
126                 {
127                     // _scale: 1 x 1
128                     multiply(dst, scale.at<float>(0, 0), dst);
129                 }
130                 else
131                 {
132                     // _scale: _channels x 1
133                     CV_Assert(scale.total() == channels);
134                     repeat(scale, 1, dst.cols, buffer);
135                     multiply(dst, buffer, dst);
136                 }
137             }
138         }
139         return true;
140     }
141 #endif
142
143     void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE
144     {
145         CV_TRACE_FUNCTION();
146         CV_TRACE_ARG_VALUE(name, "name", name.c_str());
147
148         CV_OCL_RUN((preferableTarget == DNN_TARGET_OPENCL) &&
149                    OCL_PERFORMANCE_CHECK(ocl::Device::getDefault().isIntel()),
150                    forward_ocl(inputs_arr, outputs_arr, internals_arr))
151
152         Layer::forward_fallback(inputs_arr, outputs_arr, internals_arr);
153     }
154
155     void forward(std::vector<Mat*> &inputs, std::vector<Mat> &outputs, std::vector<Mat> &internals) CV_OVERRIDE
156     {
157         CV_TRACE_FUNCTION();
158         CV_TRACE_ARG_VALUE(name, "name", name.c_str());
159
160         CV_Assert(inputs.size() == 1 && outputs.size() == 1);
161         CV_Assert(inputs[0]->total() == outputs[0].total());
162
163         const Mat& inp0 = *inputs[0];
164         Mat& buffer = internals[0];
165         size_t num = inp0.size[0];
166         size_t channels = inp0.size[1];
167         size_t channelSize = inp0.total() / (num * channels);
168         for (size_t n = 0; n < num; ++n)
169         {
170             Mat src = Mat(channels, channelSize, CV_32F, (void*)inp0.ptr<float>(n));
171             Mat dst = Mat(channels, channelSize, CV_32F, (void*)outputs[0].ptr<float>(n));
172
173             cv::pow(abs(src), pnorm, buffer);
174
175             if (acrossSpatial)
176             {
177                 // add eps to avoid overflow
178                 float absSum = sum(buffer)[0] + epsilon;
179                 float norm = pow(absSum, 1.0f / pnorm);
180                 multiply(src, 1.0f / norm, dst);
181             }
182             else
183             {
184                 Mat norm;
185                 reduce(buffer, norm, 0, REDUCE_SUM);
186                 norm += epsilon;
187
188                 // compute inverted norm to call multiply instead divide
189                 cv::pow(norm, -1.0f / pnorm, norm);
190
191                 repeat(norm, channels, 1, buffer);
192                 multiply(src, buffer, dst);
193             }
194
195             if (!blobs.empty())
196             {
197                 // scale the output
198                 Mat scale = blobs[0];
199                 if (scale.total() == 1)
200                 {
201                     // _scale: 1 x 1
202                     dst *= scale.at<float>(0, 0);
203                 }
204                 else
205                 {
206                     // _scale: _channels x 1
207                     CV_Assert(scale.total() == channels);
208                     repeat(scale, 1, dst.cols, buffer);
209                     multiply(dst, buffer, dst);
210                 }
211             }
212         }
213     }
214 };
215
216
217 Ptr<NormalizeBBoxLayer> NormalizeBBoxLayer::create(const LayerParams &params)
218 {
219     return Ptr<NormalizeBBoxLayer>(new NormalizeBBoxLayerImpl(params));
220 }
221
222 }
223 }