mirror of
https://github.com/opencv/opencv.git
synced 2026-07-28 23:03:03 +04:00
Merge pull request #25810 from fengyuentau:python/fix_parsing_3d_mat_in_dnn
python: attempts to fix 3d mat parsing problem for dnn #25810 Fixes https://github.com/opencv/opencv/issues/25762 https://github.com/opencv/opencv/issues/23242 Relates https://github.com/opencv/opencv/issues/25763 https://github.com/opencv/opencv/issues/19091 Although `cv.Mat` has already been introduced to workaround this problem, people do not know it and it kind of leads to confusion with `numpy.array`. This patch adds a "switch" to turn off the auto multichannel feature when the API is from cv::dnn::Net (more specifically, `setInput`) and the parameter is of type `Mat`. This patch only leads to changes of three places in `pyopencv_generated_types_content.h`: ```.diff static PyObject* pyopencv_cv_dnn_dnn_Net_setInput(PyObject* self, PyObject* py_args, PyObject* kw) { ... - pyopencv_to_safe(pyobj_blob, blob, ArgInfo("blob", 0)) && + pyopencv_to_safe(pyobj_blob, blob, ArgInfo("blob", 8)) && ... } // I guess we also need to change this as one-channel blob is expected for param static PyObject* pyopencv_cv_dnn_dnn_Net_setParam(PyObject* self, PyObject* py_args, PyObject* kw) { ... - pyopencv_to_safe(pyobj_blob, blob, ArgInfo("blob", 0)) ) + pyopencv_to_safe(pyobj_blob, blob, ArgInfo("blob", 8)) ) ... - pyopencv_to_safe(pyobj_blob, blob, ArgInfo("blob", 0)) ) + pyopencv_to_safe(pyobj_blob, blob, ArgInfo("blob", 8)) ) ... } ``` Others are unchanged, e.g. `dnn_SegmentationModel` and stuff like that. ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
@@ -46,19 +46,22 @@ private:
|
||||
static const uint32_t arg_outputarg_flag = 0x1;
|
||||
static const uint32_t arg_arithm_op_src_flag = 0x2;
|
||||
static const uint32_t arg_pathlike_flag = 0x4;
|
||||
static const uint32_t arg_nd_mat_flag = 0x8;
|
||||
|
||||
public:
|
||||
const char* name;
|
||||
bool outputarg;
|
||||
bool arithm_op_src;
|
||||
bool pathlike;
|
||||
bool nd_mat;
|
||||
// more fields may be added if necessary
|
||||
|
||||
ArgInfo(const char* name_, uint32_t arg_) :
|
||||
name(name_),
|
||||
outputarg((arg_ & arg_outputarg_flag) != 0),
|
||||
arithm_op_src((arg_ & arg_arithm_op_src_flag) != 0),
|
||||
pathlike((arg_ & arg_pathlike_flag) != 0) {}
|
||||
pathlike((arg_ & arg_pathlike_flag) != 0),
|
||||
nd_mat((arg_ & arg_nd_mat_flag) != 0) {}
|
||||
|
||||
private:
|
||||
ArgInfo(const ArgInfo&) = delete;
|
||||
|
||||
@@ -173,7 +173,7 @@ bool pyopencv_to(PyObject* o, Mat& m, const ArgInfo& info)
|
||||
|
||||
CV_LOG_DEBUG(NULL, "Incoming ndarray '" << info.name << "': ndims=" << ndims << " _sizes=" << pycv_dumpArray(_sizes, ndims) << " _strides=" << pycv_dumpArray(_strides, ndims));
|
||||
|
||||
bool ismultichannel = ndims == 3 && _sizes[2] <= CV_CN_MAX;
|
||||
bool ismultichannel = ndims == 3 && _sizes[2] <= CV_CN_MAX && !info.nd_mat;
|
||||
if (pyopencv_Mat_TypePtr && PyObject_TypeCheck(o, pyopencv_Mat_TypePtr))
|
||||
{
|
||||
bool wrapChannels = false;
|
||||
|
||||
@@ -340,22 +340,38 @@ static bool pyopencv_to_generic_vec(PyObject* obj, std::vector<Tp>& value, const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!PySequence_Check(obj))
|
||||
if (info.nd_mat && PyArray_Check(obj))
|
||||
{
|
||||
failmsg("Can't parse '%s'. Input argument doesn't provide sequence protocol", info.name);
|
||||
return false;
|
||||
}
|
||||
const size_t n = static_cast<size_t>(PySequence_Size(obj));
|
||||
value.resize(n);
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
SafeSeqItem item_wrap(obj, i);
|
||||
if (!pyopencv_to(item_wrap.item, value[i], info))
|
||||
/*
|
||||
If obj is marked as nd mat and of array type, it is parsed to a single
|
||||
mat in the target vector to avoid being split into multiple mats
|
||||
*/
|
||||
value.resize(1);
|
||||
if (!pyopencv_to(obj, value.front(), info))
|
||||
{
|
||||
failmsg("Can't parse '%s'. Sequence item with index %lu has a wrong type", info.name, i);
|
||||
failmsg("Can't parse '%s'. Array item has a wrong type", info.name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else // parse as sequence
|
||||
{
|
||||
if (!PySequence_Check(obj))
|
||||
{
|
||||
failmsg("Can't parse '%s'. Input argument doesn't provide sequence protocol", info.name);
|
||||
return false;
|
||||
}
|
||||
const size_t n = static_cast<size_t>(PySequence_Size(obj));
|
||||
value.resize(n);
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
SafeSeqItem item_wrap(obj, i);
|
||||
if (!pyopencv_to(item_wrap.item, value[i], info))
|
||||
{
|
||||
failmsg("Can't parse '%s'. Sequence item with index %lu has a wrong type", info.name, i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -488,6 +488,10 @@ class ArgInfo(object):
|
||||
return self.name + '_'
|
||||
return self.name
|
||||
|
||||
@property
|
||||
def nd_mat(self):
|
||||
return '/ND' in self._modifiers
|
||||
|
||||
@property
|
||||
def inputarg(self):
|
||||
return '/O' not in self._modifiers
|
||||
@@ -528,6 +532,7 @@ class ArgInfo(object):
|
||||
arg = 0x01 if self.outputarg else 0x0
|
||||
arg += 0x02 if self.arithm_op_src_arg else 0x0
|
||||
arg += 0x04 if self.pathlike else 0x0
|
||||
arg += 0x08 if self.nd_mat else 0x0
|
||||
return "ArgInfo(\"%s\", %d)" % (self.name, arg)
|
||||
|
||||
|
||||
|
||||
@@ -82,6 +82,10 @@ class CppHeaderParser(object):
|
||||
modlist = []
|
||||
|
||||
# pass 0: extracts the modifiers
|
||||
if "CV_ND" in arg_str:
|
||||
modlist.append("/ND")
|
||||
arg_str = arg_str.replace("CV_ND", "")
|
||||
|
||||
if "CV_OUT" in arg_str:
|
||||
modlist.append("/O")
|
||||
arg_str = arg_str.replace("CV_OUT", "")
|
||||
|
||||
Reference in New Issue
Block a user