Path: blob/master/modules/dnn/src/layers/resize_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.6#include "../precomp.hpp"7#include "layers_common.hpp"8#include "../op_inf_engine.hpp"9#include <opencv2/imgproc.hpp>1011namespace cv { namespace dnn {1213class ResizeLayerImpl : public ResizeLayer14{15public:16ResizeLayerImpl(const LayerParams& params) : zoomFactorWidth(0), zoomFactorHeight(0), scaleWidth(0), scaleHeight(0)17{18setParamsFrom(params);19outWidth = params.get<float>("width", 0);20outHeight = params.get<float>("height", 0);21if (params.has("zoom_factor"))22{23CV_Assert(!params.has("zoom_factor_x") && !params.has("zoom_factor_y"));24zoomFactorWidth = zoomFactorHeight = params.get<int>("zoom_factor");25}26else if (params.has("zoom_factor_x") || params.has("zoom_factor_y"))27{28CV_Assert(params.has("zoom_factor_x") && params.has("zoom_factor_y"));29zoomFactorWidth = params.get<int>("zoom_factor_x");30zoomFactorHeight = params.get<int>("zoom_factor_y");31}32interpolation = params.get<String>("interpolation");33CV_Assert(interpolation == "nearest" || interpolation == "bilinear");3435alignCorners = params.get<bool>("align_corners", false);36}3738bool getMemoryShapes(const std::vector<MatShape> &inputs,39const int requiredOutputs,40std::vector<MatShape> &outputs,41std::vector<MatShape> &internals) const CV_OVERRIDE42{43CV_Assert_N(inputs.size() == 1, inputs[0].size() == 4);44outputs.resize(1, inputs[0]);45outputs[0][2] = outHeight > 0 ? outHeight : (outputs[0][2] * zoomFactorHeight);46outputs[0][3] = outWidth > 0 ? outWidth : (outputs[0][3] * zoomFactorWidth);47// We can work in-place (do nothing) if input shape == output shape.48return (outputs[0][2] == inputs[0][2]) && (outputs[0][3] == inputs[0][3]);49}5051virtual bool supportBackend(int backendId) CV_OVERRIDE52{53if (backendId == DNN_BACKEND_INFERENCE_ENGINE)54return interpolation == "nearest" && preferableTarget != DNN_TARGET_MYRIAD;55else56return backendId == DNN_BACKEND_OPENCV;57}5859virtual void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr) CV_OVERRIDE60{61std::vector<Mat> inputs, outputs;62inputs_arr.getMatVector(inputs);63outputs_arr.getMatVector(outputs);6465if (!outWidth && !outHeight)66{67outHeight = outputs[0].size[2];68outWidth = outputs[0].size[3];69}70if (alignCorners && outHeight > 1)71scaleHeight = static_cast<float>(inputs[0].size[2] - 1) / (outHeight - 1);72else73scaleHeight = static_cast<float>(inputs[0].size[2]) / outHeight;7475if (alignCorners && outWidth > 1)76scaleWidth = static_cast<float>(inputs[0].size[3] - 1) / (outWidth - 1);77else78scaleWidth = static_cast<float>(inputs[0].size[3]) / outWidth;79}8081void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE82{83CV_TRACE_FUNCTION();84CV_TRACE_ARG_VALUE(name, "name", name.c_str());8586if (inputs_arr.depth() == CV_16S)87{88forward_fallback(inputs_arr, outputs_arr, internals_arr);89return;90}9192std::vector<Mat> inputs, outputs, internals;93inputs_arr.getMatVector(inputs);94outputs_arr.getMatVector(outputs);95internals_arr.getMatVector(internals);9697if (outHeight == inputs[0].size[2] && outWidth == inputs[0].size[3])98return;99100Mat& inp = inputs[0];101Mat& out = outputs[0];102if (interpolation == "nearest")103{104for (size_t n = 0; n < inputs[0].size[0]; ++n)105{106for (size_t ch = 0; ch < inputs[0].size[1]; ++ch)107{108resize(getPlane(inp, n, ch), getPlane(out, n, ch),109Size(outWidth, outHeight), 0, 0, INTER_NEAREST);110}111}112}113else if (interpolation == "bilinear")114{115const int inpHeight = inp.size[2];116const int inpWidth = inp.size[3];117const int inpSpatialSize = inpHeight * inpWidth;118const int outSpatialSize = outHeight * outWidth;119const int numPlanes = inp.size[0] * inp.size[1];120CV_Assert_N(inp.isContinuous(), out.isContinuous());121122Mat inpPlanes = inp.reshape(1, numPlanes * inpHeight);123Mat outPlanes = out.reshape(1, numPlanes * outHeight);124for (int y = 0; y < outHeight; ++y)125{126float input_y = y * scaleHeight;127int y0 = static_cast<int>(input_y);128const float* inpData_row0 = inpPlanes.ptr<float>(y0);129const float* inpData_row1 = inpPlanes.ptr<float>(std::min(y0 + 1, inpHeight - 1));130for (int x = 0; x < outWidth; ++x)131{132float input_x = x * scaleWidth;133int x0 = static_cast<int>(input_x);134int x1 = std::min(x0 + 1, inpWidth - 1);135136float* outData = outPlanes.ptr<float>(y, x);137const float* inpData_row0_c = inpData_row0;138const float* inpData_row1_c = inpData_row1;139for (int c = 0; c < numPlanes; ++c)140{141*outData = inpData_row0_c[x0] +142(input_y - y0) * (inpData_row1_c[x0] - inpData_row0_c[x0]) +143(input_x - x0) * (inpData_row0_c[x1] - inpData_row0_c[x0] +144(input_y - y0) * (inpData_row1_c[x1] - inpData_row0_c[x1] - inpData_row1_c[x0] + inpData_row0_c[x0]));145146inpData_row0_c += inpSpatialSize;147inpData_row1_c += inpSpatialSize;148outData += outSpatialSize;149}150}151}152}153else154CV_Error(Error::StsNotImplemented, "Unknown interpolation: " + interpolation);155}156157virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&) CV_OVERRIDE158{159#ifdef HAVE_INF_ENGINE160InferenceEngine::LayerParams lp;161lp.name = name;162lp.type = "Resample";163lp.precision = InferenceEngine::Precision::FP32;164165std::shared_ptr<InferenceEngine::CNNLayer> ieLayer(new InferenceEngine::CNNLayer(lp));166ieLayer->params["type"] = "caffe.ResampleParameter.NEAREST";167ieLayer->params["antialias"] = "0";168ieLayer->params["width"] = cv::format("%d", outWidth);169ieLayer->params["height"] = cv::format("%d", outHeight);170171return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));172#endif // HAVE_INF_ENGINE173return Ptr<BackendNode>();174}175176protected:177int outWidth, outHeight, zoomFactorWidth, zoomFactorHeight;178String interpolation;179float scaleWidth, scaleHeight;180bool alignCorners;181};182183184Ptr<ResizeLayer> ResizeLayer::create(const LayerParams& params)185{186return Ptr<ResizeLayer>(new ResizeLayerImpl(params));187}188189class InterpLayerImpl CV_FINAL : public ResizeLayerImpl190{191public:192InterpLayerImpl(const LayerParams& params) : ResizeLayerImpl(params) {}193194bool getMemoryShapes(const std::vector<MatShape> &inputs,195const int requiredOutputs,196std::vector<MatShape> &outputs,197std::vector<MatShape> &internals) const CV_OVERRIDE198{199CV_Assert_N(inputs.size() == 1, inputs[0].size() == 4);200outputs.resize(1, inputs[0]);201outputs[0][2] = outHeight > 0 ? outHeight : (1 + zoomFactorHeight * (outputs[0][2] - 1));202outputs[0][3] = outWidth > 0 ? outWidth : (1 + zoomFactorWidth * (outputs[0][3] - 1));203// We can work in-place (do nothing) if input shape == output shape.204return (outputs[0][2] == inputs[0][2]) && (outputs[0][3] == inputs[0][3]);205}206207virtual bool supportBackend(int backendId) CV_OVERRIDE208{209return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_INFERENCE_ENGINE;210}211212virtual void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr) CV_OVERRIDE213{214std::vector<Mat> inputs, outputs;215inputs_arr.getMatVector(inputs);216outputs_arr.getMatVector(outputs);217218if (!outWidth && !outHeight)219{220outHeight = outputs[0].size[2];221outWidth = outputs[0].size[3];222}223int inpHeight = inputs[0].size[2];224int inpWidth = inputs[0].size[3];225scaleHeight = (outHeight > 1) ? (static_cast<float>(inpHeight - 1) / (outHeight - 1)) : 0.f;226scaleWidth = (outWidth > 1) ? (static_cast<float>(inpWidth - 1) / (outWidth - 1)) : 0.f;227}228229virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&) CV_OVERRIDE230{231#ifdef HAVE_INF_ENGINE232InferenceEngine::LayerParams lp;233lp.name = name;234lp.type = "Interp";235lp.precision = InferenceEngine::Precision::FP32;236237std::shared_ptr<InferenceEngine::CNNLayer> ieLayer(new InferenceEngine::CNNLayer(lp));238ieLayer->params["pad_beg"] = "0";239ieLayer->params["pad_end"] = "0";240return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));241#endif // HAVE_INF_ENGINE242return Ptr<BackendNode>();243}244};245246Ptr<Layer> InterpLayer::create(const LayerParams& params)247{248LayerParams lp(params);249lp.set("interpolation", "bilinear");250return Ptr<Layer>(new InterpLayerImpl(lp));251}252253} // namespace dnn254} // namespace cv255256257