揭阳做网站,建设网站对于客户,手机产品网站建设,永川区门户网站建设轨迹前言#xff1a;
由于实验需要使用双目相机同步采集图像#xff0c;实验室准备的设备是海康威视的工业相机#xff0c;对其进行二次开发#xff0c;其中花了大部分时间查找资料#xff0c;以及代码进行反复调试#xff0c;最后到达了想要的效果#xff0c;并写博客记录…前言
由于实验需要使用双目相机同步采集图像实验室准备的设备是海康威视的工业相机对其进行二次开发其中花了大部分时间查找资料以及代码进行反复调试最后到达了想要的效果并写博客记录一下。
资料查找
首先是资料的查找我们要注意的是海康威视一共有两个官网一个是海康威视https://www.hikvision.com/cn/ 另一个是海康威视机器人https://www.hikrobotics.com/cn 由于我们的项目使用的是海康威视CH系列工业相机所以选择海康威视机器人官网。我们可以在官网找到相关的资料如下图所示 点击左侧的机器视觉
点击工业相机并找到自己使用的相机所对应的型号里面有参品的相关介绍、参数以及资料。 官方示例
在服务支持的下载中心里面有官方的工业相机的客户端MVS以及一些其他的安装包。 我的开发环境是ubuntu20.04所以选择下载对应的Linux客户端以及SDK开发包。 将下载的文件及解压即可。
环境配置
一、MVS安装 SDK有 5 个安装包分别对应的环境为x86_64 | i386 | armhf | aarch64 | arm-none在不同的硬件平台上选择不同的安装包安装。我使用的是Linux系统安装x86_64的文件就可以了我选择的。 安装步骤 安装 MVS 前需获取系统 root 权限: sudo su 或 su root。 提供两种打包方式的安装包 xxxx.deb 和 xxxx.tar.gz 。安装方式分别如下 a、安装 xxxx.deb 的安装包打开 MVS 安装包所在文件夹使用“ sudo dpkg -i xxxx.deb ”直接安装MVS客户端。 b、安装 xxxx.tar.gz 的安装包打开 MVS 安装包所在文件夹使用“ tar –xzvf xxxx.tar.gz ”对安装包进行解压打开解压后生成的文件夹运行安装脚本 “ source ./setup.sh “ 安装 MVS。 MVS安装在 opt/MVS 路径下安装完成后在 MVS文件夹中一般包含bin、doc、driver、include、lib、logserver、Samples等文件夹不同版本可能存在差异。 运行“/opt/MVS/bin/MVS.sh ”或者在/opt/MVS/bin 文件夹中运行“ ./MVS.sh ”测试 MVS 是否安装成功。
二、MVS开发目录介绍
MVS默认安装在 opt/MVS路径下安装完成后在MVS文件夹下包含目录结构如下: bin执行文件doc工业相机SDK相关文档driver Gige相机驱动安装IncludeSDK的头文件LibSDK的Lib文件logserver 日志服务Samples示例程序MVS客户端界面如下图由于写博客的时候没有连接相机看不到图像采集的画面。
这里有一个注意点我第一次安装的时候是打不开这个客户端的后面我在下载的SDK文件夹下/home/wk/下载/机器视觉工业相机SDK V3.2.0版本Runtime组件包Linux/MvCamCtrlSDK_Runtime-3.2.0_x86_64_20210915/data/opt运行了/setup.sh就可以用了具体是什么原因不知道我觉得应该是相机的一些驱动没有安装的原因。
项目开发
在安装完成之后我们可以进入到doc文件里面找到工业相机SDK的相关文档。具体操作如下 1.点击文件点击最下面的其他位置。 2.点击计算机然后找到opt文件然后进入MVS文件进入doc文件里面就能找到一个html文件打开该文件。 3.文件打开后如图所示
在这里面我们可以看到官方的一些示例教程在编程引导里面官方给出了采集图像的具体流程以及代码实现这个也是后面对相机同步采集编程的一个主要思想。 这里面还需要特别关注的有三个模块。 1.第一个是结构体的定义模块这里我们只需要在后面看官方的示例程序以及自己进行编程的时候查看对应的结构体的作用以及结构体所需要的参数。 2.第二个是官方的示例程序模块里面包含了官方实现相机的各种功能的代码点开之后也有相应功能的中文注释这里就不一一解释每个模块的作用了。 3.第三个是错误码模块里面有每一个错误码对应的含义这个对我们在代码的调试的时候是非常有帮助的可以在代码报错的时候快速定位我们的问题所在。 下面是采集图像的代码
单目采集
在单目采集里面首先我是写了两个询问的语句是否要进行标定图像的采集和连续采集图像。如果进行单目采集只需要按w就可以保存图像按q就可以退出然后按回车就可以关闭相机。在连续采集的时候按下y图像就会连续保存按q就额可以退出采集然后按回车就可以关闭相机。后面的双目采集也是如此。
#includestdio.h
#includeiostream
#includestring.h
#includeunistd.h
#includestdlib.h
#includepthread.h
#includetermio.h
#includefcntl.h
#includeMvCameraControl.h
#includetime.husing namespace std;
#define CAMERA_NUM 2
bool g_bExit false;
int GrabNum 10;
int nRet MV_OK;
void *handle NULL;
bool isCalib false,isSaveimg false;
char getcalibchar,getsavechar;bool PrintDeviceInfo(MV_CC_DEVICE_INFO *pstMVDevInfo);
void PressEnterToExit(void);
int kbhit(void);int SaveNum 0;
int SaveImageToFile(void* handle,unsigned char* p_BufAddr,unsigned short n_Width,unsigned short n_Height,enum MvGvspPixelType en_PixelType,unsigned int n_Framelen)
{int nRet MV_OK;MV_SAVE_IMAGE_PARAM_EX stSaveFileParam;memset(stSaveFileParam, 0, sizeof(MV_SAVE_IMAGE_PARAM_EX));stSaveFileParam.enImageType MV_Image_Bmp;stSaveFileParam.pData p_BufAddr;stSaveFileParam.nDataLen n_Framelen;stSaveFileParam.enPixelType en_PixelType;stSaveFileParam.nWidth n_Width;stSaveFileParam.nHeight n_Height;stSaveFileParam.nJpgQuality 80;stSaveFileParam.nBufferSize n_Framelen * 3 2048;unsigned char *pImage (unsigned char *)malloc(n_Framelen * 3 2048);stSaveFileParam.pImageBuffer pImage;char chImageNamel[256] {0};string folderPathl ../saveimg/0;string commandl;commandl mkdir -p folderPathl;system(commandl.c_str());if(isSaveimg || isCalib){nRet MV_CC_SaveImageEx2(handle, stSaveFileParam);if (nRet ! MV_OK){return nRet;}sprintf(chImageNamel,../saveimg/0/%06d.bmp, SaveNum);FILE *fp1 fopen(chImageNamel, wb);fwrite(pImage, 1, stSaveFileParam.nImageLen, fp1);fclose(fp1);return MV_OK;} return MV_OK;
}char m_Name[512] {0};
int doGrabImage(void* handle, MV_FRAME_OUT stOutFrame)
{int nRet MV_OK;nRet MV_CC_GetImageBuffer(handle, stOutFrame, 1000);if (nRet MV_OK){SaveImageToFile(handle,stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth,stOutFrame.stFrameInfo.nHeight,stOutFrame.stFrameInfo.enPixelType,stOutFrame.stFrameInfo.nFrameLen);nRet MV_CC_FreeImageBuffer(handle, stOutFrame);if (nRet ! MV_OK){return nRet;}return MV_OK;}return MV_OK;
}int main()
{coutDo you want to obtain images for calibration?[y/n]endl;cin getcalibchar;if(getcalibchar y || getcalibchar Y){isCalib true;}if(!isCalib){coutDo you want to save images continuously?[y/n]endl;cin getsavechar;if(getsavechar y || getsavechar Y){isSaveimg true;}else{return 0;}}MV_CC_DEVICE_INFO_LIST stDeviceList;//设备信息列表memset(stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));//初始化内存//枚举设备nRet MV_CC_EnumDevices(MV_USB_DEVICE, stDeviceList);//查找USB设备传入设备列表if(nRet ! MV_OK){cout MV_CC_EnumDevices fail! nRet [ nRet ] endl;return -1;}if(stDeviceList.nDeviceNum 0){for (int i 0; i stDeviceList.nDeviceNum;i){cout [device i ] endl;MV_CC_DEVICE_INFO *pDeviceInfo stDeviceList.pDeviceInfo[i];if(pDeviceInfo NULL){break;}PrintDeviceInfo(pDeviceInfo);}}else{cout Find No Devices! endl;return -1;}cout Plsase Input camera index: endl;unsigned int nIndex 0;//无符整型只能取正数作为相机索引cin nIndex;if(nIndex stDeviceList.nDeviceNum){cout Input error! endl;return 0;}//选择设备并创建句柄nRet MV_CC_CreateHandle(handle, stDeviceList.pDeviceInfo[nIndex]);if(nRet ! MV_OK){cout MV_CC_CreateHandle fail! nRet [ nRet ] endl;MV_CC_DestroyHandle(handle);return -1;}//打开设备nRet MV_CC_OpenDevice(handle);if(nRet ! MV_OK){cout MV_CC_OpenDevice fail! nRet [ nRet ] endl;MV_CC_DestroyHandle(handle);return -1;}// 设置触发模式为on// nRet MV_CC_SetEnumValue(handle, TriggerMode, MV_TRIGGER_MODE_ON);// if(nRet ! MV_OK)// {// cout MV_CC_SetTriggerMode fail! nRet [ nRet ] endl;// return 0;// }//设置触发模式为offnRet MV_CC_SetEnumValue(handle, TriggerMode, MV_TRIGGER_MODE_OFF);if(nRet ! MV_OK){cout Cam[0]:MV_CCSetTriggerMode fail! nRet [ nRet ] endl;}//设置触发源// nRet MV_CC_SetEnumValue(handle, TriggerSource, MV_TRIGGER_SOURCE_LINE0);// if(nRet ! MV_OK)// {// cout MV_CC_SetTriggerMode fail! nRet [ nRet ] endl;// return 0;// }//开始取流nRet MV_CC_StartGrabbing(handle);if(nRet ! MV_OK){cout Cam[0]:MV_CC_StartGrabbing fail! nRet [ nRet ] endl;return -1;}MV_FRAME_OUT stOutFrame {0};memset(stOutFrame, 0, sizeof(MV_FRAME_OUT));while(1){if(isCalib kbhit()){char ch getchar();cout Plase press w or W to save images or press q or Q to quit!endl;if (ch w||ch W) {nRet doGrabImage(handle, stOutFrame);if(nRet ! MV_OK){cout Cam[0]:doGrabImage failed! [ nRet ] endl;}SaveNum;}if (ch q||ch Q)break;}if(isSaveimg){nRet doGrabImage(handle, stOutFrame);if(nRet ! MV_OK){cout Cam[0]:doGrabImage failed! [ nRet ] endl;}SaveNum;if (kbhit()) {char ch getchar();cout Plase press q or Q to quit!endl;if (ch q||ch Q)break;}}}cout Plase Press Enter to stop grabbing! endl;PressEnterToExit();//停止取流nRet MV_CC_StopGrabbing(handle);if(nRet ! MV_OK){cout MV_CC_StopGrabbing fail! nRet [ nRet ] endl;return -1;}// 关闭设备nRet MV_CC_CloseDevice(handle);if(nRet ! MV_OK){cout MV_CC_CloseDevice fail! nRet [ nRet ] endl;return -1;}//销毁句柄nRet MV_CC_DestroyHandle(handle);if(nRet ! MV_OK){cout MV_CC_CloseDevice fail! nRet [ nRet ] endl;return -1;}cout exit endl;return 0;
}bool PrintDeviceInfo(MV_CC_DEVICE_INFO *pstMVDevInfo)
{if(pstMVDevInfo NULL){cout The Pointer of pstMVDevInfo is NULL! endl;return false;}if(pstMVDevInfo-nTLayerType MV_USB_DEVICE){cout Device Model Name: pstMVDevInfo-SpecialInfo.stUsb3VInfo.chModelName endl;cout UserDefinedName: pstMVDevInfo-SpecialInfo.stUsb3VInfo.chUserDefinedName endl;}else{cout Not support. endl;}return true;
}void PressEnterToExit(void)
{int c;while((c getchar()) ! \n c ! EOF)fprintf(stderr, Press enter to exit.\n);while(getchar() ! \n)g_bExit true;sleep(1);
}int kbhit(void) {struct termios oldt, newt;int ch;int oldf;tcgetattr(STDIN_FILENO, oldt);newt oldt;newt.c_lflag ~(ICANON | ECHO);tcsetattr(STDIN_FILENO, TCSANOW, newt);oldf fcntl(STDIN_FILENO, F_GETFL, 0);fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);ch getchar();tcsetattr(STDIN_FILENO, TCSANOW, oldt);fcntl(STDIN_FILENO, F_SETFL, oldf);if (ch ! EOF) {ungetc(ch, stdin);return 1;}return 0;
}双目同步采集
双目和单目有一点不同使用双目相机采集的时候我们要求两个相机采集的图像是在同一时刻下进行采集的对于如何确定两个相机是否是同步采集呢我使用的方法是利用北京时间校准直接百度精确到毫秒对其进行拍照看左右相机得到的图片是否是一样的就可以了这里我使用的触发模式是外部硬件触发的模式使用相机的Line0作为硬件触发的信号源Line2使用不了不知道具体原因具体的原理可以看相机的使用手册下载方式在前面也有提到里面对相机的介绍都是非常完整的。具体实现代码如下
#includestdio.h
#includeiostream
#includestring.h
#includeunistd.h
#includestdlib.h
#includepthread.h
#includetermio.h
#includefcntl.h
#includeMvCameraControl.h
#includetime.husing namespace std;
#define CAMERA_NUM 2
bool g_bExit false;
int nRet MV_OK;
void *handle[CAMERA_NUM] {NULL};
bool isCalib false,isSaveimg false;
char getcalibchar,getsavechar;
int savenum10,savenum21;bool PrintDeviceInfo(MV_CC_DEVICE_INFO *pstMVDevInfo);
void PressEnterToExit(void);
int kbhit(void);int SaveNum 0;
int SaveImageToFile(void* handle,unsigned char* p_BufAddr,unsigned short n_Width,unsigned short n_Height,enum MvGvspPixelType en_PixelType,unsigned int n_Framelen,int n)
{int nRet MV_OK;MV_SAVE_IMAGE_PARAM_EX stSaveFileParam;memset(stSaveFileParam, 0, sizeof(MV_SAVE_IMAGE_PARAM_EX));stSaveFileParam.enImageType MV_Image_Bmp;stSaveFileParam.pData p_BufAddr;stSaveFileParam.nDataLen n_Framelen;stSaveFileParam.enPixelType en_PixelType;stSaveFileParam.nWidth n_Width;stSaveFileParam.nHeight n_Height;stSaveFileParam.nJpgQuality 80;stSaveFileParam.nBufferSize n_Framelen * 3 2048;unsigned char *pImage (unsigned char *)malloc(n_Framelen * 3 2048);stSaveFileParam.pImageBuffer pImage;char chImageNamel[256] {0};char chImageNamer[256] {0};string folderPathl ../saveimg/0;string folderPathr ../saveimg/1;string commandl,commandr;commandl mkdir -p folderPathl;commandr mkdir -p folderPathr;system(commandl.c_str());system(commandr.c_str());if(isSaveimg || isCalib){nRet MV_CC_SaveImageEx2(handle, stSaveFileParam);if (nRet ! MV_OK){return nRet;}sprintf(chImageNamel,../saveimg/%d/%06d.bmp,n, SaveNum);FILE *fp1 fopen(chImageNamel, wb);fwrite(pImage, 1, stSaveFileParam.nImageLen, fp1);fclose(fp1);return MV_OK;} return MV_OK;
}char m_Name[512] {0};
int doGrabImage(void* handle, MV_FRAME_OUT stOutFrame,int n)
{int nRet MV_OK;nRet MV_CC_GetImageBuffer(handle, stOutFrame, 1000);if (nRet MV_OK){SaveImageToFile(handle,stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth,stOutFrame.stFrameInfo.nHeight,stOutFrame.stFrameInfo.enPixelType,stOutFrame.stFrameInfo.nFrameLen,n);nRet MV_CC_FreeImageBuffer(handle, stOutFrame);if (nRet ! MV_OK){return nRet;}return MV_OK;}return MV_OK;
}int main()
{coutDo you want to obtain images for calibration?[y/n]endl;cin getcalibchar;if(getcalibchar y || getcalibchar Y){isCalib true;}if(!isCalib){coutDo you want to save images continuously?[y/n]endl;cin getsavechar;if(getsavechar y || getsavechar Y){isSaveimg true;}else{return 0;}}MV_CC_DEVICE_INFO_LIST stDeviceList;//设备信息列表memset(stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));//初始化内存//枚举设备nRet MV_CC_EnumDevices(MV_USB_DEVICE, stDeviceList);//查找USB设备传入设备列表if(nRet ! MV_OK){cout MV_CC_EnumDevices fail! nRet [ nRet ] endl;return -1;}unsigned int nIndex 0;//无符整型只能取正数作为相机索引if(stDeviceList.nDeviceNum 0){for (int i 0; i stDeviceList.nDeviceNum;i){cout [device i ] endl;MV_CC_DEVICE_INFO *pDeviceInfo stDeviceList.pDeviceInfo[i];if(pDeviceInfo NULL){break;}PrintDeviceInfo(pDeviceInfo);} }else{cout Find No Devices! endl;return -1;}if(stDeviceList.nDeviceNum CAMERA_NUM){cout only have stDeviceList.nDeviceNum camera endl;return -1;}//提示为多相机测试cout Start CAMERA_NUM camera Grabbing Image test endl;for (int i 0; i CAMERA_NUM;i){cout Please Input Camera Index:;cin nIndex;//选择设备并创建句柄nRet MV_CC_CreateHandle(handle[i], stDeviceList.pDeviceInfo[nIndex]);if(nRet ! MV_OK){cout MV_CC_CreateHandle fail! nRet [ nRet ] endl;MV_CC_DestroyHandle(handle[i]);return -1;}//打开设备nRet MV_CC_OpenDevice(handle[i]);if(nRet ! MV_OK){cout MV_CC_OpenDevice fail! nRet [ nRet ] endl;MV_CC_DestroyHandle(handle[i]);return -1;}}for (int i 0; i CAMERA_NUM;i){// 设置触发模式为onnRet MV_CC_SetEnumValue(handle[i], TriggerMode, MV_TRIGGER_MODE_ON);if(nRet ! MV_OK){cout MV_CC_SetTriggerMode fail! nRet [ nRet ] endl;break;}//设置触发模式为off// nRet MV_CC_SetEnumValue(handle[i], TriggerMode, MV_TRIGGER_MODE_OFF);// if(nRet ! MV_OK)// {// cout Cam[0]:MV_CCSetTriggerMode fail! nRet [ nRet ] endl;// }//设置触发源nRet MV_CC_SetEnumValue(handle[i], TriggerSource, MV_TRIGGER_SOURCE_LINE0);if(nRet ! MV_OK){cout MV_CC_SetTriggerMode fail! nRet [ nRet ] endl;break;}}//开始取流nRet MV_CC_StartGrabbing(handle[0]);if(nRet ! MV_OK){cout Cam[0]:MV_CC_StartGrabbing fail! nRet [ nRet ] endl;return -1;}nRet MV_CC_StartGrabbing(handle[1]);if(nRet ! MV_OK){cout Cam[1]:MV_CC_StartGrabbing fail! nRet [ nRet ] endl;return -1;}MV_FRAME_OUT stOutFrame {0};memset(stOutFrame, 0, sizeof(MV_FRAME_OUT));while(1){if(isCalib kbhit()){char ch getchar();cout Plase press w or W to save images or press q or Q to quit!endl;if (ch w||ch W) {nRet doGrabImage(handle[0], stOutFrame,savenum1);if(nRet ! MV_OK){cout Cam[0]:doGrabImage failed! [ nRet ] endl;}nRet doGrabImage(handle[1], stOutFrame,savenum2);if(nRet ! MV_OK){cout Cam[1]:doGrabImage failed! [ nRet ] endl;}SaveNum;}if (ch q||ch Q)break;}if(isSaveimg){nRet doGrabImage(handle[0], stOutFrame,savenum1);if(nRet ! MV_OK){cout Cam[0]:doGrabImage failed! [ nRet ] endl;}nRet doGrabImage(handle[1], stOutFrame,savenum2);if(nRet ! MV_OK){cout Cam[1]:doGrabImage failed! [ nRet ] endl;}SaveNum;if (kbhit()) {char ch getchar();cout Plase press q or Q to quit!endl;if (ch q||ch Q)break;}}}cout Plase Press Enter to stop grabbing! endl;PressEnterToExit();for (int i 0; i CAMERA_NUM;i){//停止取流nRet MV_CC_StopGrabbing(handle[i]);if(nRet ! MV_OK){cout MV_CC_StopGrabbing fail! nRet [ nRet ] endl;return -1;}// 关闭设备nRet MV_CC_CloseDevice(handle[i]);if(nRet ! MV_OK){cout MV_CC_CloseDevice fail! nRet [ nRet ] endl;return -1;}//销毁句柄nRet MV_CC_DestroyHandle(handle[i]);if(nRet ! MV_OK){cout MV_CC_CloseDevice fail! nRet [ nRet ] endl;return -1;}}cout exit endl;return 0;
}bool PrintDeviceInfo(MV_CC_DEVICE_INFO *pstMVDevInfo)
{if(pstMVDevInfo NULL){cout The Pointer of pstMVDevInfo is NULL! endl;return false;}if(pstMVDevInfo-nTLayerType MV_USB_DEVICE){cout Device Model Name: pstMVDevInfo-SpecialInfo.stUsb3VInfo.chModelName endl;cout UserDefinedName: pstMVDevInfo-SpecialInfo.stUsb3VInfo.chUserDefinedName endl;}else{cout Not support. endl;}return true;
}void PressEnterToExit(void)
{int c;while((c getchar()) ! \n c ! EOF)fprintf(stderr, Press enter to exit.\n);while(getchar() ! \n)g_bExit true;sleep(1);
}int kbhit(void) {struct termios oldt, newt;int ch;int oldf;tcgetattr(STDIN_FILENO, oldt);newt oldt;newt.c_lflag ~(ICANON | ECHO);tcsetattr(STDIN_FILENO, TCSANOW, newt);oldf fcntl(STDIN_FILENO, F_GETFL, 0);fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);ch getchar();tcsetattr(STDIN_FILENO, TCSANOW, oldt);fcntl(STDIN_FILENO, F_SETFL, oldf);if (ch ! EOF) {ungetc(ch, stdin);return 1;}return 0;
}