From d1a3b530befc66b643188b9e774f30b1884bf266 Mon Sep 17 00:00:00 2001 From: David Koller Date: Sun, 14 Jan 2018 00:39:11 -0500 Subject: [PATCH] Make DNN Crop layer match Caffe default offset behavior and add parametric unit test for crop layer. --- modules/dnn/src/layers/crop_layer.cpp | 24 ++------ modules/dnn/test/test_layers.cpp | 83 +++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 19 deletions(-) diff --git a/modules/dnn/src/layers/crop_layer.cpp b/modules/dnn/src/layers/crop_layer.cpp index 29b26fc2d1..0d43487376 100644 --- a/modules/dnn/src/layers/crop_layer.cpp +++ b/modules/dnn/src/layers/crop_layer.cpp @@ -110,26 +110,12 @@ public: } crop_ranges.resize(dims, Range::all()); - for (int i = 0; i < dims; i++) + for (int i = start_axis; i < dims; i++) { - if( i < start_axis ) - continue; - - if (!offset.empty()) //normal case - { - if (offset_final[i] < 0 || offset_final[i] + inpSzBlob.size[i] > inpBlob.size[i]) - CV_Error(Error::StsBadArg, "invalid crop parameters"); - - crop_ranges[i] = Range(offset_final[i], offset_final[i] + inpSzBlob.size[i]); - } - else //detect offset automatically so that cropped image is center of original one - { - if (inpSzBlob.size[i] > inpBlob.size[i]) - CV_Error(Error::StsBadArg, "invalid output blob size"); - - int cur_crop = (inpBlob.size[i] - inpSzBlob.size[i]) / 2; - crop_ranges[i] = Range(cur_crop, cur_crop + inpSzBlob.size[i]); - } + if (offset_final[i] < 0 || offset_final[i] + inpSzBlob.size[i] > inpBlob.size[i]) + CV_Error(Error::StsBadArg, "invalid crop parameters or blob sizes"); + + crop_ranges[i] = Range(offset_final[i], offset_final[i] + inpSzBlob.size[i]); } } diff --git a/modules/dnn/test/test_layers.cpp b/modules/dnn/test/test_layers.cpp index d88f01d380..8b463c3357 100644 --- a/modules/dnn/test/test_layers.cpp +++ b/modules/dnn/test/test_layers.cpp @@ -715,4 +715,87 @@ INSTANTIATE_TEST_CASE_P(Layer_Test, Scale_untrainable, Combine( /*conv fusion*/ testing::Bool() )); +typedef testing::TestWithParam > Crop; +TEST_P(Crop, Accuracy) +{ + Vec4i inpShapeVec = get<0>(GetParam()); + Vec4i sizShapeVec = get<1>(GetParam()); + int axis = get<2>(GetParam()); + int numOffsets = get<3>(GetParam()); + int offsetVal = get<4>(GetParam()); + const int inpShape[] = {inpShapeVec[0], inpShapeVec[1], inpShapeVec[2], inpShapeVec[3]}; + const int sizShape[] = {sizShapeVec[0], sizShapeVec[1], sizShapeVec[2], sizShapeVec[3]}; + + // Create a network with two inputs. Crop layer crops a first input to + // the size of a second one. + // See http://caffe.berkeleyvision.org/tutorial/layers/crop.html + Net net; + + LayerParams lp; + lp.name = "testCrop"; + lp.type = "Crop"; + lp.set("axis", axis); + if (numOffsets > 0) + { + std::vector offsets(numOffsets, offsetVal); + lp.set("offset", DictValue::arrayInt(&offsets[0], offsets.size())); + } + else + offsetVal = 0; + int id = net.addLayerToPrev(lp.name, lp.type, lp); + net.connect(0, 1, id, 1); + + Mat inpImage(4, inpShape, CV_32F); + Mat sizImage(4, sizShape, CV_32F); + randu(inpImage, -1, 1); + randu(sizImage, -1, 1); + + std::vector inpNames(2); + inpNames[0] = "cropImage"; + inpNames[1] = "sizImage"; + net.setInputsNames(inpNames); + net.setInput(inpImage, inpNames[0]); + net.setInput(sizImage, inpNames[1]); + + // There are a few conditions that represent invalid input to the crop + // layer, so in those cases we want to verify an exception is thrown. + + bool shouldThrowException = false; + if (numOffsets > 1 && numOffsets != 4 - axis) + shouldThrowException = true; + else + for (int i = axis; i < 4; i++) + if (sizShape[i] + offsetVal > inpShape[i]) + shouldThrowException = true; + + Mat out; + if (shouldThrowException) + { + ASSERT_ANY_THROW(out = net.forward()); + return; + } + else + out = net.forward(); + + // Finally, compare the cropped output blob from the DNN layer (out) + // to a reference blob (ref) that we compute here. + + std::vector crop_range; + crop_range.resize(4, Range::all()); + for (int i = axis; i < 4; i++) + crop_range[i] = Range(offsetVal, sizShape[i] + offsetVal); + + Mat ref(sizImage.dims, sizImage.size, CV_32F); + inpImage(&crop_range[0]).copyTo(ref); + normAssert(out, ref); +} + +INSTANTIATE_TEST_CASE_P(Layer_Test, Crop, Combine( +/*input blob shape*/ Values(Vec4i(1, 3, 20, 30)), +/*cropsize blob shape*/ Values(Vec4i(1, 3, 10, 12)), +/*start axis*/ Values(0, 1, 2), +/*number of offsets*/ Values(0, 1, 2, 4), +/*offset value*/ Values(3, 4) +)); + }