最近项目中要用到一款IDS的相机,型号是UI-3060CP ,这是一款USB3.0相机。IDS官网提供了不同操作系统的开发包,有相当详细开发说明。注册后便可以下载,链接为:https://en.ids-imaging.com/download-ueye-win32.html
首先下载了windows下的开发包,默认安装后可以正常打相机,然后开始尝试利用vs2010+opencv进行二次开发。
1.配置环境,ids的软件包默认安装目录为C:\Program Files\IDS\uEye
2.新建工程文件并配置链接库,vs2010下配置过程类似于opencv的配置
①【配置属性】 ->【C/C++】 ->【常规】->【附加包含目录】
添加路径 C:\Program Files\IDS\uEye\Develop\include;②【链接器】 ->【常规】 ->【附加库目录】中
添加路径 C:\Program Files\IDS\uEye\Develop\Lib;③链接库的附加依赖项的配置:【链接器】 ->【输入】 ->【附加依赖项】中
添加
kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib
ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ueye_api.lib
3.主体程序部分,相机的使用主要包括以下部分
至此开发环境配置完成。
(1)初始化相机
通过 is_InitCamera()函数可以初始化相机,并为相机分配一个唯一的句柄,后续可以通过该句柄来访问相机。
(2)查询相机信息
is_GetCameraList();
通过is_GetSensorInfo( )函数可以获取相机传感器的信息,根据该信息可以得知相机色彩模式等可以设置的类型。
(3)选择显示模式
is_SetDisplayMode();
本款IDS相机有三种模式:Direct3D、OpenGL、位图(DIB)模式
其中Direct3D仅用于windows系统,opengl需要硬件支持、位图模式支持所有平台并可以直接访问内存。
由于需要对图像进行访问选择了位图模式,在该模式下需要手动分配内存,并在捕捉图像之前激活内存。
(4)捕捉图像
is_SetExternalTrigger();
is_CaptureVideo();
首先设定相机的预期模式分为自由运行模式和触发模式,在自由运行模式下相机传感器以设定的帧率捕捉一张张图像,并可以连续传送图像。
选择触发模式时,传感器处于待机状态,收硬件或者软件的触发信号时才开始曝光。
(5)保存图像
is_ImageFile();
(6)保存图像
只有在“与设备无关位图”(DIB)显示模式,才可以进行AVI录像。
AVI 捕捉流程图:先初始化 AVI 接口,然后创建一个空的 AVI 文件并设置相关参数。
(7)调整相机参数
相机会自动释放经is_AllocImageMem() 函数分配的图像内存。所有之前设置的相机参数将会丢失。
其头文件如下:
#include "ueye.h" #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> class Idscam{ public: Idscam(); INT InitCamera (HIDS *hCam, HWND hWnd); //初始化相机 hWnd指向显示图像窗口的指针,若用DIB模式可以令hWnd=NULL bool OpenCamera(); void ExitCamera(); int InitDisplayMode(); void GetMaxImageSize(INT *pnSizeX, INT *pnSizeY);//查询相机支持的图像格式 void SaveImage( ); bool GetiplImgFormMem(); //从视频数据流中将图像数据拷贝给IplImage // uEye varibles HIDS m_hCam; // 相机句柄 HWND m_hWndDisplay; // window显示句柄 INT m_nColorMode; // Y8/RGB16/RGB24/REG32 INT m_nBitsPerPixel; // 图像位深 INT m_nSizeX; // 图像宽度 INT m_nSizeY; // 图像高度 INT m_nPosX; // 图像左偏移 INT m_nPosY; // 图像右偏移 cv::Mat CamMat; IplImage *iplImg; char *m_pLastBuffer; private: // 使用位图模式进行实时显示需要的内存 INT m_lMemoryId; // camera memory - buffer ID char* m_pcImageMemory; // camera memory - pointer to buffer SENSORINFO m_sInfo; // sensor information struct INT m_nRenderMode; // render mode INT m_nFlipHor; // 水平翻转标志 INT m_nFlipVert; // 垂直翻转标志 };对应实现为:
#include"Idscam.h" #include <string> #include <iostream> using namespace std; Idscam::Idscam(){ m_pcImageMemory = NULL; m_lMemoryId = 0; m_hCam = 0; //初始化相机句柄为0 m_nRenderMode = IS_RENDER_FIT_TO_WINDOW; //设置显示模式为适应窗口大小 m_nPosX = 0; m_nPosY = 0; m_nFlipHor = 0; m_nFlipVert = 0; iplImg=cvCreateImageHeader( cvSize(1936,1216),8,4 ); OpenCamera(); } bool Idscam::OpenCamera(){ INT nRet = IS_NO_SUCCESS; ExitCamera(); m_hCam = (HIDS) 0; nRet = InitCamera(&m_hCam, m_hWndDisplay); // 1.初始化相机 if (nRet == IS_SUCCESS){ // 打开相机成功 // 查询相机所用传感器的类型 is_GetSensorInfo(m_hCam, &m_sInfo); //2.查询信息 GetMaxImageSize(&m_nSizeX, &m_nSizeY); nRet = InitDisplayMode(); //3.选择显示模式(位图) if (nRet == IS_SUCCESS) { // 允许接受消息 is_EnableMessage(m_hCam, IS_DEVICE_REMOVED, NULL); is_EnableMessage(m_hCam, IS_DEVICE_RECONNECTED, NULL); is_EnableMessage(m_hCam, IS_FRAME, NULL); is_CaptureVideo( m_hCam, IS_WAIT ); //4.设定捕捉模式:自由运行模式下的实时模式 return true; } else{ printf("初始化显示模式失败!"); return false; } } else{ printf("没有发现uEye相机!"); return false; } } void Idscam:: ExitCamera() { if( m_hCam != 0 ) { // 调用 hWnd = NULL函数禁用Windows消息 is_EnableMessage( m_hCam, IS_FRAME, NULL ); // 在曝光未开始时停止实时模式或取消硬件触发的图像捕捉 is_StopLiveVideo( m_hCam, IS_WAIT ); // 释放分配的图像内存 if( m_pcImageMemory != NULL ) is_FreeImageMem( m_hCam, m_pcImageMemory, m_lMemoryId ); m_pcImageMemory = NULL; // 关闭相机 is_ExitCamera( m_hCam ); m_hCam = NULL; } } //1.初始化相机 INT Idscam::InitCamera (HIDS *hCam, HWND hWnd) { INT nRet = is_InitCamera (hCam, hWnd); if (nRet == IS_STARTER_FW_UPLOAD_NEEDED)//相机的启动程序固件和驱动不兼容,需要更新固件版本 { INT nUploadTime = 25000; //默认更新时间为25S is_GetDuration (*hCam, IS_STARTER_FW_UPLOAD, &nUploadTime); printf("This camera requires a new firmware !\n"); printf("The upload will take about %f seconds. Please wait ...\n",nUploadTime/1000); //再次打开相机并自动更新固件 *hCam = (HIDS) (((INT)*hCam) | IS_ALLOW_STARTER_FW_UPLOAD); nRet = is_InitCamera (hCam, NULL); } printf("初始化相机成功 !\n"); return nRet; } int Idscam::InitDisplayMode() { INT nRet = IS_NO_SUCCESS; if (m_hCam == NULL) return IS_NO_SUCCESS; if (m_pcImageMemory != NULL) //释放通过 is_AllocImageMem() 函数分配的图像内存 { is_FreeImageMem( m_hCam, m_pcImageMemory, m_lMemoryId ); //如果图像内存不是通过SDK分配,则需调用 is_FreeImageMem() 函数。否则驱动会继续尝试访问该内存。 //但是这并不能释放内存。因此,必须确保可再次释放内存。 } m_pcImageMemory = NULL; // 设置位图模式 nRet = is_SetDisplayMode(m_hCam, IS_SET_DM_DIB); if (m_sInfo.nColorMode == IS_COLORMODE_BAYER) { // 如果是拜耳色 则设置位深为当前窗口的设置,linux 下不可以这么设置 // 用于检索当前Windows桌面的颜色设置并返回每像素位深及相匹配的uEye色彩模式 is_GetColorDepth(m_hCam, &m_nBitsPerPixel, &m_nColorMode); } else if (m_sInfo.nColorMode == IS_COLORMODE_CBYCRY) { m_nColorMode = IS_CM_BGRA8_PACKED; m_nBitsPerPixel = 32; } else { m_nColorMode = IS_CM_MONO8; m_nBitsPerPixel = 8; } // 分配图像内存,图像尺寸有 m_nSizeX和m_nSizeY确定,色彩位深由m_nBitsPerPixel确定,m_pcImageMemory返回起始地址,m_lMemoryId 返回已分配内存的ID if (is_AllocImageMem(m_hCam, m_nSizeX, m_nSizeY, m_nBitsPerPixel, &m_pcImageMemory, &m_lMemoryId ) != IS_SUCCESS) { printf("相机内存分配出错!"); } else is_SetImageMem( m_hCam, m_pcImageMemory, m_lMemoryId ); /* INT is_SetImageMem (HIDS hCam, char* pcImgMem, INT id)用于将指定的图像内存变为活动内存。 只有活动图像内存可以接收图像数据。 在调用 is_FreezeVideo() 时,捕捉的图像会存储在 pcImgMem 和 id 指定的图像缓冲区中。 捕捉的图像会存储在 pcImgMem 和 id 指定的图像缓冲区中。对于 pcImgMem, 您必须传递 is_AllocImageMem() 创建的指针,传递任何其他指针均会发出错误信息。 您可以多次传递同样的指针。 */ if (nRet == IS_SUCCESS) { // 设置显卡在保存或显示图像数据时所使用的色彩模 is_SetColorMode(m_hCam, m_nColorMode); // set the image size to capture IS_SIZE_2D imageSize; imageSize.s32Width = m_nSizeX; imageSize.s32Height = m_nSizeY; //设置图像感兴趣区域(AOI)的大小和位置 is_AOI(m_hCam, IS_AOI_IMAGE_SET_SIZE, (void*)&imageSize, sizeof(imageSize)); } return nRet; } void Idscam::GetMaxImageSize(INT *pnSizeX, INT *pnSizeY) { INT nAOISupported = 0; BOOL bAOISupported = TRUE; if (is_ImageFormat(m_hCam, IMGFRMT_CMD_GET_ARBITRARY_AOI_SUPPORTED, (void*)&nAOISupported, sizeof(nAOISupported)) == IS_SUCCESS) { bAOISupported = (nAOISupported != 0); } if (bAOISupported) { // All other sensors // Get maximum image size SENSORINFO sInfo; is_GetSensorInfo (m_hCam, &sInfo); *pnSizeX = sInfo.nMaxWidth; *pnSizeY = sInfo.nMaxHeight; } else { // Only ueye xs // Get image size of the current format IS_SIZE_2D imageSize; is_AOI(m_hCam, IS_AOI_IMAGE_GET_SIZE, (void*)&imageSize, sizeof(imageSize)); *pnSizeX = imageSize.s32Width; *pnSizeY = imageSize.s32Height; } } bool Idscam::GetiplImgFormMem(){ //实时获取图像时需要不断刷新此函数 if(!m_hCam) return false; char *pLast = NULL, *pMem = NULL; INT dummy = 0; //确定当前用于捕捉图像的图像内存 pMem,最后一个用于捕捉图像的图像内存pLast is_GetActSeqBuf (m_hCam, &dummy, &pMem, &pLast); m_pLastBuffer = pLast; if (m_pLastBuffer) { iplImg->imageData = m_pLastBuffer; //将图像首地址传给iplImg return true; } else return false; } void Idscam::SaveImage( ){ IMAGE_FILE_PARAMS ImageFileParams; ImageFileParams.pwchFileName = NULL; ImageFileParams.pnImageID = NULL; ImageFileParams.ppcImageMem = NULL; ImageFileParams.nQuality = 0; ImageFileParams.nFileType = IS_IMG_BMP; INT nRet = is_ImageFile(m_hCam, IS_IMAGE_FILE_CMD_SAVE, (void*)&ImageFileParams, sizeof(ImageFileParams)); //保存活动内存中的jpeg图像,图像画质为100 ImageFileParams.pwchFileName = L"CamIds.jpg"; ImageFileParams.nFileType = IS_IMG_JPG; //待保存文件的类型 ImageFileParams.nQuality = 100; //100为最佳图像画质(无压缩) nRet = is_ImageFile(m_hCam, IS_IMAGE_FILE_CMD_SAVE, (void*)&ImageFileParams, sizeof(ImageFileParams)); }
在主程序中创建一个Idscam类,默认初始化会直接打开相机,调用函数GetiplImgFormMem()和变量iplImg即可得到相机获取的图片。
这里并没有创建线程一直刷新相机,所以获取只能获取初始捕捉到的画面。
主程序为:
#include <cv.h> #include <highgui.h> #include"Idscam.h" char* window_name = "Source Video"; int main() { Idscam *mycam; mycam = new Idscam(); if(mycam->GetiplImgFormMem()) cvShowImage(window_name,mycam->iplImg); cvWaitKey(3000); return 0; }成功打开相机并得到相机画面。
由于项目环境是linux,故对windows下的开发并未做过多研究。