当使用海康工业相机SDK时,调用其枚举接口然后打开相机时,会有出现一个问题,打开顺序是固定的,如果更换相机,相机的顺序又会出现变化,总结下规律,可以发现,其顺序是根据相机出厂序列号从小到大来的;
但是,对于使用者来讲,还是会有个很尴尬的问题,多相机,在设备安装时,肯定不可能严格按照序列号大小依次安装,总会出现乱序的情况,那么怎样才能顺风顺水的打开我想要的相机呢
SDK调用的第一步,通常是枚举相机,那么枚举出来的信息,都在相机结构体 MV_CC_DEVICE_INFO_LIST
里面,我们通过去改变结构体里面的排序,自然就可以改变打开顺序设备信息结构体
/// \~chinese 设备信息列表 \~english Device Information List
typedef struct _MV_CC_DEVICE_INFO_LIST_
{
unsigned int nDeviceNum; ///< [OUT] \~chinese 在线设备数量 \~english Online Device Number
MV_CC_DEVICE_INFO* pDeviceInfo[MV_MAX_DEVICE_NUM]; ///< [OUT] \~chinese 支持最多256个设备 \~english Support up to 256 devices
}MV_CC_DEVICE_INFO_LIST;
/// \~chinese 设备信息 \~english Device info
typedef struct _MV_CC_DEVICE_INFO_
{
unsigned short nMajorVer; ///< [OUT] \~chinese 主要版本 \~english Major Version
unsigned short nMinorVer; ///< [OUT] \~chinese 次要版本 \~english Minor Version
unsigned int nMacAddrHigh; ///< [OUT] \~chinese 高MAC地址 \~english High MAC Address
unsigned int nMacAddrLow; ///< [OUT] \~chinese 低MAC地址 \~english Low MAC Address
unsigned int nTLayerType; ///< [OUT] \~chinese 设备传输层协议类型 \~english Device Transport Layer Protocol Type
unsigned int nReserved[4]; ///< \~chinese 预留 \~english Reserved
union
{
MV_GIGE_DEVICE_INFO stGigEInfo; ///< [OUT] \~chinese GigE设备信息 \~english GigE Device Info
MV_USB3_DEVICE_INFO stUsb3VInfo; ///< [OUT] \~chinese USB设备信息 \~english USB Device Info
MV_CamL_DEV_INFO stCamLInfo; ///< [OUT] \~chinese CameraLink设备信息 \~english CameraLink Device Info
// more ...
}SpecialInfo;
}MV_CC_DEVICE_INFO;
/// \~chinese GigE设备信息 \~english GigE device info
typedef struct _MV_GIGE_DEVICE_INFO_
{
unsigned int nIpCfgOption; ///< [OUT] \~chinese IP配置选项 \~english IP Configuration Options
unsigned int nIpCfgCurrent; ///< [OUT] \~chinese 当前IP配置 \~english IP Configuration:bit31-static bit30-dhcp bit29-lla
unsigned int nCurrentIp; ///< [OUT] \~chinese 当前IP地址 \~english Current Ip
unsigned int nCurrentSubNetMask; ///< [OUT] \~chinese 当前子网掩码 \~english Curtent Subnet Mask
unsigned int nDefultGateWay; ///< [OUT] \~chinese 当前网关 \~english Current Gateway
unsigned char chManufacturerName[32]; ///< [OUT] \~chinese 制造商名称 \~english Manufacturer Name
unsigned char chModelName[32]; ///< [OUT] \~chinese 型号名称 \~english Model Name
unsigned char chDeviceVersion[32]; ///< [OUT] \~chinese 设备版本 \~english Device Version
unsigned char chManufacturerSpecificInfo[48]; ///< [OUT] \~chinese 制造商的具体信息 \~english Manufacturer Specific Information
unsigned char chSerialNumber[16]; ///< [OUT] \~chinese 序列号 \~english Serial Number
unsigned char chUserDefinedName[16]; ///< [OUT] \~chinese 用户自定义名称 \~english User Defined Name
unsigned int nNetExport; ///< [OUT] \~chinese 网口IP地址 \~english NetWork IP Address
unsigned int nReserved[4]; ///< \~chinese 预留 \~english Reserved
}MV_GIGE_DEVICE_INFO;
实现方法:
第一步:枚举相机信息:
// ch:枚举设备 | Enum device
MV_CC_DEVICE_INFO_LIST stDeviceList;
memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
if (MV_OK != nRet)
{
printf("Enum Devices fail! nRet [0x%x]\n", nRet);
break;
}
第二步:根据相机IP大小,从小到大重新排序(如果想根据其他信息排序,if的判断语句就应该做对应修改,例如,改成chUserDefinedName、序列号等)
for (int i = 0; i < psDevlist->nDeviceNum; i++)
{
for (int j = 0; j < psDevlist->nDeviceNum-i-1; j++)
{
//USB相机,SpecialInfo.stGigEInfo就需要变成SpecialInfo.stUSBInfo,换成其他设备信息来排序
if(psDevlist->pDeviceInfo[j]->SpecialInfo.stGigEInfo.nCurrentIp > psDevlist->pDeviceInfo[j+1]->SpecialInfo.stGigEInfo.nCurrentIp)
{
MV_CC_DEVICE_INFO* temp = psDevlist->pDeviceInfo[j];
psDevlist->pDeviceInfo[j]=psDevlist->pDeviceInfo[j+1];
psDevlist->pDeviceInfo[j+1]=temp;
}
}
}
第三步:正常打开就行
完整代码如下:
//------------------根据ip大小修改默认排序-----------------------
int EnumDeviceBycuirentIp(IN unsigned int nTLayerType,IN OUT MV_CC_DEVICE_INFO_LIST*psDevlist)
{
int nRet = MV_CC_EnumDevices(nTLayerType,psDevlist);
if (MV_OK != nRet)
{
printf("Enum Devices fail! nRet [0x%x]\n", nRet);
return nRet;
}
for (int i = 0; i < psDevlist->nDeviceNum; i++)
{
for (int j = 0; j < psDevlist->nDeviceNum-i-1; j++)
{
if(psDevlist->pDeviceInfo[j]->SpecialInfo.stGigEInfo.nCurrentIp > psDevlist->pDeviceInfo[j+1]->SpecialInfo.stGigEInfo.nCurrentIp)
{
MV_CC_DEVICE_INFO* temp = psDevlist->pDeviceInfo[j];
psDevlist->pDeviceInfo[j]=psDevlist->pDeviceInfo[j+1];
psDevlist->pDeviceInfo[j+1]=temp;
}
}
}
return nRet;
}
//-------------------主函数部分----------------------------------
// ch:枚举设备 | en:Enum device
MV_CC_DEVICE_INFO_LIST stDeviceList;
memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
unsigned int nTLayerType=MV_GIGE_DEVICE;
MV_CC_DEVICE_INFO_LIST *psDevlist;
nRet = EnumDeviceBycuirentIp(nTLayerType,&stDeviceList);
if (MV_OK != nRet)
{
printf("Enum Devices fail! nRet [0x%x]\n", nRet);
return nRet;
}
if (stDeviceList.nDeviceNum > 0)
{
for (unsigned int i = 0; i < stDeviceList.nDeviceNum; i++)
{
printf("[device %d]:\n", i);
MV_CC_DEVICE_INFO* pDeviceInfo = stDeviceList.pDeviceInfo[i];
if (NULL == pDeviceInfo)
{
break;
}
PrintDeviceInfo(pDeviceInfo);
}
}
else
{
printf("Find No Devices!\n");
break;
}
前面讲了,我们可以根据相机信息结构体中设备信息,重新修改排序,那么应该可以做一个简单的循环,比对信息来打开我指定的相机,如下,指定打开一个命名叫“CCDName”的相机
实现方法:
int nRet = 0;
char* ccdName={"CCDName"};
int nDeviceNum = -1;
unsigned int VersionSDK = MV_CC_GetSDKVersion();
MV_CC_DEVICE_INFO_LIST stDeviceList;
memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
if (MV_OK != nRet)
{
printf("MV_CC_EnumDevices fail! nRet %x\n", nRet);
return nRet;
}
if (stDeviceList.nDeviceNum < 0)
{
return -1;
}
for (unsigned int i = 0; i < stDeviceList.nDeviceNum; i++)
{
if (stDeviceList.pDeviceInfo[i]->nTLayerType == MV_GIGE_DEVICE)
{
if (strcmp((const char*)stDeviceList.pDeviceInfo[i]->SpecialInfo.stGigEInfo.chUserDefinedName, ccdName)==0)
{
nDeviceNum = i;
printf("Gige_devicen_nDeviceNum %d\n", nDeviceNum);
}
}
else if (stDeviceList.pDeviceInfo[i]->nTLayerType == MV_USB_DEVICE)
{
if (strcmp((const char*)stDeviceList.pDeviceInfo[i]->SpecialInfo.stUsb3VInfo.chUserDefinedName, ccdName)==0)
{
nDeviceNum = i;
printf("USB_devicen_DeviceNum %d\n", nDeviceNum);
}
}
continue;
}
if (nDeviceNum < 0)
{
return -1;
}
nRet = MV_CC_CreateHandle(&handle, stDeviceList.pDeviceInfo[nDeviceNum]);
if (MV_OK != nRet)
{
printf("Camera;%s->MV_CC_CreateHandle fail! nRet %x\n", ccdName, nRet);
return nRet;
}
nRet = MV_CC_OpenDevice(handle);
if (MV_OK != nRet)
{
printf("Camera;%s->MV_CC_OpenDevice fail! nRet %x\n",ccdName,nRet);
return nRet;
}
既然我们对相机信息结构体有了一定了解,那么为啥不能自己向里面填充信息呢
下面的代码就是自己填写ip地址,打开固定ip地址的相机,用这种方法呢,可以跳过枚举接口,直接获取信息创建句柄
//指定网卡ip,相机ip打开相机,需注意,不要写错ip地址,否则会报错206问题
int nRet = 0;
int nDeviceNum = -1;
MV_CC_DEVICE_INFO stDevInfo = { 0 };
MV_GIGE_DEVICE_INFO stGigEDev = { 0 };
stGigEDev.nNetExport = 0x0a403951;//网卡ip地址 10.64.57.81
stGigEDev.nCurrentIp = 0x0a40395b;//相机ip地址 10.64.57.91
stDevInfo.nTLayerType = MV_GIGE_DEVICE;// ch:仅支持GigE相机 | en:Only support GigE camera
stDevInfo.SpecialInfo.stGigEInfo = stGigEDev;
nRet = MV_CC_CreateHandle(&handle, &stDevInfo);
if (MV_OK != nRet)
{
printf("MV_CC_CreateHandle fail! nRet [%x]\n", nRet);
return -1;
}
nRet = MV_CC_GetDeviceInfo(handle, &stDevInfo);//补全设备信息
if (nRet != MV_OK)
{
MV_CC_DestroyHandle(handle);
handle = NULL;
return false;
}
nRet = MV_CC_OpenDevice(handle);
if (MV_OK != nRet)
{
printf("MV_CC_OpenDevice fail! nRet %x\n", nRet);
return nRet;
}
以上三种方法,实测可行,如果有更多的方法与思路,可以评论交流