Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
310 lines
11 KiB
310 lines
11 KiB
/*M/////////////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. |
|
// |
|
// By downloading, copying, installing or using the software you agree to this license. |
|
// If you do not agree to this license, do not download, install, |
|
// copy or use the software. |
|
// |
|
// |
|
// License Agreement |
|
// For Open Source Computer Vision Library |
|
// |
|
// Copyright (C) 2013, OpenCV Foundation, all rights reserved. |
|
// Copyright (C) 2017, Intel Corporation, all rights reserved. |
|
// Third party copyrights are property of their respective owners. |
|
// |
|
// Redistribution and use in source and binary forms, with or without modification, |
|
// are permitted provided that the following conditions are met: |
|
// |
|
// * Redistribution's of source code must retain the above copyright notice, |
|
// this list of conditions and the following disclaimer. |
|
// |
|
// * Redistribution's in binary form must reproduce the above copyright notice, |
|
// this list of conditions and the following disclaimer in the documentation |
|
// and/or other materials provided with the distribution. |
|
// |
|
// * The name of the copyright holders may not be used to endorse or promote products |
|
// derived from this software without specific prior written permission. |
|
// |
|
// This software is provided by the copyright holders and contributors "as is" and |
|
// any express or implied warranties, including, but not limited to, the implied |
|
// warranties of merchantability and fitness for a particular purpose are disclaimed. |
|
// In no event shall the Intel Corporation or contributors be liable for any direct, |
|
// indirect, incidental, special, exemplary, or consequential damages |
|
// (including, but not limited to, procurement of substitute goods or services; |
|
// loss of use, data, or profits; or business interruption) however caused |
|
// and on any theory of liability, whether in contract, strict liability, |
|
// or tort (including negligence or otherwise) arising in any way out of |
|
// the use of this software, even if advised of the possibility of such damage. |
|
// |
|
//M*/ |
|
|
|
#include "../precomp.hpp" |
|
#include "../op_inf_engine.hpp" |
|
#include "layers_common.hpp" |
|
#include <opencv2/dnn/shape_utils.hpp> |
|
|
|
#ifdef HAVE_OPENCL |
|
#include "opencl_kernels_dnn.hpp" |
|
#endif |
|
|
|
namespace cv |
|
{ |
|
namespace dnn |
|
{ |
|
|
|
class SliceLayerImpl CV_FINAL : public SliceLayer |
|
{ |
|
public: |
|
SliceLayerImpl(const LayerParams& params) |
|
{ |
|
setParamsFrom(params); |
|
axis = params.get<int>("axis", 1); |
|
if (params.has("slice_point")) |
|
{ |
|
CV_Assert(!params.has("begin") && !params.has("size") && !params.has("end")); |
|
const DictValue &indicesValue = params.get("slice_point"); |
|
sliceRanges.resize(indicesValue.size() + 1, |
|
std::vector<Range>(axis + 1, Range::all())); |
|
int prevSlice = 0; |
|
for (int i = 0; i < indicesValue.size(); ++i) |
|
{ |
|
sliceRanges[i][axis].start = prevSlice; |
|
sliceRanges[i][axis].end = indicesValue.get<int>(i); |
|
prevSlice = sliceRanges[i][axis].end; |
|
} |
|
sliceRanges.back()[axis].start = prevSlice; |
|
} |
|
else if (params.has("begin")) |
|
{ |
|
CV_Assert(params.has("size") ^ params.has("end")); |
|
const DictValue &begins = params.get("begin"); |
|
const DictValue &sizesOrEnds = params.has("size") ? params.get("size") : params.get("end"); |
|
CV_Assert(begins.size() == sizesOrEnds.size()); |
|
|
|
sliceRanges.resize(1); |
|
sliceRanges[0].resize(begins.size(), Range::all()); |
|
for (int i = 0; i < begins.size(); ++i) |
|
{ |
|
int start = begins.get<int>(i); |
|
int sizeOrEnd = sizesOrEnds.get<int>(i); // It may be negative to reverse indexation. |
|
CV_Assert(start >= 0); |
|
|
|
sliceRanges[0][i].start = start; |
|
if (params.has("size")) |
|
{ |
|
int size = sizeOrEnd; |
|
CV_Assert(size == -1 || size > 0); // -1 value means range [start, axis_size). |
|
sliceRanges[0][i].end = size > 0 ? (start + size) : -1; // We'll finalize a negative value later. |
|
} |
|
else |
|
{ |
|
int end = sizeOrEnd; |
|
CV_Assert(end < 0 || end > start); // End index is excluded. |
|
sliceRanges[0][i].end = end; // We'll finalize a negative value later. |
|
} |
|
} |
|
} |
|
} |
|
|
|
virtual bool supportBackend(int backendId) CV_OVERRIDE |
|
{ |
|
#ifdef HAVE_INF_ENGINE |
|
if (backendId == DNN_BACKEND_INFERENCE_ENGINE) |
|
{ |
|
return INF_ENGINE_VER_MAJOR_LT(INF_ENGINE_RELEASE_2018R5) && |
|
sliceRanges.size() == 1 && sliceRanges[0].size() == 4; |
|
} |
|
else |
|
#endif |
|
return backendId == DNN_BACKEND_OPENCV; |
|
} |
|
|
|
bool getMemoryShapes(const std::vector<MatShape> &inputs, |
|
const int requiredOutputs, |
|
std::vector<MatShape> &outputs, |
|
std::vector<MatShape> &internals) const CV_OVERRIDE |
|
{ |
|
CV_Assert(inputs.size() == 1); |
|
MatShape inpShape = inputs[0]; |
|
|
|
if (!sliceRanges.empty()) |
|
{ |
|
outputs.resize(sliceRanges.size(), inpShape); |
|
for (int i = 0; i < outputs.size(); ++i) |
|
{ |
|
CV_Assert(sliceRanges[i].size() <= inpShape.size()); |
|
for (int j = 0; j < sliceRanges[i].size(); ++j) |
|
{ |
|
outputs[i][j] = clamp(sliceRanges[i][j], inpShape[j]).size(); |
|
} |
|
} |
|
} |
|
else // Divide input blob on equal parts by axis. |
|
{ |
|
CV_Assert(0 <= axis && axis < inpShape.size()); |
|
CV_Assert(requiredOutputs > 0 && inpShape[axis] % requiredOutputs == 0); |
|
inpShape[axis] /= requiredOutputs; |
|
outputs.resize(requiredOutputs, inpShape); |
|
} |
|
return false; |
|
} |
|
|
|
void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr) CV_OVERRIDE |
|
{ |
|
std::vector<Mat> inputs, outputs; |
|
inputs_arr.getMatVector(inputs); |
|
outputs_arr.getMatVector(outputs); |
|
|
|
CV_Assert(inputs.size() == 1); |
|
const MatSize& inpShape = inputs[0].size; |
|
|
|
if (sliceRanges.empty()) |
|
{ |
|
// Divide input blob on equal parts by axis. |
|
int outAxisSize = inpShape[axis] / outputs.size(); |
|
sliceRanges.resize(outputs.size(), |
|
std::vector<Range>(axis + 1, Range::all())); |
|
int prevSlice = 0; |
|
for (int i = 0; i < outputs.size(); ++i) |
|
{ |
|
sliceRanges[i][axis].start = prevSlice; |
|
sliceRanges[i][axis].end = sliceRanges[i][axis].start + outAxisSize; |
|
prevSlice = sliceRanges[i][axis].end; |
|
} |
|
} |
|
else |
|
CV_Assert(outputs.size() == sliceRanges.size()); |
|
|
|
for (int i = 0; i < outputs.size(); ++i) |
|
{ |
|
CV_Assert(sliceRanges[i].size() <= inpShape.dims()); |
|
// Clamp. |
|
for (int j = 0; j < sliceRanges[i].size(); ++j) |
|
{ |
|
sliceRanges[i][j] = clamp(sliceRanges[i][j], inpShape[j]); |
|
} |
|
// Fill the rest of ranges. |
|
for (int j = sliceRanges[i].size(); j < inpShape.dims(); ++j) |
|
{ |
|
sliceRanges[i].push_back(Range::all()); |
|
} |
|
} |
|
} |
|
|
|
#ifdef HAVE_OPENCL |
|
bool forward_ocl(InputArrayOfArrays inputs_, OutputArrayOfArrays outputs_, OutputArrayOfArrays internals_) |
|
{ |
|
std::vector<UMat> inputs; |
|
std::vector<UMat> outputs; |
|
|
|
bool use_half = (inputs_.depth() == CV_16S); |
|
inputs_.getUMatVector(inputs); |
|
outputs_.getUMatVector(outputs); |
|
|
|
if (inputs[0].dims < 4 || (total(shape(outputs[0]), 0, 2) % 4 != 0) || |
|
(total(shape(outputs[0]), 2) % 4 != 0)) |
|
return false; |
|
|
|
String opts; |
|
if (use_half) |
|
opts = "-DDtype=half -DDtype4=half4 -DDtype8=half8"; |
|
else |
|
opts = "-DDtype=float -DDtype4=float4 -DDtype8=float8"; |
|
const UMat& inpMat = inputs[0]; |
|
for (size_t i = 0; i < outputs.size(); i++) |
|
{ |
|
int groups = outputs[i].size[0]; |
|
int channels = outputs[i].size[1]; |
|
int rows = outputs[i].size[2]; |
|
int cols = outputs[i].size[3]; |
|
|
|
ocl::Kernel kernel("slice", ocl::dnn::slice_oclsrc, opts); |
|
size_t local[] = { 128 }; |
|
size_t global[] = { (size_t)groups * channels / 4 * local[0] }; |
|
int idx = 0; |
|
kernel.set(idx++, ocl::KernelArg::PtrReadOnly(inpMat)); |
|
kernel.set(idx++, (int)(inpMat.size[2] * inpMat.size[3])); |
|
kernel.set(idx++, (int)(rows * cols)); |
|
kernel.set(idx++, (int)inpMat.size[3]); |
|
kernel.set(idx++, (int)cols); |
|
kernel.set(idx++, (int)sliceRanges[i][2].start); |
|
kernel.set(idx++, (int)sliceRanges[i][3].start); |
|
kernel.set(idx++, ocl::KernelArg::PtrWriteOnly(outputs[i])); |
|
bool ret = kernel.run(1, global, local, false); |
|
if (!ret) |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
#endif |
|
|
|
void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE |
|
{ |
|
CV_TRACE_FUNCTION(); |
|
CV_TRACE_ARG_VALUE(name, "name", name.c_str()); |
|
|
|
CV_OCL_RUN(IS_DNN_OPENCL_TARGET(preferableTarget), |
|
forward_ocl(inputs_arr, outputs_arr, internals_arr)) |
|
|
|
std::vector<Mat> inputs, outputs; |
|
inputs_arr.getMatVector(inputs); |
|
outputs_arr.getMatVector(outputs); |
|
|
|
const Mat& inpMat = inputs[0]; |
|
CV_Assert(outputs.size() == sliceRanges.size()); |
|
for (size_t i = 0; i < outputs.size(); i++) |
|
{ |
|
inpMat(sliceRanges[i]).copyTo(outputs[i]); |
|
} |
|
} |
|
|
|
#ifdef HAVE_INF_ENGINE |
|
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >& inputs) CV_OVERRIDE |
|
{ |
|
#if INF_ENGINE_VER_MAJOR_LT(INF_ENGINE_RELEASE_2018R5) |
|
InferenceEngine::DataPtr input = infEngineDataNode(inputs[0]); |
|
InferenceEngine::LayerParams lp; |
|
lp.name = name; |
|
lp.type = "Crop"; |
|
lp.precision = InferenceEngine::Precision::FP32; |
|
std::shared_ptr<InferenceEngine::CropLayer> ieLayer(new InferenceEngine::CropLayer(lp)); |
|
|
|
CV_Assert(sliceRanges.size() == 1); |
|
|
|
int from, to, step; |
|
if (preferableTarget == DNN_TARGET_MYRIAD) |
|
{ |
|
from = 1; |
|
to = sliceRanges[0].size() + 1; |
|
step = 1; |
|
} |
|
else |
|
{ |
|
from = sliceRanges[0].size() - 1; |
|
to = -1; |
|
step = -1; |
|
} |
|
for (int i = from; i != to; i += step) |
|
{ |
|
ieLayer->axis.push_back(i); |
|
ieLayer->offset.push_back(sliceRanges[0][i].start); |
|
ieLayer->dim.push_back(sliceRanges[0][i].end - sliceRanges[0][i].start); |
|
} |
|
return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer)); |
|
#else |
|
return Ptr<BackendNode>(); |
|
#endif // IE < R5 |
|
} |
|
#endif |
|
}; |
|
|
|
Ptr<SliceLayer> SliceLayer::create(const LayerParams& params) |
|
{ |
|
return Ptr<SliceLayer>(new SliceLayerImpl(params)); |
|
} |
|
|
|
} |
|
}
|
|
|