C++ 将图像指针返回到Erlang
我正在尝试将openCV与Erlang NIF结合使用。 所以我想做一件基本的事情,那就是读取一张图片并将指针发送回erlang。 并且能够再次将收到的指针发送回C,并显示图片 因此niftest.cpp如下所示:C++ 将图像指针返回到Erlang,c++,opencv,pointers,erlang,erlang-nif,C++,Opencv,Pointers,Erlang,Erlang Nif,我正在尝试将openCV与Erlang NIF结合使用。 所以我想做一件基本的事情,那就是读取一张图片并将指针发送回erlang。 并且能够再次将收到的指针发送回C,并显示图片 因此niftest.cpp如下所示: /* niftest.cpp */ #include "erl_nif.h" #include <opencv/highgui.h> #include <opencv/cv.h> using namespace cv; using namespace std
/* niftest.cpp */
#include "erl_nif.h"
#include <opencv/highgui.h>
#include <opencv/cv.h>
using namespace cv;
using namespace std;
static ErlNifResourceType* frame_res = NULL;
typedef struct _frame_t {
IplImage* _frame;
} frame_t;
//------------------------------------------------------------------------------
// NIF callbacks
//------------------------------------------------------------------------------
static void frame_cleanup(ErlNifEnv* env, void* arg) {
enif_free(arg);
}
static int load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
{
ErlNifResourceFlags flags = (ErlNifResourceFlags) (ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER);
frame_res = enif_open_resource_type(env, "niftest", "ocv_frame",
&frame_cleanup,
flags, 0);
return 0;
}
static ERL_NIF_TERM get_pic(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
IplImage* src = cvLoadImage("/home/khashayar/Downloads/pic.png");
cout << src->width << endl;
IplImage* gray = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
cvCvtColor(src, gray, CV_RGB2GRAY);
frame_t* frame = (frame_t*)enif_alloc_resource(frame_res, sizeof(frame_t));
frame->_frame = gray ;
ERL_NIF_TERM term = enif_make_resource(env, frame);
enif_release_resource(frame);
return enif_make_tuple2(env, enif_make_atom(env, "ok"), term);
}
static ERL_NIF_TERM show_pic(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]){
frame_t* frame;
if (!enif_get_resource(env, argv[0], frame_res, (void**) &frame)) {
return enif_make_badarg(env);
}
cvShowImage("YOOHOO", frame->_frame);
cvWaitKey(30);
return enif_make_atom(env, "ok");
}
static ErlNifFunc nif_funcs[] =
{
{"show_pic", 1, show_pic},
{"get_pic", 0, get_pic}
};
ERL_NIF_INIT(niftest,nif_funcs,load,NULL,NULL,NULL)
所以现在的问题是,当我调用get_pic时,我得到的是{ok,}
,指针根本无效
当我cout
生成enif\u make\u资源之前的帧时,它有一个值,我可以看到它,但它返回给我为空
我做错了什么?
我已经阅读了所有的文档,但我真的不明白这一点
注意:您可以使用以下命令编译代码:
g++ -fPIC -shared -o niftest.so niftest.cpp -lopencv_core -lopencv_imgproc -lopencv_highgui -I /usr/lib64/erlang/usr/include/
然后运行erlang shell并调用init和get_pic函数NIF是移植OpenCV高级GUI的错误解决方案。
然而,为了回答您的问题:您得到的{ok,}
元组中显然是空的二进制文件在Erlang中是不透明的。这是一个资源对象,如手册页中所述
资源对象是垃圾收集器友好的。如果没有进程引用给定的资源,则将调用cleanup函数。它们通常是在nIF中嵌入C或C++指针的适当结构。
IplImage*
指针是资源对象的完美候选对象。您可能不需要frame\t
类型,因为您可以简单地将指针投射到IplImage**
。cleanup函数应该释放内存,并且在您的示例中调用
由于指针是不透明的,因此需要移植访问器函数以向Erlang提供数据。这实际上取决于要从图像中提取的数据类型。例如,您可以移植函数并使用将数据从CvMat*
转换为erlang二进制文件
另外,作为补充说明,您应该调用存根函数,而不是返回列表“NIF library not loaded”
移植API(如OpenCV的High GUI)的正确方法是使用外部驱动程序(或C节点)
有几个原因,包括:
- NIF调用应该很快返回(调用
cvWaitKey
不适合NIF,并且计算时间太长),否则会混淆调度程序李>
- 使用NIF或链接的in驱动程序,内存管理会直接影响Erlang的虚拟机,任何崩溃都会导致整个Erlang节点崩溃
外部驱动程序是一个从stdin
(通常)获取数据并在stdout
上回复的过程。这是非常简单的设计,在C或C++。您可以移植OpenCV的API,也可以根据需要移植更复杂的函数。在这种情况下,诸如IplImage*
之类的指针可以作为4或8字节的不透明序列传输,或者作为参考号传输,前提是您维护Erlang已分配的所有IplImage*
指针的列表。然而,与NIFs不同的是,没有资源对象,您必须设计Erlang端代码以确保正确释放内存
您将在中找到更多信息和示例代码
另请参见此问题:我认为您对我的代码中的详细信息非常关注,这里对其进行了简化,因此更易于阅读。我当然已经阅读了您建议的文档。相信我,我正在为此工作一段时间,而不仅仅是在这里发布一些东西。谢谢你的回复
g++ -fPIC -shared -o niftest.so niftest.cpp -lopencv_core -lopencv_imgproc -lopencv_highgui -I /usr/lib64/erlang/usr/include/