|
43 | 43 | #include "../precomp.hpp"
|
44 | 44 | #include "layers_common.hpp"
|
45 | 45 |
|
46 |
| -#include <float.h> |
47 |
| -#include <algorithm> |
48 |
| - |
49 |
| -namespace cv |
50 |
| -{ |
51 |
| -namespace dnn |
52 |
| -{ |
53 |
| - |
54 |
| -namespace |
55 |
| -{ |
56 |
| - const std::string layerName = "NormalizeBBox"; |
57 |
| -} |
| 46 | +namespace cv { namespace dnn { |
58 | 47 |
|
59 | 48 | class NormalizeBBoxLayerImpl : public NormalizeBBoxLayer
|
60 | 49 | {
|
61 |
| - float _eps; |
62 |
| - bool _across_spatial; |
63 |
| - bool _channel_shared; |
64 | 50 | public:
|
65 |
| - bool getParameterDict(const LayerParams ¶ms, |
66 |
| - const std::string ¶meterName, |
67 |
| - DictValue& result) |
68 |
| - { |
69 |
| - if (!params.has(parameterName)) |
70 |
| - { |
71 |
| - return false; |
72 |
| - } |
73 |
| - |
74 |
| - result = params.get(parameterName); |
75 |
| - return true; |
76 |
| - } |
77 |
| - |
78 |
| - template<typename T> |
79 |
| - T getParameter(const LayerParams ¶ms, |
80 |
| - const std::string ¶meterName, |
81 |
| - const size_t &idx=0, |
82 |
| - const bool required=true, |
83 |
| - const T& defaultValue=T()) |
| 51 | + NormalizeBBoxLayerImpl(const LayerParams& params) |
84 | 52 | {
|
85 |
| - DictValue dictValue; |
86 |
| - bool success = getParameterDict(params, parameterName, dictValue); |
87 |
| - if(!success) |
88 |
| - { |
89 |
| - if(required) |
90 |
| - { |
91 |
| - std::string message = layerName; |
92 |
| - message += " layer parameter does not contain "; |
93 |
| - message += parameterName; |
94 |
| - message += " parameter."; |
95 |
| - CV_Error(Error::StsBadArg, message); |
96 |
| - } |
97 |
| - else |
98 |
| - { |
99 |
| - return defaultValue; |
100 |
| - } |
101 |
| - } |
102 |
| - return dictValue.get<T>(idx); |
103 |
| - } |
104 |
| - |
105 |
| - NormalizeBBoxLayerImpl(const LayerParams ¶ms) |
106 |
| - { |
107 |
| - _eps = getParameter<float>(params, "eps", 0, false, 1e-10f); |
108 |
| - _across_spatial = getParameter<bool>(params, "across_spatial"); |
109 |
| - _channel_shared = getParameter<bool>(params, "channel_shared"); |
110 | 53 | setParamsFrom(params);
|
111 |
| - } |
112 |
| - |
113 |
| - void checkInputs(const std::vector<Mat*> &inputs) |
114 |
| - { |
115 |
| - CV_Assert(inputs.size() > 0); |
116 |
| - CV_Assert(inputs[0]->dims == 4 && inputs[0]->type() == CV_32F); |
117 |
| - for (size_t i = 1; i < inputs.size(); i++) |
118 |
| - { |
119 |
| - CV_Assert(inputs[i]->dims == 4 && inputs[i]->type() == CV_32F); |
120 |
| - CV_Assert(inputs[i]->size == inputs[0]->size); |
121 |
| - } |
122 |
| - CV_Assert(inputs[0]->dims > 2); |
| 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); |
123 | 58 | }
|
124 | 59 |
|
125 | 60 | bool getMemoryShapes(const std::vector<MatShape> &inputs,
|
126 | 61 | const int requiredOutputs,
|
127 | 62 | std::vector<MatShape> &outputs,
|
128 | 63 | std::vector<MatShape> &internals) const
|
129 | 64 | {
|
130 |
| - bool inplace = Layer::getMemoryShapes(inputs, requiredOutputs, outputs, internals); |
131 |
| - size_t channels = inputs[0][1]; |
132 |
| - size_t rows = inputs[0][2]; |
133 |
| - size_t cols = inputs[0][3]; |
134 |
| - size_t channelSize = rows * cols; |
135 |
| - |
136 |
| - internals.assign(1, shape(channels, channelSize)); |
137 |
| - internals.push_back(shape(channels, 1)); |
138 |
| - internals.push_back(shape(1, channelSize)); |
139 |
| - |
140 |
| - return inplace; |
| 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; |
141 | 70 | }
|
142 | 71 |
|
143 | 72 | void forward(std::vector<Mat*> &inputs, std::vector<Mat> &outputs, std::vector<Mat> &internals)
|
144 | 73 | {
|
145 | 74 | CV_TRACE_FUNCTION();
|
146 | 75 | CV_TRACE_ARG_VALUE(name, "name", name.c_str());
|
147 | 76 |
|
148 |
| - checkInputs(inputs); |
149 |
| - |
150 |
| - Mat& buffer = internals[0], sumChannelMultiplier = internals[1], |
151 |
| - sumSpatialMultiplier = internals[2]; |
152 |
| - |
153 |
| - sumChannelMultiplier.setTo(1.0); |
154 |
| - sumSpatialMultiplier.setTo(1.0); |
| 77 | + CV_Assert(inputs.size() == 1 && outputs.size() == 1); |
| 78 | + CV_Assert(inputs[0]->total() == outputs[0].total()); |
155 | 79 |
|
156 | 80 | const Mat& inp0 = *inputs[0];
|
| 81 | + Mat& buffer = internals[0]; |
157 | 82 | size_t num = inp0.size[0];
|
158 | 83 | size_t channels = inp0.size[1];
|
159 |
| - size_t channelSize = inp0.size[2] * inp0.size[3]; |
160 |
| - |
161 |
| - Mat zeroBuffer(channels, channelSize, CV_32F, Scalar(0)); |
162 |
| - Mat absDiff; |
163 |
| - Mat scale = blobs[0]; |
164 |
| - for (size_t j = 0; j < inputs.size(); j++) |
| 84 | + size_t channelSize = inp0.total() / (num * channels); |
| 85 | + for (size_t n = 0; n < num; ++n) |
165 | 86 | {
|
166 |
| - for (size_t n = 0; n < num; ++n) |
167 |
| - { |
168 |
| - Mat src = Mat(channels, channelSize, CV_32F, inputs[j]->ptr<float>(n)); |
169 |
| - Mat dst = Mat(channels, channelSize, CV_32F, outputs[j].ptr<float>(n)); |
170 |
| - |
171 |
| - buffer = src.mul(src); |
172 |
| - |
173 |
| - if (_across_spatial) |
174 |
| - { |
175 |
| - absdiff(buffer, zeroBuffer, absDiff); |
176 |
| - |
177 |
| - // add eps to avoid overflow |
178 |
| - double absSum = sum(absDiff)[0] + _eps; |
| 87 | + Mat src = Mat(channels, channelSize, CV_32F, (void*)inp0.ptr<float>(n)); |
| 88 | + Mat dst = Mat(channels, channelSize, CV_32F, (void*)outputs[0].ptr<float>(n)); |
179 | 89 |
|
180 |
| - float norm = sqrt(absSum); |
181 |
| - dst = src / norm; |
182 |
| - } |
183 |
| - else |
184 |
| - { |
185 |
| - Mat norm(channelSize, 1, buffer.type()); // 1 x channelSize |
186 |
| - |
187 |
| - // (_channels x channelSize)T * _channels x 1 -> channelSize x 1 |
188 |
| - gemm(buffer, sumChannelMultiplier, 1, norm, 0, norm, GEMM_1_T); |
| 90 | + cv::pow(abs(src), pnorm, buffer); |
189 | 91 |
|
190 |
| - // compute norm |
191 |
| - pow(norm, 0.5f, norm); |
| 92 | + if (acrossSpatial) |
| 93 | + { |
| 94 | + // add eps to avoid overflow |
| 95 | + float absSum = sum(buffer)[0] + epsilon; |
| 96 | + float norm = pow(absSum, 1.0f / pnorm); |
| 97 | + multiply(src, 1.0f / norm, dst); |
| 98 | + } |
| 99 | + else |
| 100 | + { |
| 101 | + Mat norm; |
| 102 | + reduce(buffer, norm, 0, REDUCE_SUM); |
| 103 | + norm += epsilon; |
192 | 104 |
|
193 |
| - // scale the layer |
194 |
| - // _channels x 1 * (channelSize x 1)T -> _channels x channelSize |
195 |
| - gemm(sumChannelMultiplier, norm, 1, buffer, 0, buffer, GEMM_2_T); |
| 105 | + // compute inverted norm to call multiply instead divide |
| 106 | + cv::pow(norm, -1.0f / pnorm, norm); |
196 | 107 |
|
197 |
| - dst = src / buffer; |
198 |
| - } |
| 108 | + repeat(norm, channels, 1, buffer); |
| 109 | + multiply(src, buffer, dst); |
| 110 | + } |
199 | 111 |
|
| 112 | + if (!blobs.empty()) |
| 113 | + { |
200 | 114 | // scale the output
|
201 |
| - if (_channel_shared) |
| 115 | + Mat scale = blobs[0]; |
| 116 | + if (scale.total() == 1) |
202 | 117 | {
|
203 | 118 | // _scale: 1 x 1
|
204 | 119 | dst *= scale.at<float>(0, 0);
|
205 | 120 | }
|
206 | 121 | else
|
207 | 122 | {
|
208 | 123 | // _scale: _channels x 1
|
209 |
| - // _channels x 1 * 1 x channelSize -> _channels x channelSize |
210 |
| - gemm(scale, sumSpatialMultiplier, 1, buffer, 0, buffer); |
211 |
| - |
212 |
| - dst = dst.mul(buffer); |
| 124 | + CV_Assert(scale.total() == channels); |
| 125 | + repeat(scale, 1, dst.cols, buffer); |
| 126 | + multiply(dst, buffer, dst); |
213 | 127 | }
|
214 | 128 | }
|
215 | 129 | }
|
216 | 130 | }
|
217 |
| - |
218 | 131 | };
|
219 | 132 |
|
220 | 133 |
|
|
0 commit comments