Does anyone know if the Oak-D Pro PoE (or any of the Oak cameras) would be compatible with MVTec Halcon?

Halcon does support the following interfaces:

  • GenICam
  • GigE Vision
  • USB3 Vision
  • CoaXPress
  • Camera Link

It's possible I'm just blind, but I'm having difficulty finding specifics about the OAK-D communication standards.

    Hi dschroeder
    Not familar with Halcon or how it operates. It likely won't work out of the box since OAK devices all use the depthai API to communicate and stream video. You could perhaps use UVC mode (making the device work as a USB camera).

    Thoughts?

    Thanks,
    Jaka

    Hey @jakaskerl thanks for the reply.

    When used in UVC mode, I'm guessing it only uses one of the camera inputs instead of both? Can 3d vision still be gotten through UVC?

      Hi dschroeder
      I'll try if it was implemented in the firmware. Will report back.

      Thanks,
      Jaka

      3 months later

      @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

      1. Embedded Halcon within our application(s) using HDevEngineCpp
      2. 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;
      }

      Thanks @alex_007! I'm pretty inexperienced with c++, but I think I get the gist. Using the HDevEngine over creating a framegrabber certainly makes sense.