Skip to content

Commit b9f94c9

Browse files
committed
Nearest neighbor resize layer
1 parent 5f6ce6f commit b9f94c9

File tree

5 files changed

+104
-0
lines changed

5 files changed

+104
-0
lines changed

modules/dnn/include/opencv2/dnn/all_layers.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,17 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
539539
static Ptr<NormalizeBBoxLayer> create(const LayerParams& params);
540540
};
541541

542+
/**
543+
* @brief Resize input 4-dimensional blob by nearest neghbor strategy.
544+
*
545+
* Layer is used to support TensorFlow's resize_nearest_neighbor op.
546+
*/
547+
class CV_EXPORTS ResizeNearestNeighborLayer : public Layer
548+
{
549+
public:
550+
static Ptr<ResizeNearestNeighborLayer> create(const LayerParams& params);
551+
};
552+
542553
//! @}
543554
//! @}
544555
CV__DNN_EXPERIMENTAL_NS_END

modules/dnn/src/init.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ void initializeLayerFactory()
8383
CV_DNN_REGISTER_LAYER_CLASS(Concat, ConcatLayer);
8484
CV_DNN_REGISTER_LAYER_CLASS(Reshape, ReshapeLayer);
8585
CV_DNN_REGISTER_LAYER_CLASS(Flatten, FlattenLayer);
86+
CV_DNN_REGISTER_LAYER_CLASS(ResizeNearestNeighbor, ResizeNearestNeighborLayer);
8687

8788
CV_DNN_REGISTER_LAYER_CLASS(Convolution, ConvolutionLayer);
8889
CV_DNN_REGISTER_LAYER_CLASS(Deconvolution, DeconvolutionLayer);
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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) 2017, Intel Corporation, all rights reserved.
6+
// Third party copyrights are property of their respective owners.
7+
#include "../precomp.hpp"
8+
#include "layers_common.hpp"
9+
#include <opencv2/imgproc.hpp>
10+
11+
namespace cv { namespace dnn {
12+
13+
class ResizeNearestNeighborLayerImpl : public ResizeNearestNeighborLayer
14+
{
15+
public:
16+
ResizeNearestNeighborLayerImpl(const LayerParams& params)
17+
{
18+
setParamsFrom(params);
19+
CV_Assert(params.has("width"), params.has("height"));
20+
outWidth = params.get<float>("width");
21+
outHeight = params.get<float>("height");
22+
alignCorners = params.get<bool>("align_corners", false);
23+
if (alignCorners)
24+
CV_Error(Error::StsNotImplemented, "Nearest neighborhood resize with align_corners=true is not implemented");
25+
}
26+
27+
bool getMemoryShapes(const std::vector<MatShape> &inputs,
28+
const int requiredOutputs,
29+
std::vector<MatShape> &outputs,
30+
std::vector<MatShape> &internals) const
31+
{
32+
CV_Assert(inputs.size() == 1, inputs[0].size() == 4);
33+
outputs.resize(1, inputs[0]);
34+
outputs[0][2] = outHeight;
35+
outputs[0][3] = outWidth;
36+
// We can work in-place (do nothing) if input shape == output shape.
37+
return (outputs[0][2] == inputs[0][2]) && (outputs[0][3] == inputs[0][3]);
38+
}
39+
40+
void forward(std::vector<Mat*> &inputs, std::vector<Mat> &outputs, std::vector<Mat> &internals)
41+
{
42+
CV_TRACE_FUNCTION();
43+
CV_TRACE_ARG_VALUE(name, "name", name.c_str());
44+
45+
if (outHeight == inputs[0]->size[2] && outWidth == inputs[0]->size[3])
46+
return;
47+
48+
Mat& inp = *inputs[0];
49+
Mat& out = outputs[0];
50+
for (size_t n = 0; n < inputs[0]->size[0]; ++n)
51+
{
52+
for (size_t ch = 0; ch < inputs[0]->size[1]; ++ch)
53+
{
54+
resize(getPlane(inp, n, ch), getPlane(out, n, ch),
55+
Size(outWidth, outHeight), 0, 0, INTER_NEAREST);
56+
}
57+
}
58+
}
59+
private:
60+
int outWidth, outHeight;
61+
bool alignCorners;
62+
};
63+
64+
65+
Ptr<ResizeNearestNeighborLayer> ResizeNearestNeighborLayer::create(const LayerParams& params)
66+
{
67+
return Ptr<ResizeNearestNeighborLayer>(new ResizeNearestNeighborLayerImpl(params));
68+
}
69+
70+
} // namespace dnn
71+
} // namespace cv

modules/dnn/src/tensorflow/tf_importer.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,22 @@ void TFImporter::populateNet(Net dstNet)
11321132
// one input only
11331133
connect(layer_id, dstNet, parsePin(layer.input(1)), id, 0);
11341134
}
1135+
else if (type == "ResizeNearestNeighbor")
1136+
{
1137+
Mat outSize = getTensorContent(getConstBlob(layer, value_id, 1));
1138+
CV_Assert(outSize.type() == CV_32SC1, outSize.total() == 2);
1139+
1140+
layerParams.set("height", outSize.at<int>(0, 0));
1141+
layerParams.set("width", outSize.at<int>(0, 1));
1142+
1143+
if (hasLayerAttr(layer, "align_corners"))
1144+
layerParams.set("align_corners", getLayerAttr(layer, "align_corners").b());
1145+
1146+
int id = dstNet.addLayer(name, "ResizeNearestNeighbor", layerParams);
1147+
layer_id[name] = id;
1148+
1149+
connect(layer_id, dstNet, parsePin(layer.input(0)), id, 0);
1150+
}
11351151
else if (type == "Abs" || type == "Tanh" || type == "Sigmoid" ||
11361152
type == "Relu" || type == "Elu" || type == "Softmax" ||
11371153
type == "Identity" || type == "Relu6")

modules/dnn/test/test_tf_importer.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,4 +175,9 @@ TEST(Test_TensorFlow, split)
175175
runTensorFlowNet("split_equals");
176176
}
177177

178+
TEST(Test_TensorFlow, resize_nearest_neighbor)
179+
{
180+
runTensorFlowNet("resize_nearest_neighbor");
181+
}
182+
178183
}

0 commit comments

Comments
 (0)