2013-09-24 4 views
0

Я пытаюсь использовать openCV с Erlang NIF. Итак, я хочу сделать основную вещь, и это просто, чтобы прочитать картинку и отправить указатель на erlang. и быть в состоянии снова отправить обратно указатель, полученные на C и просто показать ПИКВозвращающий указатель изображения на Erlang

так 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/ 

, а затем запустить Эрланг оболочку и вызвать Init и get_pic функцию

ответ

1

НИФ является неправильным решением сильноточного порта OpenCV в графический интерфейс уровня.

Тем не менее, чтобы ответить на ваш вопрос: по-видимому, пустой двоичный код в кортеже {ok, <<>>}, который вы получаете, непрозрачен от Erlang. Это объект ресурсов , как описано в справочной странице erl_nif.

Ресурсные объекты являются сборщиками мусора. Если никакой процесс не относится к данному ресурсу, будет вызвана функция очистки. Они, как правило, являются правильной структурой для встраивания указателей C или C++ в ваш NIF.

IplImage* Указатель является идеальным кандидатом на объект ресурса. Вам, вероятно, не нужен тип frame_t, так как вы можете просто наложить указатель на IplImage**. Функция очистки должна освобождать память, а в вашем примере - cvReleaseImage.

Поскольку указатель непрозрачен, вам необходимо выполнить функции доступа к портам для предоставления данных в Erlang. Это действительно зависит от типа данных, которые вы хотели бы извлечь из изображения. Например, вы можете перенести функцию cvEncodeImage и преобразовать данные из CvMat* в бинарник erlang, используя enif_make_binary.

Кроме того, в качестве примечания стороны вместо того, чтобы возвращать список "NIF library not loaded", вы должны позвонить erlang:nif_error/1,2 в функции заглушки.

Правильный подход к порту АНИ, такие как High GUI OpenCV в бы внешний драйвер (или С-узел).

Есть несколько причин, в том числе:

  • NIF вызовы должны быстро вернуться (вызов cvWaitKey является плохим кандидатом на NIF, а также вычисления слишком долго), так как они могли бы запутать планировщик;
  • с NIF или подключенным драйвером, управление памятью напрямую влияет на виртуальную машину Erlang, и любой сбой приведет к удалению всего узла Erlang.

внешний драйвер представляет собой процесс, который получает данные от stdin (обычно) и отвечает на stdout. Это очень просто для проектирования на C или C++. Вы можете либо загрузить API OpenCV, либо более сложные функции в зависимости от ваших потребностей. В этом случае указатели, такие как IplImage*, могут быть переданы в виде непрозрачной серии из 4 или 8 байтов или в качестве ссылочного номера при условии, что вы сохраните список всех указателей IplImage*, которые выделил Эрланг. Однако, в отличие от NIF, объект ресурсов отсутствует, и вам нужно будет разработать свой код на стороне Erlang, чтобы обеспечить правильную передачу памяти.

Более подробную информацию и код примера вы найдете в Interoperability Tutorial User's Guide.

Смотрите также вопрос: OpenCV on Erlang

+0

Я думаю, что вы заплатили слишком много внимания к деталям в моем коде, это упрощено здесь так будет легче read.I иметь, конечно, читать документы, которые вы предложили. поверь мне, я работаю над этим некоторое время, а не просто размещаю что-то здесь. Спасибо за ваш ответ – Khashayar

Смежные вопросы