返回指向 Erlang 的图像指针



我正在尝试将openCV与Erlang NIF一起使用。所以我想做一件基本的事情,那就是阅读图片并将指针发回 erlang。并能够再次将收到的指针发回 C 并仅显示图片

所以最漂亮的.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, <<>>},指针根本不有效。

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

我做错了什么?我已经阅读了所有文档,但我真的无法弄清楚这一点。

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

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 函数,并使用 enif_make_binary 将数据从 CvMat* 转换为 erlang 二进制文件。

另外,作为旁注,您应该在存根函数中调用erlang:nif_error/1,2,而不是返回列表"NIF library not loaded"

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

有几个原因,包括:

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

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

您可以在互操作性教程用户指南中找到更多信息和示例代码。

另请参阅此问题:Erlang 上的 OpenCV

相关内容

  • 没有找到相关文章

最新更新