Просмотр исходного кода

编写大华相机模块代码

niujiuru 2 месяцев назад
Родитель
Сommit
19a8dead07
2 измененных файлов с 265 добавлено и 0 удалено
  1. 209 0
      dh_takephoto/takephoto.c
  2. 56 0
      dh_takephoto/takephoto.h

+ 209 - 0
dh_takephoto/takephoto.c

@@ -0,0 +1,209 @@
+#include "takephoto.h"
+
+// 模块名称
+static const char MODULE_NAME[] = "TakePhoto";
+
+// 相机类型
+static unsigned int device_type =  interfaceTypeGige | interfaceTypeUsb3;
+
+// 制造厂商
+static const char * const manufacturer = "Huaray Technology";
+
+// 触发模式
+static const char * const setTriggerMode = "On"; /// 默认: 打开,  可关闭: "Off"
+
+// 曝光取图
+#define AE_WAIT_MAX_MS     180000 // 最大曝光稳定等待的时间, 默认3分钟, 单位: ms
+#define AE_EXP_TIME_EPS_US     50 // 曝光时间稳定判定的误差, 防抖&区间, 单位: us
+#define AE_EXP_STABLE_FRAMES    4 // 相机处于自动曝光模式时, 累计曝光值稳定的帧数
+
+// 保存照片
+
+// 拍照回调
+typedef struct
+{
+  HANDLE      hCam;           // 打开相机的句柄
+  uint32_t    camType;        // 相机类型:U、网
+  char manuName[MAX_LINE_CHARS]; //制造厂商名称
+  DHImgType    saveImgType;   // 保存图像的类型
+  const char *saveImgPath;    // 保存图像的路径
+  bool        isExposureAuto; // 自动曝光:是/否
+  struct timespec expTime0;   // 曝光开始的时间
+  float       lastExpTime;    // 上次的曝光时长(us)
+  int         expStableCnt;   // 连续曝光稳定帧计数
+  HANDLE      hESig;          // 任务结束的通知
+  int         rCode;          // 任务结束返回值
+} PthotoProcCtx;
+
+// 非标准的"Huaray Technology"制造商名称, 但也是华睿的相机, 如: "Machine Vision"
+static const char * const huaray_manu_aliases[] = { "Machine Vision", NULL };
+static bool is_huaray_manu_alias(const char *name)
+{
+  for(int i = 0; i < huaray_manu_aliases[i] != NULL; i++)
+  {
+    if(xstrcasecmp(name, huaray_manu_aliases[i]) == 0) return true;
+  }
+  return false;
+}
+
+// 单次执行相机拍照, 并保存到文件, 成功返回: 0值, 失败返回:非0值
+// "imgType"     - 获取图像类型
+// "saveImgPath" - 保存的文件名
+// "timeout"     - 等待超时时间, 单位:秒: < 0 表示无超时;
+//                 无论超时怎么设置, 首次尝试拍照一定会执行
+//                 , 但时间不确定; 拍照成功、超时或发生错误
+//                 时会自动结束任务(相机持续无数据的时间).
+// "pImgMark"    - 输出本次拍照图像的水印信息, 可以设置NULL
+int DH_TakePhoto(DHImgType imgType, const char *saveImgPath, int timeout, DHImgMark *pImgMark)
+{
+  int fd; char runDir[MAX_PATH_CHARS] = { 0 }, lockFile[MAX_PATH_CHARS+32] = { 0 };
+  int ret, index = 0; DHImgMark imgMark = { 0 }; HANDLE hCam = NULL; PthotoProcCtx ctx = { 0 };
+  IMV_DeviceList devList = { 0 }; IMV_DeviceInfo *pDevInfo = NULL; IMV_String exposureMode =  { 0 };
+
+  // 1, 占用锁定, 避免同时间拍照
+  xGetSelfRunningInfo(runDir, NULL);
+  if(runDir[strlen(runDir)-1] == '/') sprintf(lockFile, "%s%s", runDir, "status/");
+  else sprintf(lockFile, "%s/%s", runDir, "status/");
+  if(!sw_dir_exists(lockFile)) sw_dir_create(lockFile);
+  strcat(lockFile, "dh_takephoto.lock");
+
+  fd = open(lockFile, O_CREAT | O_RDWR | __O_CLOEXEC, 0666);
+  if(-1 == fd) { return -1; }
+
+  if(-1 == flock(fd, LOCK_EX | LOCK_NB)) { close(fd); return -2; }
+
+  // 2, 查找相机, 获取其设备信息
+  ret = IMV_EnumDevices(&devList, device_type);
+  if(IMV_OK != ret)
+  {
+    sw_log_error("[%s] 枚举相机,执行错误, errCode=%d!!", MODULE_NAME, ret);
+    goto end_p;
+  }
+  if(devList.nDevNum < 1)
+  {
+    ret = -3;
+    sw_log_error("[%s] 没有相机,数量=%u!!", MODULE_NAME, devList.nDevNum);
+    goto end_p;
+  }
+
+findp:
+  pDevInfo = &devList.pDevInfo[index++];
+  if(!pDevInfo)
+  {
+    ret = -4;
+    sw_log_error("[%s] unexpected internal error, failed to obtain camera information!!", MODULE_NAME);
+    goto end_p;
+  }
+
+  if(pDevInfo->nCameraType == typeU3vCamera) ctx.camType = interfaceTypeUsb3;
+  else if(pDevInfo->nCameraType == typeGigeCamera) ctx.camType = interfaceTypeGige;
+  else { // SDK出错, 我只枚举了U口和G口相机, 不可能出现其他类型
+    ret = -5;
+    sw_log_error("[%s] unexpected internal error, unknown camera type(%u)!!", MODULE_NAME, pDevInfo->nCameraType);
+    goto end_p;
+  }
+  strcpy(ctx.manuName, pDevInfo->vendorName);
+  strcpy(imgMark.camModelName, pDevInfo->modelName);
+  strcpy(imgMark.camSerialNum, pDevInfo->serialNumber);
+
+  if(xstrcasecmp(ctx.manuName, manufacturer) != 0 && !is_huaray_manu_alias(ctx.manuName))
+  {
+    if(index < devList.nDevNum) goto findp;
+    ret = -6;
+    sw_log_error("[%s] 没有找到 \"%s\" 的相机!!", MODULE_NAME, manufacturer);
+    goto end_p;
+  }
+
+  // 3, 打开相机, 设置其触发模式
+  unsigned int cameraIndex = (index - 1);
+  ret = IMV_CreateHandle(&hCam, modeByIndex, (void*)&cameraIndex);
+  if(IMV_OK == ret) ret = IMV_Open(hCam);
+  if(IMV_OK != ret)
+  {
+    sw_log_error("[%s] 打开相机时发生错误, errCode=%d!!", MODULE_NAME,  ret);
+    goto end_p;
+  }
+
+  if(IMV_OK == ret && xstrcasecmp(setTriggerMode, "On") == 0) ret = IMV_SetEnumFeatureSymbol(hCam, "TriggerSelector", "FrameStart"); // 设置触发条件
+  if(IMV_OK == ret && xstrcasecmp(setTriggerMode, "On") == 0) ret = IMV_SetEnumFeatureSymbol(hCam, "TriggerSource", "Software");     // 设置软件触发
+  if(IMV_OK == ret) ret = IMV_SetEnumFeatureSymbol(hCam, "TriggerMode", setTriggerMode); // 设置触发模式
+  if(IMV_OK != ret)
+  {
+    sw_log_error("[%s] 设置相机时发生错误, errCode=%d!!", MODULE_NAME,  ret);
+    goto end_p;
+  }
+
+  // 4, 开始拍照, 等待完成后输出
+
+  // 5, 成功拍照, 输出相机的信息
+
+  // 6, 任务结束, 释放相关的资源
+end_p:
+  if(hCam)
+  {
+    IMV_StopGrabbing(hCam);
+    IMV_Close(hCam);
+    IMV_DestroyHandle(hCam);
+  }
+
+  flock(fd, LOCK_UN);
+  close(fd);
+  sw_file_delete(lockFile);
+
+  return ret;
+}
+
+// 获取系统当前USBFS内存大小(MB), 成功返回: >=0, 失败返回: <0值
+int DH_GetSysUsbfsMemCurrentSize()
+{
+  const char *usbfsFile = "/sys/module/usbcore/parameters/usbfs_memory_mb";
+  char buf[MAX_LINE_CHARS]; int val = -1;
+  FILE *fp = fopen(usbfsFile, "r");
+  if(fp)
+  {
+    if(fgets(buf, sizeof(buf), fp)) sscanf(buf, "%d", &val);
+    fclose(fp);
+  }
+  return val;
+}
+
+// 设置系统新的USBFS内存大小(MB), 成功返回: 0值, 失败返回: <0值
+int DH_SetSysUsbfsMemSize(int val)
+{
+  const char *usbfsFile = "/sys/module/usbcore/parameters/usbfs_memory_mb";
+  char buf[MAX_LINE_CHARS]; sprintf(buf, "%d\n", val);
+  if(val >= 0 && sw_file_update(usbfsFile, "w", buf, strlen(buf)) == strlen(buf)) return 0;
+  else return -1;
+}
+
+// 获取当前已连接的海康相机的数量, 成功返回: >=0, 失败返回: <0值
+int DH_GetCameraCount()
+{
+  IMV_DeviceList devList = { 0 };
+  int ret;
+
+  ret = IMV_EnumDevices(&devList, device_type);
+  if(IMV_OK != ret)
+  {
+    sw_log_error("[%s] 枚举相机,执行错误, errCode=%d!!", MODULE_NAME, ret);
+    return -1;
+  }
+
+  ret = devList.nDevNum;
+
+  if(ret > 0)
+  {
+    int index = 0, cnt = 0; IMV_DeviceInfo *pDevInfo; char name[MAX_LINE_CHARS];
+findp:
+    pDevInfo = &devList.pDevInfo[index++];
+
+    name[0] = '\0';
+    if(pDevInfo && (pDevInfo->nCameraType == typeU3vCamera || pDevInfo->nCameraType == typeGigeCamera)) strcpy(name, pDevInfo->vendorName);
+
+    if(xstrcasecmp(name, manufacturer) == 0 || is_huaray_manu_alias(name)) cnt++;
+    if(index < devList.nDevNum) goto findp;
+    else ret = cnt;
+  }
+
+  return ret;
+}

+ 56 - 0
dh_takephoto/takephoto.h

@@ -0,0 +1,56 @@
+// Author: NiuJiuRu
+// Email: niujiuru@qq.com
+// Date: 2026-01-14 【新增支持大华相机】
+#ifndef __DH_TAKEPHOTO_H__
+#define __DH_TAKEPHOTO_H__
+
+#include "./include/IMVApi.h"
+#include "../swapi/include_swapiLib.h"
+
+#undef  MAX_LINE_CHARS
+#define MAX_LINE_CHARS IMV_MAX_STRING_LENTH // ☝
+
+// 图像水印
+typedef struct
+{
+  char camModelName[MAX_LINE_CHARS]; // 相机型号名
+  char camSerialNum[MAX_LINE_CHARS]; // 相机序列号
+  float imgExposureTime; // 拍照曝光时间, 单位: us
+} DHImgMark;
+
+// 图像类型
+typedef enum
+{
+  IMG_TYPE_BMP = 1, // 拍照输出".bmp"格式的图像文件
+	IMG_TYPE_JPG = 2, // 拍照输出".jpg"格式的图像文件
+} DHImgType;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+// 获取系统当前USBFS内存大小(MB), 成功返回: >=0, 失败返回: <0值
+int DH_GetSysUsbfsMemCurrentSize();
+
+// 设置系统新的USBFS内存大小(MB), 成功返回: 0值, 失败返回: <0值
+int DH_SetSysUsbfsMemSize(int val);
+
+// 获取当前已连接的海康相机的数量, 成功返回: >=0, 失败返回: <0值
+int DH_GetCameraCount();
+
+// 单次执行相机拍照, 并保存到文件, 成功返回: 0值, 失败返回:非0值
+// "imgType"     - 获取图像类型
+// "saveImgPath" - 保存的文件名
+// "timeout"     - 等待超时时间, 单位:秒: < 0 表示无超时;
+//                 无论超时怎么设置, 首次尝试拍照一定会执行
+//                 , 但时间不确定; 拍照成功、超时或发生错误
+//                 时会自动结束任务(相机持续无数据的时间).
+// "pImgMark"    - 输出本次拍照图像的水印信息, 可以设置NULL
+int DH_TakePhoto(DHImgType imgType, const char *saveImgPath, int timeout, DHImgMark *pImgMark);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DH_TAKEPHOTO_H__ */