|
|
|
@ -84,6 +84,34 @@ Range normalizeRange(const Range& input_range, int n) |
|
|
|
|
return range; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO: support cv::Range with steps and negative steps to get rid of this transformation
|
|
|
|
|
void tranformForNegSteps(const MatShape& inpShape, std::vector<std::vector<Range> >& sliceRanges, std::vector<std::vector<int> >& sliceSteps) |
|
|
|
|
{ |
|
|
|
|
// in case of negative steps,
|
|
|
|
|
// x of shape [5, 10], x[5:0:-1, 10:1:-3] <=> np.flip(x[1:5:1, 2:10:3], aixs=(0, 1))
|
|
|
|
|
// new_end_i = start_i + 1 > dim_i ? dim_i : start_i + 1
|
|
|
|
|
// new_start_i = end + 1
|
|
|
|
|
// new_start_i = new_end_i - 1 - ((new_end_i - 1 - new_start_i) / abs(step_i)) * abs(step_i)
|
|
|
|
|
int start, end, new_start, new_end, step; |
|
|
|
|
for (int i = 0; i < sliceSteps[0].size(); ++i) |
|
|
|
|
{ |
|
|
|
|
step = sliceSteps[0][i]; |
|
|
|
|
if (step > 0) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
step = -step; |
|
|
|
|
start = sliceRanges[0][i].start; |
|
|
|
|
end = sliceRanges[0][i].end; |
|
|
|
|
new_end = start >= inpShape[i] ? inpShape[i] : start + 1; |
|
|
|
|
new_start = end + 1; |
|
|
|
|
new_start = new_end - 1 - ((new_end - 1 - new_start) / step) * step; |
|
|
|
|
|
|
|
|
|
sliceSteps[0][i] = step; |
|
|
|
|
sliceRanges[0][i].start = new_start; |
|
|
|
|
sliceRanges[0][i].end = new_end; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::vector<std::vector<cv::Range> > finalizeSliceRange(const MatShape& inpShape, int& axis, |
|
|
|
|
const std::vector<std::vector<cv::Range> >& inputSliceRanges) |
|
|
|
|
{ |
|
|
|
@ -149,6 +177,24 @@ public: |
|
|
|
|
const DictValue &sizesOrEnds = params.has("size") ? params.get("size") : params.get("end"); |
|
|
|
|
CV_Assert(begins.size() == sizesOrEnds.size()); |
|
|
|
|
|
|
|
|
|
if (params.has("steps")) |
|
|
|
|
{ |
|
|
|
|
const DictValue &steps = params.get("steps"); |
|
|
|
|
sliceSteps.resize(1); |
|
|
|
|
sliceSteps[0].resize(steps.size()); |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < steps.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
int step = steps.get<int>(i); |
|
|
|
|
CV_Assert(step != 0); |
|
|
|
|
if (step < 0) |
|
|
|
|
neg_step_dims.push_back(i); |
|
|
|
|
if (std::abs(step) > 1) |
|
|
|
|
hasSteps = true; |
|
|
|
|
sliceSteps[0][i] = step; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sliceRanges.resize(1); |
|
|
|
|
sliceRanges[0].resize(begins.size(), Range::all()); |
|
|
|
|
for (int i = 0; i < begins.size(); ++i) |
|
|
|
@ -166,26 +212,13 @@ public: |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
int end = sizeOrEnd; |
|
|
|
|
if (hasSteps && !neg_step_dims.empty() && sliceSteps[0][i] < 0) |
|
|
|
|
CV_Assert(end < 0 || end != start); // if current step is negative, end < start is allowed.
|
|
|
|
|
else |
|
|
|
|
CV_Assert(end < 0 || end > start); // End index is excluded.
|
|
|
|
|
sliceRanges[0][i].end = end; // We'll finalize a negative value later.
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (params.has("steps")) |
|
|
|
|
{ |
|
|
|
|
const DictValue &steps = params.get("steps"); |
|
|
|
|
sliceSteps.resize(1); |
|
|
|
|
sliceSteps[0].resize(steps.size()); |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < steps.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
int step = steps.get<int>(i); |
|
|
|
|
CV_Assert(step >= 1); |
|
|
|
|
if (step > 1) |
|
|
|
|
hasSteps = true; |
|
|
|
|
sliceSteps[0][i] = step; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -193,11 +226,11 @@ public: |
|
|
|
|
{ |
|
|
|
|
#ifdef HAVE_INF_ENGINE |
|
|
|
|
if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) |
|
|
|
|
return sliceRanges.size() == 1 && !hasSteps; |
|
|
|
|
return sliceRanges.size() == 1 && !hasSteps && neg_step_dims.empty(); |
|
|
|
|
#endif |
|
|
|
|
#ifdef HAVE_CUDA |
|
|
|
|
if (backendId == DNN_BACKEND_CUDA) |
|
|
|
|
return !hasSteps; |
|
|
|
|
return !hasSteps && neg_step_dims.empty(); |
|
|
|
|
#endif |
|
|
|
|
return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_CANN; |
|
|
|
|
} |
|
|
|
@ -210,8 +243,13 @@ public: |
|
|
|
|
CV_Assert(inputs.size() == 1); |
|
|
|
|
MatShape inpShape = inputs[0]; |
|
|
|
|
|
|
|
|
|
std::vector<std::vector<int> > sliceSteps_ = sliceSteps; |
|
|
|
|
std::vector<std::vector<cv::Range> > sliceRanges_ = sliceRanges; |
|
|
|
|
if (hasSteps && !neg_step_dims.empty()) |
|
|
|
|
tranformForNegSteps(inpShape, sliceRanges_, sliceSteps_); |
|
|
|
|
|
|
|
|
|
int axis_rw = axis; |
|
|
|
|
std::vector<std::vector<cv::Range> > sliceRanges_rw = finalizeSliceRange(inpShape, axis_rw, sliceRanges); |
|
|
|
|
std::vector<std::vector<cv::Range> > sliceRanges_rw = finalizeSliceRange(inpShape, axis_rw, sliceRanges_); |
|
|
|
|
|
|
|
|
|
if (!sliceRanges_rw.empty()) |
|
|
|
|
{ |
|
|
|
@ -224,8 +262,8 @@ public: |
|
|
|
|
if (shapesInitialized || inpShape[j] > 0) |
|
|
|
|
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)) |
|
|
|
|
outputs[i][j] = (outputs[i][j] + sliceSteps[i][j] - 1) / sliceSteps[i][j]; |
|
|
|
|
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]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -257,7 +295,10 @@ public: |
|
|
|
|
outputs_arr.getMatVector(outputs); |
|
|
|
|
|
|
|
|
|
CV_Assert(inputs.size() == 1); |
|
|
|
|
const MatSize& inpShape = inputs[0].size; |
|
|
|
|
MatShape inpShape = shape(inputs[0]); |
|
|
|
|
|
|
|
|
|
if (hasSteps && !neg_step_dims.empty()) |
|
|
|
|
tranformForNegSteps(inpShape, sliceRanges, sliceSteps); |
|
|
|
|
|
|
|
|
|
finalSliceRanges = finalizeSliceRange(shape(inputs[0]), axis, sliceRanges); |
|
|
|
|
|
|
|
|
@ -280,9 +321,9 @@ public: |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < outputs.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
CV_Assert(finalSliceRanges[i].size() <= inpShape.dims()); |
|
|
|
|
CV_Assert(finalSliceRanges[i].size() <= inpShape.size()); |
|
|
|
|
// Fill the rest of ranges.
|
|
|
|
|
for (int j = finalSliceRanges[i].size(); j < inpShape.dims(); ++j) |
|
|
|
|
for (int j = finalSliceRanges[i].size(); j < inpShape.size(); ++j) |
|
|
|
|
{ |
|
|
|
|
finalSliceRanges[i].push_back(Range::all()); |
|
|
|
|
} |
|
|
|
@ -586,6 +627,8 @@ public: |
|
|
|
|
getSliceRecursive<int8_t>(inpMat, inpIdx, finalSliceRanges[i], sliceSteps[i], 0, dimsNum, outputs[i], outIdx); |
|
|
|
|
else |
|
|
|
|
getSliceRecursive<float>(inpMat, inpIdx, finalSliceRanges[i], sliceSteps[i], 0, dimsNum, outputs[i], outIdx); |
|
|
|
|
// flip for negative steps
|
|
|
|
|
flip(outputs[i]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -650,7 +693,6 @@ public: |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_DNN_NGRAPH |
|
|
|
|
virtual Ptr<BackendNode> initNgraph(const std::vector<Ptr<BackendWrapper> >& inputs, |
|
|
|
|
const std::vector<Ptr<BackendNode> >& nodes) CV_OVERRIDE |
|
|
|
@ -739,9 +781,15 @@ private: |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void flip(Mat& output) // break if 1d tensor?
|
|
|
|
|
{ |
|
|
|
|
for (int i = 0; i < neg_step_dims.size(); ++i) |
|
|
|
|
cv::flipND(output, output, neg_step_dims[i]); |
|
|
|
|
} |
|
|
|
|
protected: |
|
|
|
|
// The actual non-negative values determined from @p sliceRanges depends on input size.
|
|
|
|
|
std::vector<std::vector<Range> > finalSliceRanges; |
|
|
|
|
std::vector<int> neg_step_dims; |
|
|
|
|
bool hasDynamicShapes; |
|
|
|
|
bool shapesInitialized; |
|
|
|
|
bool hasSteps; |
|
|
|
|