Merge remote-tracking branch 'upstream/3.4' into merge-3.4

pull/21690/head
Alexander Alekhin 3 years ago
commit 901e0ddfe4
  1. 2
      modules/dnn/src/darknet/darknet_io.cpp
  2. 52
      modules/dnn/src/layers/slice_layer.cpp
  3. 23
      modules/dnn/src/onnx/onnx_importer.cpp
  4. 13
      modules/dnn/src/tensorflow/tf_importer.cpp
  5. 2
      modules/dnn/src/torch/torch_importer.cpp
  6. 2
      modules/dnn/test/test_layers.cpp
  7. 6
      modules/photo/src/seamless_cloning.hpp
  8. 6
      modules/photo/src/seamless_cloning_impl.cpp
  9. 10
      modules/python/test/test_misc.py

@ -376,7 +376,7 @@ namespace cv {
int begin[] = {0, split_size * group_id, 0, 0}; int begin[] = {0, split_size * group_id, 0, 0};
cv::dnn::DictValue paramBegin = cv::dnn::DictValue::arrayInt(begin, 4); cv::dnn::DictValue paramBegin = cv::dnn::DictValue::arrayInt(begin, 4);
int end[] = {-1, begin[1] + split_size, -1, -1}; int end[] = {INT_MAX, begin[1] + split_size, INT_MAX, INT_MAX};
cv::dnn::DictValue paramEnd = cv::dnn::DictValue::arrayInt(end, 4); cv::dnn::DictValue paramEnd = cv::dnn::DictValue::arrayInt(end, 4);
darknet::LayerParameter lp; darknet::LayerParameter lp;

@ -64,12 +64,32 @@ namespace cv
namespace dnn namespace dnn
{ {
void sliceRangesFromShape(const MatShape& inpShape, int& axis, std::vector<std::vector<cv::Range> >& sliceRanges) Range normalizeRange(const Range& input_range, int n)
{ {
Range range = input_range;
range.start = std::min(std::max(range.start, -n), n - 1);
if (range.start < 0)
{
range.start += n;
}
range.end = std::min(std::max(range.end, -n), n);
if (range.end < 0)
{
range.end += n;
}
return range;
}
std::vector<std::vector<cv::Range> > finalizeSliceRange(const MatShape& inpShape, int& axis,
const std::vector<std::vector<cv::Range> >& inputSliceRanges)
{
std::vector<std::vector<cv::Range> > sliceRanges = inputSliceRanges;
CV_Assert(inpShape.size() > 0); CV_Assert(inpShape.size() > 0);
bool axisNeg = (axis < 0); bool axisNeg = (axis < 0);
axis = (axis + static_cast<int>(inpShape.size())) % inpShape.size(); axis = (axis + static_cast<int>(inpShape.size())) % inpShape.size();
int n = inpShape[axis];
for (size_t i = 0; i < sliceRanges.size(); ++i){ for (size_t i = 0; i < sliceRanges.size(); ++i){
std::vector<Range>& ranges = sliceRanges[i]; std::vector<Range>& ranges = sliceRanges[i];
@ -77,16 +97,20 @@ void sliceRangesFromShape(const MatShape& inpShape, int& axis, std::vector<std::
{ {
ranges.insert(ranges.begin(), axis, Range::all()); ranges.insert(ranges.begin(), axis, Range::all());
} }
Range& range = ranges.back();
if (range.start >= 0) for (size_t j = 0; j < ranges.size(); ++j)
{ {
continue; int n = inpShape[j];
} if (n <= 0)
{
continue;
}
CV_Assert(n != 0); ranges[j] = normalizeRange(ranges[j], n);
range.start = (n + range.start) % n; }
} }
return sliceRanges;
} }
class SliceLayerImpl : public SliceLayer class SliceLayerImpl : public SliceLayer
@ -136,7 +160,7 @@ public:
{ {
int size = sizeOrEnd; int size = sizeOrEnd;
CV_Assert(size == -1 || size > 0); // -1 value means range [start, axis_size). 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. sliceRanges[0][i].end = size > 0 ? (start + size) : INT_MAX; // We'll finalize a negative value later.
} }
else else
{ {
@ -186,8 +210,7 @@ public:
MatShape inpShape = inputs[0]; MatShape inpShape = inputs[0];
int axis_rw = axis; int axis_rw = axis;
std::vector<std::vector<cv::Range> > sliceRanges_rw = sliceRanges; std::vector<std::vector<cv::Range> > sliceRanges_rw = finalizeSliceRange(inpShape, axis_rw, sliceRanges);
sliceRangesFromShape(inpShape, axis_rw, sliceRanges_rw);
if (!sliceRanges_rw.empty()) if (!sliceRanges_rw.empty())
{ {
@ -198,7 +221,7 @@ public:
for (int j = 0; j < sliceRanges_rw[i].size(); ++j) for (int j = 0; j < sliceRanges_rw[i].size(); ++j)
{ {
if (shapesInitialized || inpShape[j] > 0) if (shapesInitialized || inpShape[j] > 0)
outputs[i][j] = normalize_axis_range(sliceRanges_rw[i][j], inpShape[j]).size(); outputs[i][j] = normalizeRange(sliceRanges_rw[i][j], inpShape[j]).size();
if (!sliceSteps.empty() && (i < sliceSteps.size()) && (j < sliceSteps[i].size()) && (sliceSteps[i][j] > 1)) if (!sliceSteps.empty() && (i < sliceSteps.size()) && (j < sliceSteps[i].size()) && (sliceSteps[i][j] > 1))
outputs[i][j] = (outputs[i][j] + sliceSteps[i][j] - 1) / sliceSteps[i][j]; outputs[i][j] = (outputs[i][j] + sliceSteps[i][j] - 1) / sliceSteps[i][j];
@ -235,8 +258,7 @@ public:
CV_Assert(inputs.size() == 1); CV_Assert(inputs.size() == 1);
const MatSize& inpShape = inputs[0].size; const MatSize& inpShape = inputs[0].size;
sliceRangesFromShape(shape(inputs[0]), axis, sliceRanges); finalSliceRanges = finalizeSliceRange(shape(inputs[0]), axis, sliceRanges);
finalSliceRanges = sliceRanges;
if (sliceRanges.empty()) if (sliceRanges.empty())
{ {
@ -266,7 +288,7 @@ public:
// Clamp. // Clamp.
for (int j = 0; j < finalSliceRanges[i].size(); ++j) for (int j = 0; j < finalSliceRanges[i].size(); ++j)
{ {
finalSliceRanges[i][j] = normalize_axis_range(finalSliceRanges[i][j], inpShape[j]); finalSliceRanges[i][j] = normalizeRange(finalSliceRanges[i][j], inpShape[j]);
} }
} }

@ -1275,13 +1275,12 @@ void ONNXImporter::parseSlice(LayerParams& layerParams, const opencv_onnx::NodeP
if (axis > 0) { if (axis > 0) {
CV_CheckLE(axis, 1024, "Slice layer can't have more than 1024 axes"); // arbitrary limit CV_CheckLE(axis, 1024, "Slice layer can't have more than 1024 axes"); // arbitrary limit
begin.resize(axis, 0); begin.resize(axis, 0);
end.resize(axis, -1); end.resize(axis, INT_MAX);
} }
for (int i = 0; i < starts.size(); ++i) for (int i = 0; i < starts.size(); ++i)
{ {
begin.push_back(starts.get<int>(i)); begin.push_back(starts.get<int>(i));
int finish = ends.get<int>(i); end.push_back(ends.get<int>(i));
end.push_back((finish < 0) ? --finish : finish); // numpy doesn't include last dim
} }
} else { // inp_size > 1 } else { // inp_size > 1
CV_Assert(inp_size >= 3); CV_Assert(inp_size >= 3);
@ -1305,14 +1304,10 @@ void ONNXImporter::parseSlice(LayerParams& layerParams, const opencv_onnx::NodeP
const int* ends = end_blob.ptr<int>(); const int* ends = end_blob.ptr<int>();
if (axis > 0) { if (axis > 0) {
begin.resize(axis, 0); begin.resize(axis, 0);
end.resize(axis, -1); end.resize(axis, INT_MAX);
} }
std::copy(starts, starts + start_blob.total(), std::back_inserter(begin)); std::copy(starts, starts + start_blob.total(), std::back_inserter(begin));
for (int i = 0; i < end_blob.total(); ++i) std::copy(ends, ends + end_blob.total(), std::back_inserter(end));
{
int finish = ends[i];
end.push_back((finish < 0) ? --finish : finish); // numpy doesn't include last dim
}
if (inp_size == 5) { if (inp_size == 5) {
CV_Assert(constBlobs.find(node_proto.input(4)) != constBlobs.end()); CV_Assert(constBlobs.find(node_proto.input(4)) != constBlobs.end());
@ -2485,9 +2480,15 @@ void ONNXImporter::parseExpand(LayerParams& layerParams, const opencv_onnx::Node
if (!haveVariables) if (!haveVariables)
{ {
if (broadcast_axes.size() != 1) if (broadcast_axes.size() > 1)
CV_Error(Error::StsNotImplemented, "Expand op doesn't support multiple axes for constant input"); CV_Error(Error::StsNotImplemented, "Expand op doesn't support multiple axes for constant input");
if (broadcast_axes.empty())
{
addConstant(output_name, getBlob(node_proto, 0));
return;
}
Mat input = getBlob(node_proto, 0); Mat input = getBlob(node_proto, 0);
input = input.reshape(0, total(inpShape, 0, broadcast_axes[0])); input = input.reshape(0, total(inpShape, 0, broadcast_axes[0]));
Mat output = cv::repeat(input, 1, targetShape[broadcast_axes[0]]); Mat output = cv::repeat(input, 1, targetShape[broadcast_axes[0]]);
@ -2708,7 +2709,7 @@ void ONNXImporter::parseGather(LayerParams& layerParams, const opencv_onnx::Node
sliceLp.type = "Slice"; sliceLp.type = "Slice";
sliceLp.name = inpShape.size() > 1 ? layerParams.name + "/slice" : layerParams.name; sliceLp.name = inpShape.size() > 1 ? layerParams.name + "/slice" : layerParams.name;
std::vector<int> begin(inpShape.size(), 0); std::vector<int> begin(inpShape.size(), 0);
std::vector<int> end(inpShape.size(), -1); std::vector<int> end(inpShape.size(), INT_MAX);
begin[axis] = index; begin[axis] = index;
end[axis] = index + 1; end[axis] = index + 1;

@ -1681,10 +1681,8 @@ void TFImporter::parseStridedSlice(tensorflow::GraphDef& net, const tensorflow::
int end_mask = getLayerAttr(layer, "end_mask").i(); int end_mask = getLayerAttr(layer, "end_mask").i();
for (int i = 0; i < num; ++i) for (int i = 0; i < num; ++i)
{ {
if (ends.at<int>(i) < 0)
ends.at<int>(i) -= 1;
if (end_mask & (1 << i)) if (end_mask & (1 << i))
ends.at<int>(i) = -1; ends.at<int>(i) = INT_MAX;
if (strides.at<int>(i) != 1) if (strides.at<int>(i) != 1)
CV_Error(Error::StsNotImplemented, CV_Error(Error::StsNotImplemented,
format("StridedSlice with stride %d", strides.at<int>(i))); format("StridedSlice with stride %d", strides.at<int>(i)));
@ -1982,15 +1980,16 @@ void TFImporter::parseConv2DBackpropInput(tensorflow::GraphDef& net, const tenso
int64_t pads[8]; int64_t pads[8];
bool explicit_pads = getExplicitPadding(layerParams, layer, pads); bool explicit_pads = getExplicitPadding(layerParams, layer, pads);
int64_t begs[4] = {}; int64_t begs[4] = {};
int64_t ends[4] = {-1, -1, -1, -1}; int64_t ends[4] = {};
if (explicit_pads) if (explicit_pads)
{ {
name += "/deconv"; name += "/deconv";
layerParams.set("pad_mode", "VALID"); layerParams.set("pad_mode", "VALID");
ends[0] = ends[1] = INT_MAX;
for (int i = 2; i < 4; ++i) // begins=[0, 0, a, b], ends=[-1, -1, c, d] for (int i = 2; i < 4; ++i) // begins=[0, 0, a, b], ends=[-1, -1, c, d]
{ {
begs[i] = pads[2*i]; begs[i] = pads[2*i];
ends[i] = -1 - pads[2*i + 1]; ends[i] = -pads[2*i + 1];
} }
} }
@ -2010,8 +2009,8 @@ void TFImporter::parseConv2DBackpropInput(tensorflow::GraphDef& net, const tenso
const int strideX = layerParams.get<int>("stride_w"); const int strideX = layerParams.get<int>("stride_w");
Mat outShape = getTensorContent(getConstBlob(layer, value_id, 0)); Mat outShape = getTensorContent(getConstBlob(layer, value_id, 0));
int shift = (getDataLayout(layer) == DATA_LAYOUT_NCHW); int shift = (getDataLayout(layer) == DATA_LAYOUT_NCHW);
const int outH = outShape.at<int>(1 + shift) + begs[2] - 1 - ends[2]; const int outH = outShape.at<int>(1 + shift) + begs[2] - ends[2];
const int outW = outShape.at<int>(2 + shift) + begs[3] - 1 - ends[3]; const int outW = outShape.at<int>(2 + shift) + begs[3] - ends[3];
if (layerParams.get<String>("pad_mode") == "SAME") if (layerParams.get<String>("pad_mode") == "SAME")
{ {
layerParams.set("adj_w", (outW - 1) % strideX); layerParams.set("adj_w", (outW - 1) % strideX);

@ -954,7 +954,7 @@ struct TorchImporter
int size = scalarParams.get<int>("size"); int size = scalarParams.get<int>("size");
int begins[] = {0, 0, size, size}; int begins[] = {0, 0, size, size};
int ends[] = {-1, -1, -size - 1, -size - 1}; int ends[] = {INT_MAX, INT_MAX, -size, -size};
newModule->apiType = "Slice"; newModule->apiType = "Slice";
layerParams.set("begin", DictValue::arrayInt<int*>(&begins[0], 4)); layerParams.set("begin", DictValue::arrayInt<int*>(&begins[0], 4));

@ -2082,7 +2082,7 @@ TEST_P(Layer_Test_Slice, variable_input_shape)
int targetId = get<1>(GetParam()); int targetId = get<1>(GetParam());
int begin[] = {0, 0, 0, 0}; int begin[] = {0, 0, 0, 0};
int end[] = {-1, -1, -1, -1}; int end[] = {INT_MAX, INT_MAX, INT_MAX, INT_MAX};
Net net; Net net;
LayerParams lp; LayerParams lp;

@ -53,7 +53,7 @@ namespace cv
class Cloning class Cloning
{ {
public: public:
void normalClone(const cv::Mat& destination, const cv::Mat &mask, const cv::Mat &wmask, cv::Mat &cloned, int flag); void normalClone(const cv::Mat& destination, const cv::Mat &mask, cv::Mat &wmask, cv::Mat &cloned, int flag);
void illuminationChange(cv::Mat &I, cv::Mat &mask, cv::Mat &wmask, cv::Mat &cloned, float alpha, float beta); void illuminationChange(cv::Mat &I, cv::Mat &mask, cv::Mat &wmask, cv::Mat &cloned, float alpha, float beta);
void localColorChange(cv::Mat &I, cv::Mat &mask, cv::Mat &wmask, cv::Mat &cloned, float red_mul, float green_mul, float blue_mul); void localColorChange(cv::Mat &I, cv::Mat &mask, cv::Mat &wmask, cv::Mat &cloned, float red_mul, float green_mul, float blue_mul);
void textureFlatten(cv::Mat &I, cv::Mat &mask, cv::Mat &wmask, float low_threshold, float high_threhold, int kernel_size, cv::Mat &cloned); void textureFlatten(cv::Mat &I, cv::Mat &mask, cv::Mat &wmask, float low_threshold, float high_threhold, int kernel_size, cv::Mat &cloned);
@ -61,10 +61,10 @@ namespace cv
protected: protected:
void initVariables(const cv::Mat &destination, const cv::Mat &binaryMask); void initVariables(const cv::Mat &destination, const cv::Mat &binaryMask);
void computeDerivatives(const cv::Mat &destination, const cv::Mat &patch, const cv::Mat &binaryMask); void computeDerivatives(const cv::Mat &destination, const cv::Mat &patch, cv::Mat &binaryMask);
void scalarProduct(cv::Mat mat, float r, float g, float b); void scalarProduct(cv::Mat mat, float r, float g, float b);
void poisson(const cv::Mat &destination); void poisson(const cv::Mat &destination);
void evaluate(const cv::Mat &I, const cv::Mat &wmask, const cv::Mat &cloned); void evaluate(const cv::Mat &I, cv::Mat &wmask, const cv::Mat &cloned);
void dst(const Mat& src, Mat& dest, bool invert = false); void dst(const Mat& src, Mat& dest, bool invert = false);
void solve(const Mat &img, Mat& mod_diff, Mat &result); void solve(const Mat &img, Mat& mod_diff, Mat &result);

@ -246,7 +246,7 @@ void Cloning::initVariables(const Mat &destination, const Mat &binaryMask)
filter_Y[j] = 2.0f * (float)std::cos(scale * (j + 1)); filter_Y[j] = 2.0f * (float)std::cos(scale * (j + 1));
} }
void Cloning::computeDerivatives(const Mat& destination, const Mat &patch, const Mat &binaryMask) void Cloning::computeDerivatives(const Mat& destination, const Mat &patch, Mat &binaryMask)
{ {
initVariables(destination, binaryMask); initVariables(destination, binaryMask);
@ -306,7 +306,7 @@ void Cloning::poisson(const Mat &destination)
} }
} }
void Cloning::evaluate(const Mat &I, const Mat &wmask, const Mat &cloned) void Cloning::evaluate(const Mat &I, Mat &wmask, const Mat &cloned)
{ {
bitwise_not(wmask,wmask); bitwise_not(wmask,wmask);
@ -320,7 +320,7 @@ void Cloning::evaluate(const Mat &I, const Mat &wmask, const Mat &cloned)
merge(output,cloned); merge(output,cloned);
} }
void Cloning::normalClone(const Mat &destination, const Mat &patch, const Mat &binaryMask, Mat &cloned, int flag) void Cloning::normalClone(const Mat &destination, const Mat &patch, Mat &binaryMask, Mat &cloned, int flag)
{ {
const int w = destination.cols; const int w = destination.cols;
const int h = destination.rows; const int h = destination.rows;

@ -643,6 +643,16 @@ class Arguments(NewOpenCVTests):
msg="Classes from submodules and global module don't refer " msg="Classes from submodules and global module don't refer "
"to the same type") "to the same type")
def test_class_from_submodule_has_global_alias(self):
self.assertTrue(hasattr(cv.ml, "Boost"),
msg="Class is not registered in the submodule")
self.assertTrue(hasattr(cv, "ml_Boost"),
msg="Class from submodule doesn't have alias in the "
"global module")
self.assertEqual(cv.ml.Boost, cv.ml_Boost,
msg="Classes from submodules and global module don't refer "
"to the same type")
def test_inner_class_has_global_alias(self): def test_inner_class_has_global_alias(self):
self.assertTrue(hasattr(cv.SimpleBlobDetector, "Params"), self.assertTrue(hasattr(cv.SimpleBlobDetector, "Params"),
msg="Class is not registered as inner class") msg="Class is not registered as inner class")

Loading…
Cancel
Save