Merge pull request #11620 from terfendail:hmmorph_fix
[platform/upstream/opencv.git] / modules / dnn / src / layers / max_unpooling_layer.cpp
1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4
5 // Copyright (C) 2016, Intel Corporation, all rights reserved.
6 // Third party copyrights are property of their respective owners.
7
8 /*
9 Implementation of Batch Normalization layer.
10 */
11
12 #include "../precomp.hpp"
13 #include "layers_common.hpp"
14 #include "../op_halide.hpp"
15 #include <opencv2/dnn/shape_utils.hpp>
16
17 #include <iostream>
18
19 namespace cv
20 {
21 namespace dnn
22 {
23
24 class MaxUnpoolLayerImpl CV_FINAL : public MaxUnpoolLayer
25 {
26 public:
27     MaxUnpoolLayerImpl(const LayerParams& params)
28     {
29         setParamsFrom(params);
30         poolKernel = Size(params.get<int>("pool_k_w"), params.get<int>("pool_k_h"));
31         poolPad = Size(params.get<int>("pool_pad_w"), params.get<int>("pool_pad_h"));
32         poolStride = Size(params.get<int>("pool_stride_w"), params.get<int>("pool_stride_h"));
33     }
34
35     virtual bool supportBackend(int backendId) CV_OVERRIDE
36     {
37         return backendId == DNN_BACKEND_OPENCV ||
38                backendId == DNN_BACKEND_HALIDE && haveHalide() &&
39                !poolPad.width && !poolPad.height;
40     }
41
42     bool getMemoryShapes(const std::vector<MatShape> &inputs,
43                          const int requiredOutputs,
44                          std::vector<MatShape> &outputs,
45                          std::vector<MatShape> &internals) const CV_OVERRIDE
46     {
47         CV_Assert(inputs.size() == 2);
48         CV_Assert(total(inputs[0]) == total(inputs[1]));
49
50         MatShape outShape = inputs[0];
51         outShape[2] = (outShape[2] - 1) * poolStride.height + poolKernel.height - 2 * poolPad.height;
52         outShape[3] = (outShape[3] - 1) * poolStride.width + poolKernel.width - 2 * poolPad.width;
53
54         outputs.clear();
55         outputs.push_back(outShape);
56
57         return false;
58     }
59
60     void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE
61     {
62         CV_TRACE_FUNCTION();
63         CV_TRACE_ARG_VALUE(name, "name", name.c_str());
64
65         Layer::forward_fallback(inputs_arr, outputs_arr, internals_arr);
66     }
67
68     void forward(std::vector<Mat*> &inputs, std::vector<Mat> &outputs, std::vector<Mat> &internals) CV_OVERRIDE
69     {
70         CV_TRACE_FUNCTION();
71         CV_TRACE_ARG_VALUE(name, "name", name.c_str());
72
73         CV_Assert(inputs.size() == 2);
74         Mat& input = *inputs[0];
75         Mat& indices = *inputs[1];
76
77         CV_Assert(input.total() == indices.total());
78         CV_Assert(input.size[0] == 1);
79         CV_Assert(input.isContinuous());
80
81         for(int i_n = 0; i_n < outputs.size(); i_n++)
82         {
83             Mat& outBlob = outputs[i_n];
84             outBlob.setTo(0);
85             CV_Assert(input.size[1] == outBlob.size[1]);
86             int outPlaneTotal = outBlob.size[2]*outBlob.size[3];
87
88             for (int i_c = 0; i_c < input.size[1]; i_c++)
89             {
90                 Mat outPlane = getPlane(outBlob, 0, i_c);
91                 int wh_area = input.size[2]*input.size[3];
92                 const float* inptr = input.ptr<float>(0, i_c);
93                 const float* idxptr = indices.ptr<float>(0, i_c);
94                 float* outptr = outPlane.ptr<float>();
95
96                 for(int i_wh = 0; i_wh < wh_area; i_wh++)
97                 {
98                     int index = idxptr[i_wh];
99                     if (!(0 <= index && index < outPlaneTotal))
100                     {
101                         std::cerr
102                             << "i_n=" << i_n << std::endl
103                             << "i_c=" << i_c << std::endl
104                             << "i_wh=" << i_wh << std::endl
105                             << "index=" << index << std::endl
106                             << "maxval=" << inptr[i_wh] << std::endl
107                             << "outPlaneTotal=" << outPlaneTotal << std::endl
108                             << "input.size=" << input.size << std::endl
109                             << "indices.size=" << indices.size << std::endl
110                             << "outBlob=" << outBlob.size << std::endl
111                             ;
112                         CV_Assert(0 <= index && index < outPlaneTotal);
113                     }
114                     outptr[index] = inptr[i_wh];
115                 }
116             }
117         }
118     }
119
120     virtual Ptr<BackendNode> initHalide(const std::vector<Ptr<BackendWrapper> > &input) CV_OVERRIDE
121     {
122 #ifdef HAVE_HALIDE
123         // Meaningless operation if false because if kernel > stride
124         // it is not deterministic and if kernel < stride we just
125         // skip a part of input data (you'd better change your model).
126         if (poolKernel.width != poolStride.width ||
127             poolKernel.height != poolStride.height)
128             CV_Error(cv::Error::StsNotImplemented,
129                      "Halide backend for maximum unpooling "
130                      "is not support cases when kernel != stride");
131
132         Halide::Var x("x"), y("y"), c("c"), n("n");
133         Halide::Func top = (name.empty() ? Halide::Func() : Halide::Func(name));
134         Halide::Buffer<float> inputBuffer = halideBuffer(input[0]);
135         Halide::Buffer<float> indices = halideBuffer(input[1]);
136
137         Halide::Expr pooledX = x / poolKernel.width;
138         Halide::Expr pooledY = y / poolKernel.height;
139
140         const int outW = inputBuffer.width() * poolKernel.width;
141         top(x, y, c, n) = select(y * outW + x == indices(pooledX, pooledY, c, n),
142                                  inputBuffer(pooledX, pooledY, c, n), 0.0f);
143         return Ptr<BackendNode>(new HalideBackendNode(top));
144 #endif  // HAVE_HALIDE
145         return Ptr<BackendNode>();
146     }
147 };
148
149 Ptr<MaxUnpoolLayer> MaxUnpoolLayer::create(const LayerParams& params)
150 {
151     return Ptr<MaxUnpoolLayer>(new MaxUnpoolLayerImpl(params));
152 }
153
154 }
155 }