c++ - 将图像指针返回给 Erlang

标签 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;


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)

我的 niftest.erl 看起来像这样:

-module(niftest).

-compile(export_all).

init() ->
      erlang:load_nif("./niftest", 0).

get_pic() ->
      "NIF library not loaded".

show_pic(F) ->
      "NIF library not loaded".

所以现在的问题是,当我调用 get_pic 时,我得到的返回是 {ok, <<>>}并且指针根本无效。

当我 cout制作 enif_make_resource 之前的框架它有一个值,我可以看到它,但它返回给我的是空的!

我做错了什么? 我已经阅读了所有文档,但我真的想不通。

注意:您可以使用此命令编译代码:

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 来说是不透明的。这是一个资源对象,如erl_nif 中所述。手册页。

资源对象是垃圾收集器友好的。如果没有进程引用给定资源,将调用清理函数。它们通常是在 NIF 中嵌入 C 或 C++ 指针的正确结构。

IplImage*指针是资源对象的完美候选者。您可能不需要 frame_t类型,因为您可以简单地将指针转换为 IplImage** .清理函数应该释放内存,在你的例子中,调用 cvReleaseImage .

由于指针是不透明的,您需要移植访问器函数以向 Erlang 提供数据。这实际上取决于您想从图像中提取的数据类型。例如,您可以移植 cvEncodeImage函数并转换来自 CvMat* 的数据使用 enif_make_binary 到 erlang 二进制文件.

此外,作为旁注,不要返回列表 "NIF library not loaded" , 你应该调用 erlang:nif_error/1,2 在 stub 函数中。

移植 API(例如 OpenCV 的高级 GUI) 的正确方法是外部驱动程序(或 C 节点)。

有几个原因,包括:

  • NIF 调用应该快速返回(调用 cvWaitKey 不适合 NIF,而且计算时间太长),否则它们会混淆调度程序;
  • 使用 NIF 或链接驱动程序,内存管理直接影响 Erlang 的虚拟机,任何崩溃都会导致整个 Erlang 节点宕机。

外部驱动程序 是从stdin 获取数据的进程(通常)并回复 stdout .这在 C 或 C++ 中设计起来非常简单。您可以根据需要移植 OpenCV 的 API 或更复杂的函数。在这种情况下,诸如 IplImage* 之类的指针可以作为 4 或 8 字节的不透明系列传输,或者作为引用编号传输,前提是您维护所有 IplImage* 的列表。 Erlang 已经分配的指针。然而,与 NIF 不同的是,它没有资源对象,您必须设计 Erlang 端代码以确保正确释放内存。

您将在 Interoperability Tutorial User's Guide 中找到更多信息和示例代码.

另见这个问题:OpenCV on Erlang

关于c++ - 将图像指针返回给 Erlang,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18986874/

相关文章:

opencv - 在 OpenCV 中,CvMatND 结构用于什么?

c++ - 删除不同位置的指针会导致不同的行为(崩溃与否)

c++ - 仅用于 <char> 的模板化类型的附加构造函数

c++ - glReadPixels 始终在 glClearColor 中返回相同的值

python - 在 opencv python 中实现光流时选择我自己的点而不是角点

c - 段错误,尽管代码从未执行?

c++ - 指针索引 : Getting Unexpected Values

c++ - 使用 Eigen 创建具有俯仰、偏航、滚动的旋转矩阵

c# - 通过反射从 C# 访问 C++ 非成员函数

c# - 无法在OpenCV中分配字节