|
|
|
@ -2,7 +2,7 @@ |
|
|
|
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
|
|
|
|
// of this distribution and at http://opencv.org/license.html.
|
|
|
|
|
|
|
|
|
|
// Copyright (C) 2016, Intel Corporation, all rights reserved.
|
|
|
|
|
// Copyright (C) 2017, Intel Corporation, all rights reserved.
|
|
|
|
|
// Third party copyrights are property of their respective owners.
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -24,14 +24,20 @@ public: |
|
|
|
|
PaddingLayerImpl(const LayerParams ¶ms) |
|
|
|
|
{ |
|
|
|
|
setParamsFrom(params); |
|
|
|
|
paddingDim = params.get<int>("padding_dim"); |
|
|
|
|
padding = params.get<int>("padding"); |
|
|
|
|
inputDims = params.get<int>("input_dims", 0); |
|
|
|
|
index = params.get<int>("index", 0); |
|
|
|
|
paddingValue = params.get<double>("value", 0); |
|
|
|
|
|
|
|
|
|
if(paddingDim < 0 || padding < 0) |
|
|
|
|
CV_Error(cv::Error::StsNotImplemented, "Negative padding and dim aren't supported"); |
|
|
|
|
paddingValue = params.get<float>("value", 0); |
|
|
|
|
inputDims = params.get<int>("input_dims", -1); |
|
|
|
|
|
|
|
|
|
CV_Assert(params.has("paddings")); |
|
|
|
|
const DictValue& paddingsParam = params.get("paddings"); |
|
|
|
|
CV_Assert((paddingsParam.size() & 1) == 0); |
|
|
|
|
|
|
|
|
|
paddings.resize(paddingsParam.size() / 2); |
|
|
|
|
for (int i = 0; i < paddings.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
paddings[i].first = paddingsParam.get<int>(i * 2); // Pad before.
|
|
|
|
|
paddings[i].second = paddingsParam.get<int>(i * 2 + 1); // Pad after.
|
|
|
|
|
CV_Assert(paddings[i].first >= 0, paddings[i].second >= 0); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool getMemoryShapes(const std::vector<MatShape> &inputs, |
|
|
|
@ -39,24 +45,48 @@ public: |
|
|
|
|
std::vector<MatShape> &outputs, |
|
|
|
|
std::vector<MatShape> &internals) const |
|
|
|
|
{ |
|
|
|
|
outputs.clear(); |
|
|
|
|
for(int i = 0; i < inputs.size(); i++) |
|
|
|
|
CV_Assert(inputs.size() == 1); |
|
|
|
|
const MatShape& inpShape = inputs[0]; |
|
|
|
|
CV_Assert(inpShape.size() >= paddings.size()); |
|
|
|
|
CV_Assert(inputDims == -1 || inpShape.size() == inputDims || inpShape.size() > paddings.size()); |
|
|
|
|
|
|
|
|
|
outputs.resize(1, inpShape); |
|
|
|
|
int offset = (inputDims == -1 ? 0 : (inpShape.size() > inputDims ? 1 : 0)); |
|
|
|
|
for (int i = 0; i < paddings.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
MatShape shape = inputs[i]; |
|
|
|
|
int dim = getPadDim(shape); |
|
|
|
|
CV_Assert(dim < shape.size()); |
|
|
|
|
outputs[0][offset + i] = inpShape[offset + i] + paddings[i].first + paddings[i].second; |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
shape[dim] += padding; |
|
|
|
|
outputs.push_back(shape); |
|
|
|
|
void finalize(const std::vector<Mat*> &inputs, std::vector<Mat> &outputs) |
|
|
|
|
{ |
|
|
|
|
// Compute dstRanges.
|
|
|
|
|
const MatSize& inpShape = inputs[0]->size; |
|
|
|
|
dstRanges.resize(paddings.size()); |
|
|
|
|
|
|
|
|
|
int offset = 0; |
|
|
|
|
if (inputDims != -1 && inputs[0]->dims != inputDims) |
|
|
|
|
{ |
|
|
|
|
dstRanges.insert(dstRanges.begin(), Range::all()); |
|
|
|
|
offset = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
|
for (int i = 0; i < paddings.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
dstRanges[offset + i].start = paddings[i].first; |
|
|
|
|
dstRanges[offset + i].end = paddings[i].first + inpShape[offset + i]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Add the rest of dimensions.
|
|
|
|
|
for (int i = dstRanges.size(); i < inputs[0]->dims; ++i) |
|
|
|
|
dstRanges.push_back(Range::all()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
virtual bool supportBackend(int backendId) |
|
|
|
|
{ |
|
|
|
|
return backendId == DNN_BACKEND_DEFAULT || |
|
|
|
|
backendId == DNN_BACKEND_HALIDE && haveHalide(); |
|
|
|
|
backendId == DNN_BACKEND_HALIDE && haveHalide() && dstRanges.size() == 4; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void forward(std::vector<Mat*> &inputs, std::vector<Mat> &outputs, std::vector<Mat> &internals) |
|
|
|
@ -64,50 +94,18 @@ public: |
|
|
|
|
CV_TRACE_FUNCTION(); |
|
|
|
|
CV_TRACE_ARG_VALUE(name, "name", name.c_str()); |
|
|
|
|
|
|
|
|
|
for(int i = 0; i < inputs.size(); i++) |
|
|
|
|
{ |
|
|
|
|
outputs[i] = paddingValue; |
|
|
|
|
const Mat& inp = *inputs[i]; |
|
|
|
|
Mat& out = outputs[i]; |
|
|
|
|
int dims = inp.dims; |
|
|
|
|
MatShape inShape(inp.size.p, inp.size.p + dims); |
|
|
|
|
MatShape outShape(out.size.p, out.size.p + dims); |
|
|
|
|
int dim = getPadDim(inShape); |
|
|
|
|
|
|
|
|
|
int actualIndex = index; |
|
|
|
|
if(index == 0) |
|
|
|
|
actualIndex = inShape[dim]; |
|
|
|
|
|
|
|
|
|
std::vector<std::pair<Range, Range> > srcDstRanges; |
|
|
|
|
srcDstRanges.push_back(std::make_pair(Range(0, actualIndex), Range(0, actualIndex))); |
|
|
|
|
srcDstRanges.push_back(std::make_pair(Range(actualIndex, inShape[dim]), |
|
|
|
|
Range(actualIndex + padding, outShape[dim]))); |
|
|
|
|
|
|
|
|
|
std::vector<Range> srcRanges(dims, Range::all()), dstRanges = srcRanges; |
|
|
|
|
|
|
|
|
|
for(int j = 0; j < srcDstRanges.size(); j++) |
|
|
|
|
{ |
|
|
|
|
if(!srcDstRanges[j].first.empty()) |
|
|
|
|
{ |
|
|
|
|
srcRanges[dim] = srcDstRanges[j].first; |
|
|
|
|
dstRanges[dim] = srcDstRanges[j].second; |
|
|
|
|
Mat dst = out(&dstRanges[0]); |
|
|
|
|
Mat src = inp(&srcRanges[0]).clone(); |
|
|
|
|
src.copyTo(dst); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int getPadDim(const MatShape& shape) const |
|
|
|
|
{ |
|
|
|
|
return inputDims > 0 && (int)shape.size() > inputDims ? paddingDim + 1 : paddingDim; |
|
|
|
|
outputs[0].setTo(paddingValue); |
|
|
|
|
inputs[0]->copyTo(outputs[0](dstRanges)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
virtual Ptr<BackendNode> initHalide(const std::vector<Ptr<BackendWrapper> > &inputs) |
|
|
|
|
{ |
|
|
|
|
#ifdef HAVE_HALIDE |
|
|
|
|
int inW, inH, inC, inN; |
|
|
|
|
int minN = std::max(dstRanges[0].start, 0); |
|
|
|
|
int minC = std::max(dstRanges[1].start, 0); |
|
|
|
|
int minY = std::max(dstRanges[2].start, 0); |
|
|
|
|
int minX = std::max(dstRanges[3].start, 0); |
|
|
|
|
Halide::Buffer<float> inputBuffer = halideBuffer(inputs[0]); |
|
|
|
|
getCanonicalSize(inputBuffer, &inW, &inH, &inC, &inN); |
|
|
|
|
|
|
|
|
@ -115,13 +113,16 @@ public: |
|
|
|
|
Halide::Func top = (name.empty() ? Halide::Func() : Halide::Func(name)); |
|
|
|
|
Halide::Func padded = |
|
|
|
|
Halide::BoundaryConditions::constant_exterior(inputBuffer, paddingValue); |
|
|
|
|
top(x, y, c, n) = padded(x, y, c, n); |
|
|
|
|
top(x, y, c, n) = padded(x - minX, y - minY, c - minC, n - minN); |
|
|
|
|
return Ptr<BackendNode>(new HalideBackendNode(top)); |
|
|
|
|
#endif // HAVE_HALIDE
|
|
|
|
|
return Ptr<BackendNode>(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int paddingDim, padding, inputDims, index; |
|
|
|
|
private: |
|
|
|
|
std::vector<std::pair<int, int> > paddings; // Pairs pad before, pad after.
|
|
|
|
|
std::vector<Range> dstRanges; |
|
|
|
|
int inputDims; |
|
|
|
|
float paddingValue; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|