@dschroeder We used Halcon around the 2017-2018 time frame. You could probably prove me wrong, but per my experience, any device can be integrated with Halcon. We integrated with Halcon in the following two ways:
A) Embedded Halcon Engine
- Embedded Halcon within our application(s) using
HDevEngineCpp
- Package your image payload as
HalconCpp::HImage
this could be done for any of the OAK DepthAI image products (RGB, Mono, Depth Map, etc.). Consider the following example:
bool CHalconInterface::ExecuteProcessors(
uint8_t *pBuffer,
uint32_t width,
uint32_t height,
uint32_t size)
{
bool ret = true;
HalconCpp::HImage image;
try
{
image = HalconCpp::HImage("byte", width, (int)height, (void*)pBuffer);
}
catch (HOperatorException& e)
{
spdlog::error("Load Image Exception: {}",
std::string(e.ErrorMessage()));
return false;
}
catch (HTupleAccessException& e)
{
spdlog::error("Create Image Vector Accessor Exception: {}",
std::string(e.ErrorMessage()));
return false;
}
...
B) Luxonis Framegrabber
If you want to use your depth camera within HDevelop, you will need to create a framegrabber for the Luxonis depth camera. We abandoned the framegrabber pattern pretty quickly. It was much easier to manage application development using the embedded halcon engine(s). I have included an example of an old framegrabber below:
#include <Halcon.h>
#include <hlib/CIOFrameGrab.h>
typedef struct
{
/* Note: The following struct members will only be used once per board */
char DeviceName[MAX_STRING]; /* assign a name to each board */
INT4_8 DeviceId; /* some sort of handle (specific */
/* to the frame grabber API) */
HBYTE *BoardFrameBuffer[FG_MAX_BUFFERS];/* buffers assigned to board, */
/* i.e., to ALL TFGInstances */
HINT currBuffer; /* index of the active buffer */
HIMGCNT sizeBuffer; /* size of each buffer */
HINT refBuffer; /* number of references to the */
/* buffers (from TFGInstance(s) */
HINT refInst; /* number of instances assigned
to this board */
/* more examples: */
HBOOL doesPhysicalSubsampling;
HINT maxBitsPerChannel;
} BoardInfo;
typedef struct
{
H_pthread_mutex_t cancel_mutex;
BoardInfo *board; /* the 'physical' board this instance is */
/* attached to */
HBOOL busy; /* useful, if you plan to support asynchr. */
/* grabbing (is the last grab still running?) */
HINT instance; /* a useful backreference to the general HALCON */
/* instance information: The instance index */
/* (0 to FG_MAX_INST-1 ) */
INT4_8 maxAge; /* useful for async grabbing: timeout threshold */
/* for "images too old" */
HINT currBuffer;/* you probably use more than one buffer: Index */
/* of the active buffer */
#ifdef WIN32
struct _timeb grabStarted;/* just to check the timeout: the timestamp */
/* when the last grab was started */
#else
struct timeval grabStarted;/* the same for UNIX systems ... */
#endif
HBYTE *InstFrameBuffer[FG_MAX_BUFFERS]; /* buffers assigned to */
/* this instance */
HBOOL allocBuffer; /* TRUE <=> buffers are allocated per instance, */
/* not only references to the buffers in "board"*/
HBOOL volatileMode;/* TRUE <=> pass buffer memory directly to a */
/* HALCON image (possibly "overwriting" older */
/* images) */
/* more examples: */
INT4_8 grabTimeout; /* maximum time for aborting a pending grab */
HINT num_buffers; /* number of buffers to be used */
HBOOL start_async_after_grab_async; /* flag for grab_image_async */
/* example for using callback functions: */
HAcqCallback callbackFunction[FG_CALLBACK_NUM]; /* store application */
/* function pointers */
void *userContext[FG_CALLBACK_NUM]; /* store application user context */
} TFGInstance;
static FGClass *fgClass;
static TFGInstance FGInst[MAX_INSTANCES];
unsigned int g_imageHeight, g_imageWidth;
int g_cameraHandle;
sig_atomic_t opened = false;
void GetParamByName(char *pParam, Hcpar *pPar, int *pNumValues);
void SetParamByName(char *pParam, Hcpar *pPar, int numValues);
void newFrameCallback(int Handle, int EventType, void *Buffer, int Size)
{
int currBuffer = FGInst[0].currBuffer + 1;
if (currBuffer >= FG_MAX_BUFFERS)
{
currBuffer = 0;
}
memcpy(FGInst[0].InstFrameBuffer[currBuffer], Buffer, Size);
FGInst[0].currBuffer = currBuffer;
}
extern "C" Herror FGInfo(Hproc_handle proc_id, HINT queryType,
char **info, Hcpar **values, HINT *numValues)
{
return H_MSG_FAIL;
}
extern "C" Herror FGGetParam(Hproc_handle proc_id, FGInstance *fginst,
char *param, Hcpar *value, int *num)
{
if (g_cameraHandle < 0)
{
return H_MSG_FAIL;
}
GetParamByName(param, value, num);
return H_MSG_OK;
}
extern "C" Herror FGSetParam(Hproc_handle proc_id, FGInstance *fginst,
char *param, Hcpar *value, int num)
{
if (g_cameraHandle < 0)
{
return H_MSG_FAIL;
}
SetParamByName(param, value, num);
return H_MSG_OK;
}
extern "C" FGInstance **FGOpenRequest(Hproc_handle proc_id, FGInstance *fginst)
{
fginst->gen_pointer = (void*)&FGInst[0];
return (&(fgClass->instance[0]));
}
extern "C" Herror FOpen(Hproc_handle proc_id,FGInstance *fginst)
{
int retval;
g_cameraHandle = CustomCameraApi_DeviceOpen();
if (g_cameraHandle < 0)
{
printf("CustomCameraApi_DeviceOpen Failed: %d\n", g_cameraHandle);
return H_MSG_FAIL;
}
CustomCameraApi_GetImageHeight(g_cameraHandle, g_imageHeight);
CustomCameraApi_GetImageWidth(g_cameraHandle, g_imageWidth);
int size = g_imageHeight * g_imageWidth;
TFGInstance *currInst = (TFGInstance *)fginst->gen_pointer;
fginst->async_grab = FALSE;
fginst->bits_per_channel = 8;
fginst->num_channels = 1;
fginst->width_max = fginst->image_width = g_imageWidth;
fginst->height_max = fginst->image_height = g_imageHeight;
strcpy(fginst->color_space, "gray");
currInst->board = FGInst[0].board;
currInst->cancel_mutex = NULL;
currInst->busy = FALSE;
currInst->allocBuffer = FALSE;
currInst->currBuffer = 0;
currInst->volatileMode = FALSE;
currInst->num_buffers = FG_MAX_BUFFERS;
for (int i = 0; i < FG_MAX_BUFFERS; i++)
{
currInst->InstFrameBuffer[i] = (HBYTE*) malloc(size*2);
}
retval = CustomCameraApi_SetCallback(g_cameraHandle, EVENT_FRAME, newFrameCallback);
if (retval != 0)
{
printf("CustomCameraApi_SetCallback Failed: %d\n", retval);
return H_MSG_FAIL;
}
float fps;
CustomCameraApi_GetFrameRateMax(g_cameraHandle, fps);
printf("Camera old FPS: %f\n", fps);
//retval = CustomCameraApi_SetFrameRate(g_cameraHandle, 20.0);
retval = CustomCameraApi_SetFrameRate(g_cameraHandle, 60.0);
if (retval != 0)
{
printf("CustomCameraApi_SetFrameRate Failed: %d\n", retval);
return H_MSG_FAIL;
}
// retval = CustomCameraApi_SetExposureTime(g_cameraHandle, 16000);
retval = CustomCameraApi_SetExposureTime(g_cameraHandle, 2000);
if (retval != 0)
{
printf("CustomCameraApi_SetExposureTime Failed: %d\n", retval);
return H_MSG_FAIL;
}
UINT exposure;
CustomCameraApi_GetExposureTime(g_cameraHandle, exposure);
printf("New Exposure Time: %d\n", exposure);
retval = CustomCameraApi_AcquisitionStart(g_cameraHandle);
if (retval != 0)
{
printf("CustomCameraApi_AcquisitionStart Failed: %d\n", retval);
return H_MSG_FAIL;
}
return H_MSG_OK;
}
extern "C" Herror FClose(Hproc_handle proc_id,FGInstance *fginst)
{
int retval;
for (int i = 0; i < FG_MAX_BUFFERS; i++)
{
free(FGInst[0].InstFrameBuffer[i]);
}
retval = CustomCameraApi_AcquisitionStop(g_cameraHandle);
if (retval != 0)
{
printf("CustomCameraApi_AcquisitionStop Failed: %d\n", retval);
return H_MSG_FAIL;
}
CustomCameraApi_DeviceClose(g_cameraHandle);
return H_MSG_OK;
}
extern "C" Herror FGrab(Hproc_handle proc_id, FGInstance *fginst,
Himage *image, HINT *num_image)
{
uint size = g_imageHeight * g_imageWidth;
uint currBuffer = FGInst[0].currBuffer;
*num_image = 1;
HNewImage(proc_id, &image[0], BYTE_IMAGE, g_imageWidth, g_imageHeight);
memcpy((void*)image[0].pixel.b, FGInst[0].InstFrameBuffer[currBuffer], size);
return H_MSG_OK;
}
extern "C" Herror FGInit(Hproc_handle proc_id, FGClass *fg)
{
fg->interface_version = FG_INTERFACE_VERSION;
fg->available = TRUE;
fg->instances_num = 0;
fg->instances_max = MAX_INSTANCES;
fg->OpenRequest = FGOpenRequest;
fg->Open = FOpen;
fg->Close = FClose;
fg->Info = FGInfo;
fg->Grab = FGrab;
fg->GrabStartAsync = NULL;
fg->GrabAsync = NULL;
fg->GrabData = NULL;
fg->GrabDataAsync = NULL;
fg->SetParam = FGSetParam;
fg->GetParam = FGGetParam;
fg->SetLut = NULL;
fg->GetLut = NULL;
fg->SetCallback = NULL;
fg->GetCallback = NULL;
fg->horizontal_resolution = 2048; /* use camera default */
fg->vertical_resolution = 2048; /* use camera default */
fg->image_width = 2048;
fg->image_height = 2048;
fg->start_col = 2048;
fg->start_row = 2048;
fg->field = FG_FIELD_DEFAULT;
fg->bits_per_channel = 8;
strcpy(fg->color_space,"gray");
fg->gain = -1.0f; /* only for backwards compatibility */
fg->external_trigger = FALSE;
strcpy(fg->camera_type,"default");
strcpy(fg->device,"default");
fg->port = -1;
fg->line_in = -1;
fgClass = fg;
g_cameraHandle = -1;
return H_MSG_OK;
}