Conversion note.
Opened this issue · 8 comments
jsopencv_to
method are generated by the macro:
CV_JS_TO_CLASS(TYPE)
CV_JS_TO_CLASS_PTR(TYPE)
CV_JS_TO_ENUM(TYPE)
Those Marco are called from:
opencv/modules/core/misc/python/pyopencv_async.hpp
opencv/modules/core/misc/python/pyopencv_cuda.hpp
opencv/modules/core/misc/python/pyopencv_umat.hpp
opencv/modules/core/misc/python/shadow_umat.hpp
CURRENT ERROR:
#define CV_JS_TO_ENUM(TYPE) template<> bool jsopencv_to(const Napi::CallbackInfo &info, const Napi::Value* dst, TYPE& src, const ArgInfo& argInfo) { if (dst.IsNull() || dst.IsUndefined()) return true; int underlying = 0; if (!jsopencv_to(info, dst, underlying, argInfo)) return false; src = static_cast<TYPE>(underlying); return true; }
CV_PY_TO_ENUM
Expands to:
template<> bool jsopencv_to(const Napi::CallbackInfo &info, const Napi::Value* dst, AKAZE_DescriptorType& src, const ArgInfo& argInfo) { if (dst.IsNull() || dst.IsUndefined()) return true; int underlying = 0; if (!jsopencv_to(info, dst, underlying, argInfo)) return false; src = static_cast<AKAZE_DescriptorType>(underlying); return true; }
no instance of overloaded function "jsopencv_to" matches the specified typeC/C++(493)
I think the missing function is:
template<> bool jsopencv_to(const Napi::CallbackInfo &info, Napi::Value* obj, int& value, const ArgInfo& Arginfo);
but it is available in cv2_convert.cpp/hpp
by removing the line:
if (!jsopencv_to(info, dst, underlying, argInfo)) return false;
from CV_JS_TO_ENUM
I still get the same error. so that the missing jsopencv_to
2nd case:
if (!jsopencv_AKAZE_getp(self, self1))
jsopencv_AKAZE_getp is generated by the macro:
#define CVJS_TYPE_DECLARE(EXPORT_NAME, CLASS_ID, STORAGE, SNAME, SCOPE) \
CVJS_TYPE_DECLARE
is called by the macro:
define CVJS_TYPE(EXPORT_NAME, CLASS_ID, STORAGE, SNAME, _1, _2, SCOPE) CVJS_TYPE_DECLARE(EXPORT_NAME, CLASS_ID, STORAGE, SNAME, SCOPE)
CVJS_TYPE
is called from jsopencv_generated_types.h
The original line should be generated by:
CVJS_TYPE(AKAZE, AKAZE, Ptr<cv::AKAZE>, Ptr, Feature2D, 0, "");
currently extended as:
struct jsopencv_AKAZE_t { PyObject_HEAD Ptr<cv::AKAZE> v; };
static JsTypeObject jsopencv_AKAZE_TypeXXX = { PyVarObject_HEAD_INIT(&PyType_Type, 0) MODULESTR """.""AKAZE", sizeof(jsopencv_AKAZE_t), };
static PyTypeObject * jsopencv_AKAZE_TypePtr = &jsopencv_AKAZE_TypeXXX;
static bool jsopencv_AKAZE_getp(Napi::Value * self, Ptr<cv::AKAZE> * & dst) {
if (PyObject_TypeCheck(self, jsopencv_AKAZE_TypePtr)) {
dst = &(((jsopencv_AKAZE_t*)self)->v);
return true;
}
return false;
}
static Napi::Value * jsopencv_AKAZE_Instance(const Ptr<cv::AKAZE> &r) {
jsopencv_AKAZE_t *m = PyObject_NEW(jsopencv_AKAZE_t, jsopencv_AKAZE_TypePtr);
new (&(m->v)) Ptr<cv::AKAZE>(r);
return (Napi::Value*)m;
}
static void jsopencv_AKAZE_dealloc(Napi::Value* self) {
((jsopencv_AKAZE_t*)self)->v.Ptr<cv::AKAZE>::~Ptr();
PyObject_Del(self);
}
static Napi::Value* jsopencv_AKAZE_repr(Napi::Value* self) {
char str[1000];
snprintf(str, sizeof(str), "< " MODULESTR """.""AKAZE"" %p>", self);
return PyString_FromString(str);
}
PyObject => Napi::Value
PyErr_Format => failmsg
JsOpenCV_Converter implementations
- 74+ generated in
jsopencv_generated_types_content.h
- 2 generic implementation in cv2_convert.h
- template struct JsOpenCV_Converter< cv::Ptr >
- template struct PyOpenCV_Converter < T, typename std::enable_if< std::is_same<unsigned int, T>::value && !std::is_same<unsigned int, size_t>::value >::type >
- 2 hard coded in
gapi/misc/python/pyobjectcv_gapi.hpp
How classes are defined:
in jsopencv_generated_types_content.h
each class is defined with example for AKAZE
:
// used to link getter
static JsGetSetDef jsopencv_AKAZE_getseters[] = {
{NULL} /* Sentinel */
}
// used to link methods:
static JsMethodDef jsopencv_AKAZE_methods[] =
{
{"create", CV_JS_FN_WITH_KW_(jsopencv_cv_AKAZE_create_static, METH_STATIC), "doc ..."},
{"setThreshold", CV_JS_FN_WITH_KW_(jsopencv_cv_AKAZE_setThreshold, 0), "doc..."},
...
{NULL, NULL}
};
All referenced methods are defined before in the same file.
the macro: CVJS_TYPE_INIT_DYNAMIC
is used to build those objects.
in N-Api each class should be defined with a code like:
Init(Napi::Env env, Napi::Object exports) {
Napi::Function func = DefineClass(env, "AKAZE", {
InstanceMethod("getDefaultName", &AKAZE::GetDefaultName),
InstanceMethod("setThreshold", &AKAZE::SetThreshold),
InstanceAccessor("x", &AKAZE::GetX, nullptr)
});
constructor = Napi::Persistent(func);
constructor.SuppressDestruct();
exports.Set("AKAZE", func);
return exports;
This implementation use Napi::ObjectWrap tools
Next implementation sample:
#include <napi.h>
class AKAZE {
public:
AKAZE() = default;
~AKAZE() = default;
void setThreshold(double threshold) {
this->threshold = threshold;
}
static AKAZE getDefault() {
AKAZE akaze;
akaze.setThreshold(0.001);
return akaze;
}
private:
double threshold;
};
Napi::Object Init(Napi::Env env, Napi::Object exports) {
Napi::HandleScope scope(env);
Napi::Function akazeConstructor = Napi::Function::New(env, [](const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
AKAZE* akaze = new AKAZE();
info.This().As<Napi::Object>().SetInternalField(0, Napi::External<AKAZE>::New(env, akaze));
return info.This();
});
Napi::Function setThreshold = Napi::Function::New(env, [](const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
double threshold = info[0].As<Napi::Number>().DoubleValue();
AKAZE* akaze = info.This().As<Napi::Object>().GetInternalField(0).As<Napi::External<AKAZE>>().Data();
akaze->setThreshold(threshold);
return Napi::Value();
});
Napi::Function getDefault = Napi::Function::New(env, [](const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
AKAZE akaze = AKAZE::getDefault();
Napi::Object obj = Napi::Object::New(env);
obj.SetInternalField(0, Napi::External<AKAZE>::New(env, new AKAZE(akaze)));
return obj;
});
akazeConstructor["getDefault"] = getDefault;
akazeConstructor.As<Napi::Object>().DefineOwnProperty(env, Napi::String::New(env, "setThreshold"), setThreshold);
exports.Set("AKAZE", akazeConstructor);
return exports;
}
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
methods from jsopencv_generated_types_content.h
relay on function like jsopencv_AKAZE_getp
defined in a macro jscompat.hpp: CVJS_TYPE_DECLARE
called by CVJS_TYPE
called in jsopencv_generated_types.h
jscompat.hpp:CVJS_TYPE_DECLARE
need to be rewritten.
The cv2_macro.hpp:CVJS_TYPE
template generates:
- a
struct jsopencv_AKAZE_t {
to encapsulate the real object - a type
jsopencv_AKAZE_TypeXXX
containing a string signature and the structure size. jsopencv_AKAZE_TypePtr
pointer tojsopencv_AKAZE_TypeXXX
jsopencv_AKAZE_getp
get a pointer to the expected type in the struct.jsopencv_AKAZE_Instance
allocate and init the structjsopencv_AKAZE_dealloc
free the structjsopencv_AKAZE_repr
return s string representation of the object.
alternate implementation:
#include <napi.h>
class AKAZE {
public:
AKAZE() = default;
~AKAZE() = default;
void setThreshold(double threshold) {}
void setDescriptorSize(int descriptorSize) {}
void setDescriptorChannels(int descriptorChannels) {}
void setDescriptorType(int descriptorType) {}
static AKAZE getDefault() {
AKAZE akaze;
return akaze;
}
};
void jsopencv_cv_AKAZE_setThreshold(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
double threshold = info[0].As<Napi::Number>().DoubleValue();
AKAZE *akaze = info.This().As<Napi::Object>().GetInternalField(0).As<Napi::External<AKAZE>>().Data();
akaze->setThreshold(threshold);
}
void jsopencv_cv_AKAZE_setDescriptorSize(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
int descriptorSize = info[0].As<Napi::Number>().Int32Value();
AKAZE *akaze = info.This().As<Napi::Object>().GetInternalField(0).As<Napi::External<AKAZE>>().Data();
akaze->setDescriptorSize(descriptorSize);
}
void jsopencv_cv_AKAZE_setDescriptorChannels(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
int descriptorChannels = info[0].As<Napi::Number>().Int32Value();
AKAZE *akaze = info.This().As<Napi::Object>().GetInternalField(0).As<Napi::External<AKAZE>>().Data();
akaze->setDescriptorChannels(descriptorChannels);
}
void jsopencv_cv_AKAZE_setDescriptorType(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
int descriptorType = info[0].As<Napi::Number>().Int32Value();
AKAZE *akaze = info.This().As<Napi::Object>().GetInternalField(0).As<Napi::External<AKAZE>>().Data();
akaze->setDescriptorType(descriptorType);
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
Napi::HandleScope scope(env);
Napi::Function akazeConstructor = Napi::Function::New(env, [](const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
AKAZE *akaze = new AKAZE();
info.This().As<Napi::Object>().SetInternalField(0, Napi::External<AKAZE>::New(env, akaze));
return info.This();
});
Napi::Function setThreshold = Napi::Function::New(env, jsopencv_cv_AKAZE_setThreshold);
Napi::Function setDescriptorSize = Napi::Function::New(env, jsopencv_cv_AKAZE_setDescriptorSize);
Napi::Function setDescriptorChannels = Napi::Function::New(env, jsopencv_cv_AKAZE_setDescriptorChannels);
Napi::Function setDescriptorType = Napi::Function::New(env, jsopencv_cv_AKAZE_setDescriptorType);
Napi::Function getDefault = Napi::Function::New(env, [](const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
AKAZE akaze = AKAZE::getDefault();
Napi::Object obj = Napi::Object::New(env);
obj.SetInternalField(0, Napi::External<AKAZE>::New(env, new AKAZE(akaze)));
return obj;
});
akazeConstructor["getDefault"] = getDefault;
akazeConstructor.As<Napi::Object>().DefineOwnProperty(env, Napi::String::New(env, "setThreshold"), setThreshold);
akazeConstructor.As<Napi::Object>().DefineOwnProperty(env, Napi::String::New(env, "setDescriptorSize"), setDescriptorSize);
akazeConstructor.As<Napi::Object>().DefineOwnProperty(env, Napi::String::New(env, "setDescriptorChannels"), setDescriptorChannels);
akazeConstructor.As<Napi::Object>().DefineOwnProperty(env, Napi::String::New(env, "setDescriptorType"), setDescriptorType);
exports.Set("AKAZE", akazeConstructor);
return exports;
}