Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/samples/dnn/custom_layers.hpp
16337 views
1
#ifndef __OPENCV_SAMPLES_DNN_CUSTOM_LAYERS__
2
#define __OPENCV_SAMPLES_DNN_CUSTOM_LAYERS__
3
4
#include <opencv2/dnn.hpp>
5
#include <opencv2/dnn/shape_utils.hpp> // getPlane
6
7
//! [InterpLayer]
8
class InterpLayer : public cv::dnn::Layer
9
{
10
public:
11
InterpLayer(const cv::dnn::LayerParams &params) : Layer(params)
12
{
13
outWidth = params.get<int>("width", 0);
14
outHeight = params.get<int>("height", 0);
15
}
16
17
static cv::Ptr<cv::dnn::Layer> create(cv::dnn::LayerParams& params)
18
{
19
return cv::Ptr<cv::dnn::Layer>(new InterpLayer(params));
20
}
21
22
virtual bool getMemoryShapes(const std::vector<std::vector<int> > &inputs,
23
const int requiredOutputs,
24
std::vector<std::vector<int> > &outputs,
25
std::vector<std::vector<int> > &internals) const CV_OVERRIDE
26
{
27
CV_UNUSED(requiredOutputs); CV_UNUSED(internals);
28
std::vector<int> outShape(4);
29
outShape[0] = inputs[0][0]; // batch size
30
outShape[1] = inputs[0][1]; // number of channels
31
outShape[2] = outHeight;
32
outShape[3] = outWidth;
33
outputs.assign(1, outShape);
34
return false;
35
}
36
37
// Implementation of this custom layer is based on https://github.com/cdmh/deeplab-public/blob/master/src/caffe/layers/interp_layer.cpp
38
virtual void forward(cv::InputArrayOfArrays inputs_arr,
39
cv::OutputArrayOfArrays outputs_arr,
40
cv::OutputArrayOfArrays internals_arr) CV_OVERRIDE
41
{
42
if (inputs_arr.depth() == CV_16S)
43
{
44
// In case of DNN_TARGET_OPENCL_FP16 target the following method
45
// converts data from FP16 to FP32 and calls this forward again.
46
forward_fallback(inputs_arr, outputs_arr, internals_arr);
47
return;
48
}
49
50
std::vector<cv::Mat> inputs, outputs;
51
inputs_arr.getMatVector(inputs);
52
outputs_arr.getMatVector(outputs);
53
54
cv::Mat& inp = inputs[0];
55
cv::Mat& out = outputs[0];
56
const float* inpData = (float*)inp.data;
57
float* outData = (float*)out.data;
58
59
const int batchSize = inp.size[0];
60
const int numChannels = inp.size[1];
61
const int inpHeight = inp.size[2];
62
const int inpWidth = inp.size[3];
63
64
const float rheight = (outHeight > 1) ? static_cast<float>(inpHeight - 1) / (outHeight - 1) : 0.f;
65
const float rwidth = (outWidth > 1) ? static_cast<float>(inpWidth - 1) / (outWidth - 1) : 0.f;
66
for (int h2 = 0; h2 < outHeight; ++h2)
67
{
68
const float h1r = rheight * h2;
69
const int h1 = static_cast<int>(h1r);
70
const int h1p = (h1 < inpHeight - 1) ? 1 : 0;
71
const float h1lambda = h1r - h1;
72
const float h0lambda = 1.f - h1lambda;
73
for (int w2 = 0; w2 < outWidth; ++w2)
74
{
75
const float w1r = rwidth * w2;
76
const int w1 = static_cast<int>(w1r);
77
const int w1p = (w1 < inpWidth - 1) ? 1 : 0;
78
const float w1lambda = w1r - w1;
79
const float w0lambda = 1.f - w1lambda;
80
const float* pos1 = inpData + h1 * inpWidth + w1;
81
float* pos2 = outData + h2 * outWidth + w2;
82
for (int c = 0; c < batchSize * numChannels; ++c)
83
{
84
pos2[0] =
85
h0lambda * (w0lambda * pos1[0] + w1lambda * pos1[w1p]) +
86
h1lambda * (w0lambda * pos1[h1p * inpWidth] + w1lambda * pos1[h1p * inpWidth + w1p]);
87
pos1 += inpWidth * inpHeight;
88
pos2 += outWidth * outHeight;
89
}
90
}
91
}
92
}
93
94
private:
95
int outWidth, outHeight;
96
};
97
//! [InterpLayer]
98
99
//! [ResizeBilinearLayer]
100
class ResizeBilinearLayer CV_FINAL : public cv::dnn::Layer
101
{
102
public:
103
ResizeBilinearLayer(const cv::dnn::LayerParams &params) : Layer(params)
104
{
105
CV_Assert(!params.get<bool>("align_corners", false));
106
CV_Assert(!blobs.empty());
107
108
for (size_t i = 0; i < blobs.size(); ++i)
109
CV_Assert(blobs[i].type() == CV_32SC1);
110
111
// There are two cases of input blob: a single blob which contains output
112
// shape and two blobs with scaling factors.
113
if (blobs.size() == 1)
114
{
115
CV_Assert(blobs[0].total() == 2);
116
outHeight = blobs[0].at<int>(0, 0);
117
outWidth = blobs[0].at<int>(0, 1);
118
factorHeight = factorWidth = 0;
119
}
120
else
121
{
122
CV_Assert(blobs.size() == 2); CV_Assert(blobs[0].total() == 1); CV_Assert(blobs[1].total() == 1);
123
factorHeight = blobs[0].at<int>(0, 0);
124
factorWidth = blobs[1].at<int>(0, 0);
125
outHeight = outWidth = 0;
126
}
127
}
128
129
static cv::Ptr<cv::dnn::Layer> create(cv::dnn::LayerParams& params)
130
{
131
return cv::Ptr<cv::dnn::Layer>(new ResizeBilinearLayer(params));
132
}
133
134
virtual bool getMemoryShapes(const std::vector<std::vector<int> > &inputs,
135
const int,
136
std::vector<std::vector<int> > &outputs,
137
std::vector<std::vector<int> > &) const CV_OVERRIDE
138
{
139
std::vector<int> outShape(4);
140
outShape[0] = inputs[0][0]; // batch size
141
outShape[1] = inputs[0][1]; // number of channels
142
outShape[2] = outHeight != 0 ? outHeight : (inputs[0][2] * factorHeight);
143
outShape[3] = outWidth != 0 ? outWidth : (inputs[0][3] * factorWidth);
144
outputs.assign(1, outShape);
145
return false;
146
}
147
148
virtual void finalize(cv::InputArrayOfArrays, cv::OutputArrayOfArrays outputs_arr) CV_OVERRIDE
149
{
150
std::vector<cv::Mat> outputs;
151
outputs_arr.getMatVector(outputs);
152
if (!outWidth && !outHeight)
153
{
154
outHeight = outputs[0].size[2];
155
outWidth = outputs[0].size[3];
156
}
157
}
158
159
// This implementation is based on a reference implementation from
160
// https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/lite/kernels/internal/reference/reference_ops.h
161
virtual void forward(cv::InputArrayOfArrays inputs_arr,
162
cv::OutputArrayOfArrays outputs_arr,
163
cv::OutputArrayOfArrays internals_arr) CV_OVERRIDE
164
{
165
if (inputs_arr.depth() == CV_16S)
166
{
167
// In case of DNN_TARGET_OPENCL_FP16 target the following method
168
// converts data from FP16 to FP32 and calls this forward again.
169
forward_fallback(inputs_arr, outputs_arr, internals_arr);
170
return;
171
}
172
173
std::vector<cv::Mat> inputs, outputs;
174
inputs_arr.getMatVector(inputs);
175
outputs_arr.getMatVector(outputs);
176
177
cv::Mat& inp = inputs[0];
178
cv::Mat& out = outputs[0];
179
const float* inpData = (float*)inp.data;
180
float* outData = (float*)out.data;
181
182
const int batchSize = inp.size[0];
183
const int numChannels = inp.size[1];
184
const int inpHeight = inp.size[2];
185
const int inpWidth = inp.size[3];
186
187
float heightScale = static_cast<float>(inpHeight) / outHeight;
188
float widthScale = static_cast<float>(inpWidth) / outWidth;
189
for (int b = 0; b < batchSize; ++b)
190
{
191
for (int y = 0; y < outHeight; ++y)
192
{
193
float input_y = y * heightScale;
194
int y0 = static_cast<int>(std::floor(input_y));
195
int y1 = std::min(y0 + 1, inpHeight - 1);
196
for (int x = 0; x < outWidth; ++x)
197
{
198
float input_x = x * widthScale;
199
int x0 = static_cast<int>(std::floor(input_x));
200
int x1 = std::min(x0 + 1, inpWidth - 1);
201
for (int c = 0; c < numChannels; ++c)
202
{
203
float interpolation =
204
inpData[offset(inp.size, c, x0, y0, b)] * (1 - (input_y - y0)) * (1 - (input_x - x0)) +
205
inpData[offset(inp.size, c, x0, y1, b)] * (input_y - y0) * (1 - (input_x - x0)) +
206
inpData[offset(inp.size, c, x1, y0, b)] * (1 - (input_y - y0)) * (input_x - x0) +
207
inpData[offset(inp.size, c, x1, y1, b)] * (input_y - y0) * (input_x - x0);
208
outData[offset(out.size, c, x, y, b)] = interpolation;
209
}
210
}
211
}
212
}
213
}
214
215
private:
216
static inline int offset(const cv::MatSize& size, int c, int x, int y, int b)
217
{
218
return x + size[3] * (y + size[2] * (c + size[1] * b));
219
}
220
221
int outWidth, outHeight, factorWidth, factorHeight;
222
};
223
//! [ResizeBilinearLayer]
224
225
//
226
// The following code is used only to generate tutorials documentation.
227
//
228
229
//! [A custom layer interface]
230
class MyLayer : public cv::dnn::Layer
231
{
232
public:
233
//! [MyLayer::MyLayer]
234
MyLayer(const cv::dnn::LayerParams &params);
235
//! [MyLayer::MyLayer]
236
237
//! [MyLayer::create]
238
static cv::Ptr<cv::dnn::Layer> create(cv::dnn::LayerParams& params);
239
//! [MyLayer::create]
240
241
//! [MyLayer::getMemoryShapes]
242
virtual bool getMemoryShapes(const std::vector<std::vector<int> > &inputs,
243
const int requiredOutputs,
244
std::vector<std::vector<int> > &outputs,
245
std::vector<std::vector<int> > &internals) const CV_OVERRIDE;
246
//! [MyLayer::getMemoryShapes]
247
248
//! [MyLayer::forward]
249
virtual void forward(cv::InputArrayOfArrays inputs,
250
cv::OutputArrayOfArrays outputs,
251
cv::OutputArrayOfArrays internals) CV_OVERRIDE;
252
//! [MyLayer::forward]
253
254
//! [MyLayer::finalize]
255
virtual void finalize(cv::InputArrayOfArrays inputs,
256
cv::OutputArrayOfArrays outputs) CV_OVERRIDE;
257
//! [MyLayer::finalize]
258
};
259
//! [A custom layer interface]
260
261
//! [Register a custom layer]
262
#include <opencv2/dnn/layer.details.hpp> // CV_DNN_REGISTER_LAYER_CLASS
263
264
static inline void loadNet()
265
{
266
CV_DNN_REGISTER_LAYER_CLASS(Interp, InterpLayer);
267
// ...
268
//! [Register a custom layer]
269
270
//! [Register InterpLayer]
271
CV_DNN_REGISTER_LAYER_CLASS(Interp, InterpLayer);
272
cv::dnn::Net caffeNet = cv::dnn::readNet("/path/to/config.prototxt", "/path/to/weights.caffemodel");
273
//! [Register InterpLayer]
274
275
//! [Register ResizeBilinearLayer]
276
CV_DNN_REGISTER_LAYER_CLASS(ResizeBilinear, ResizeBilinearLayer);
277
cv::dnn::Net tfNet = cv::dnn::readNet("/path/to/graph.pb");
278
//! [Register ResizeBilinearLayer]
279
280
if (false) loadNet(); // To prevent unused function warning.
281
}
282
283
#endif // __OPENCV_SAMPLES_DNN_CUSTOM_LAYERS__
284
285