Commit d1a3b530 authored by David Koller's avatar David Koller Committed by drkoller

Make DNN Crop layer match Caffe default offset behavior

and add parametric unit test for crop layer.
parent a55aed5f
......@@ -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]);
}
}
......
......@@ -715,4 +715,87 @@ INSTANTIATE_TEST_CASE_P(Layer_Test, Scale_untrainable, Combine(
/*conv fusion*/ testing::Bool()
));
typedef testing::TestWithParam<tuple<Vec4i, Vec4i, int, int, int> > 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<int> offsets(numOffsets, offsetVal);
lp.set("offset", DictValue::arrayInt<int*>(&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<String> 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<Range> 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)
));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment