Path: blob/master/modules/dnn/src/layers/padding_layer.cpp
16337 views
// This file is part of OpenCV project.1// It is subject to the license terms in the LICENSE file found in the top-level directory2// of this distribution and at http://opencv.org/license.html.34// Copyright (C) 2017, Intel Corporation, all rights reserved.5// Third party copyrights are property of their respective owners.67/*8Implementation of padding layer, which adds paddings to input blob.9*/1011#include "../precomp.hpp"12#include "layers_common.hpp"13#include "../op_halide.hpp"14#include <vector>1516namespace cv17{18namespace dnn19{2021class PaddingLayerImpl CV_FINAL : public PaddingLayer22{23public:24PaddingLayerImpl(const LayerParams ¶ms)25{26setParamsFrom(params);27paddingValue = params.get<float>("value", 0);28inputDims = params.get<int>("input_dims", -1);29paddingType = params.get<String>("type", "constant");3031CV_Assert(params.has("paddings"));32const DictValue& paddingsParam = params.get("paddings");33CV_Assert((paddingsParam.size() & 1) == 0);3435paddings.resize(paddingsParam.size() / 2);36for (int i = 0; i < paddings.size(); ++i)37{38paddings[i].first = paddingsParam.get<int>(i * 2); // Pad before.39paddings[i].second = paddingsParam.get<int>(i * 2 + 1); // Pad after.40CV_Assert_N(paddings[i].first >= 0, paddings[i].second >= 0);41}42}4344bool getMemoryShapes(const std::vector<MatShape> &inputs,45const int requiredOutputs,46std::vector<MatShape> &outputs,47std::vector<MatShape> &internals) const CV_OVERRIDE48{49CV_Assert(inputs.size() == 1);50const MatShape& inpShape = inputs[0];51CV_Assert(inpShape.size() >= paddings.size());52CV_Assert(inputDims == -1 || inpShape.size() == inputDims || inpShape.size() > paddings.size());5354outputs.resize(1, inpShape);55int offset = (inputDims == -1 ? 0 : (inpShape.size() > inputDims ? 1 : 0));56for (int i = 0; i < paddings.size(); ++i)57{58outputs[0][offset + i] = inpShape[offset + i] + paddings[i].first + paddings[i].second;59}60return false;61}6263void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays) CV_OVERRIDE64{65std::vector<Mat> inputs;66inputs_arr.getMatVector(inputs);6768// Compute dstRanges.69const MatSize& inpShape = inputs[0].size;70dstRanges.resize(paddings.size());7172int offset = 0;73if (inputDims != -1 && inputs[0].dims != inputDims)74{75dstRanges.insert(dstRanges.begin(), Range::all());76offset = 1;77}7879for (int i = 0; i < paddings.size(); ++i)80{81dstRanges[offset + i].start = paddings[i].first;82dstRanges[offset + i].end = paddings[i].first + inpShape[offset + i];83}8485// Add the rest of dimensions.86for (int i = dstRanges.size(); i < inputs[0].dims; ++i)87dstRanges.push_back(Range::all());88}8990virtual bool supportBackend(int backendId) CV_OVERRIDE91{92return backendId == DNN_BACKEND_OPENCV ||93backendId == DNN_BACKEND_HALIDE && haveHalide() && dstRanges.size() == 4;94}9596void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE97{98CV_TRACE_FUNCTION();99CV_TRACE_ARG_VALUE(name, "name", name.c_str());100101std::vector<Mat> inputs, outputs;102inputs_arr.getMatVector(inputs);103outputs_arr.getMatVector(outputs);104105if (paddingType == "constant")106{107if (inputs_arr.depth() == CV_16S)108{109std::vector<float> paddingValue_fp32(1, paddingValue);110std::vector<int16_t> paddingValue_fp16(1);111convertFp16(paddingValue_fp32, paddingValue_fp16);112outputs[0].setTo(paddingValue_fp16[0]);113}114else115outputs[0].setTo(paddingValue);116inputs[0].copyTo(outputs[0](dstRanges));117}118else if (paddingType == "reflect")119{120CV_Assert(inputs.size() == 1);121CV_Assert(outputs.size() == 1);122CV_Assert(inputs[0].dims == 4);123CV_Assert(outputs[0].dims == 4);124125if (inputs[0].size[0] != outputs[0].size[0] || inputs[0].size[1] != outputs[0].size[1])126CV_Error(Error::StsNotImplemented, "Only spatial reflection padding is supported.");127128const int inpHeight = inputs[0].size[2];129const int inpWidth = inputs[0].size[3];130const int outHeight = outputs[0].size[2];131const int outWidth = outputs[0].size[3];132const int padTop = dstRanges[2].start;133const int padBottom = outHeight - dstRanges[2].end;134const int padLeft = dstRanges[3].start;135const int padRight = outWidth - dstRanges[3].end;136CV_CheckLT(padTop, inpHeight, ""); CV_CheckLT(padBottom, inpHeight, "");137CV_CheckLT(padLeft, inpWidth, ""); CV_CheckLT(padRight, inpWidth, "");138139for (size_t n = 0; n < inputs[0].size[0]; ++n)140{141for (size_t ch = 0; ch < inputs[0].size[1]; ++ch)142{143copyMakeBorder(getPlane(inputs[0], n, ch),144getPlane(outputs[0], n, ch),145padTop, padBottom, padLeft, padRight,146BORDER_REFLECT_101);147}148}149}150else151CV_Error(Error::StsNotImplemented, "Unknown padding type: " + paddingType);152}153154virtual Ptr<BackendNode> initHalide(const std::vector<Ptr<BackendWrapper> > &inputs) CV_OVERRIDE155{156#ifdef HAVE_HALIDE157int inW, inH, inC, inN;158int minN = std::max(dstRanges[0].start, 0);159int minC = std::max(dstRanges[1].start, 0);160int minY = std::max(dstRanges[2].start, 0);161int minX = std::max(dstRanges[3].start, 0);162Halide::Buffer<float> inputBuffer = halideBuffer(inputs[0]);163getCanonicalSize(inputBuffer, &inW, &inH, &inC, &inN);164165Halide::Var x("x"), y("y"), c("c"), n("n");166Halide::Func top = (name.empty() ? Halide::Func() : Halide::Func(name));167Halide::Func padded =168Halide::BoundaryConditions::constant_exterior(inputBuffer, paddingValue);169top(x, y, c, n) = padded(x - minX, y - minY, c - minC, n - minN);170return Ptr<BackendNode>(new HalideBackendNode(top));171#endif // HAVE_HALIDE172return Ptr<BackendNode>();173}174175private:176std::vector<std::pair<int, int> > paddings; // Pairs pad before, pad after.177std::vector<Range> dstRanges;178int inputDims;179float paddingValue;180std::string paddingType;181};182183Ptr<PaddingLayer> PaddingLayer::create(const LayerParams ¶ms)184{185return Ptr<PaddingLayer>(new PaddingLayerImpl(params));186}187188}189}190191192