需要用摄像头,而实验室只有一个海康威视的MV-CA013-20GC(另一个大恒的更难搞),拿工业相机当普通相机用是不是有点暴殄天物了。
1. 相机接线
工业相机一般都需要独立供电,12v接上相机的正负极,另外网口接上电脑或交换机Lan口,建议使用千兆网口,不然帧率跟不上(也可以使用网口转usb3.0).
2.客户端使用
去官网下载下面两个软件安装,一个是客户端,另一个是开发运行环境。
打开软件如图所示
软件会自动搜索可连接的设备,查找到设备后修改相机的ip,连接上相机,然后就可以调节参数了。这里如果画面很黑,首先调小相机的光圈,增大进光量,开启自动曝光与自动增益、伽马校正。如果使用的百兆网口会出现帧率低的情况,这里要么就更换千兆网口,要么将图像类型设置为mono8.
3.sdk的二次开发
进入到安装目录下有一个Development文件夹,里面有头文件和库文件以及各种语言的开发说明和demo。
这里以C++为例(VS2019)
大致流程如下,具体实现请参考文档和demo
首先新建项目,将开发需要的头文件和库文件拷出来放到项目文件中,注意库文件有32和64之分。在属性里面配置头文件和库文件。如图所示
示例代码,先捕获摄像头图像,再用opencv显示
#include "MvCameraControl.h"
#include "opencv2/opencv.hpp"#include <stdio.h>
#include <conio.h>
#include <iostream>
#include <string>using namespace std;bool printDeviceInfo(MV_CC_DEVICE_INFO* hk_device);
bool hk2cv(MV_FRAME_OUT_INFO_EX* hk_imginfo, unsigned char* data, cv::Mat &src_img);int main(int argv, char** argc) {int ret = MV_OK;void* handle = NULL;MV_CC_DEVICE_INFO_LIST hk_devices;memset(&hk_devices, 0, sizeof(MV_CC_DEVICE_INFO_LIST));ret = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &hk_devices);if (ret != MV_OK) {cout << "enum devices faild!" << endl;return -1;}if (hk_devices.nDeviceNum > 0) {MV_CC_DEVICE_INFO* hk_camera = hk_devices.pDeviceInfo[0];if (printDeviceInfo(hk_camera) == false) {return -1;}}else {cout << "no device found" << endl;return -1;}ret = MV_CC_CreateHandle(&handle, hk_devices.pDeviceInfo[0]);if (ret != MV_OK) {return -1;}ret = MV_CC_OpenDevice(handle);if (ret != MV_OK) {return -1;}ret = MV_CC_SetEnumValue(handle, "TriggerMode", 0);if (ret != MV_OK) {return -1;}MVCC_INTVALUE hk_param;memset(&hk_param, 0, sizeof(MVCC_INTVALUE));ret = MV_CC_GetIntValue(handle, "PayloadSize", &hk_param);if (ret != MV_OK) {return -1;}unsigned int payload_size = hk_param.nCurValue;// load configret = MV_CC_FeatureLoad(handle, "FeatureFile.ini");if (ret != MV_OK){cout << "loading config file faild" << endl;return -1;}// save config/* ret = MV_CC_FeatureSave(handle, "FeatureFile.ini");if (ret != MV_OK) {return -1;}*/// start grabbing imagesret = MV_CC_StartGrabbing(handle);if (ret != MV_OK) {cout << "grab image failed!" << endl;return -1;}MV_FRAME_OUT_INFO_EX hk_imginfo;memset(&hk_imginfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));unsigned char* data = (unsigned char*)malloc(sizeof(unsigned char) * (payload_size));if (data == NULL) {return -1;}cv::Mat src_img;while (!(_kbhit() && _getch() == 0x1b)) {ret = MV_CC_GetOneFrameTimeout(handle, data, payload_size, &hk_imginfo, 1000);if (ret != MV_OK) {free(data);data = NULL;return -1;}if (hk2cv(&hk_imginfo, data, src_img) == false) {continue;}cv::imshow("test", src_img);cv::waitKey(30);}// stop grap imageret = MV_CC_StopGrabbing(handle);if (ret != MV_OK) {return -1;}// close deviceret = MV_CC_CloseDevice(handle);if (ret != MV_OK) {return -1;}ret = MV_CC_DestroyHandle(handle);if (ret != MV_OK) {return -1;}system("pause");return 0;
}bool printDeviceInfo(MV_CC_DEVICE_INFO* hk_device) {if (NULL == hk_device){printf("The Pointer of hk_device is NULL!\n");return false;}if (hk_device->nTLayerType == MV_GIGE_DEVICE){int nIp1 = ((hk_device->SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24);int nIp2 = ((hk_device->SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16);int nIp3 = ((hk_device->SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8);int nIp4 = (hk_device->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff);// print current ip and user defined nameprintf("CurrentIp: %d.%d.%d.%d\n", nIp1, nIp2, nIp3, nIp4);printf("UserDefinedName: %s\n\n", hk_device->SpecialInfo.stGigEInfo.chUserDefinedName);}else if (hk_device->nTLayerType == MV_USB_DEVICE){printf("UserDefinedName: %s\n", hk_device->SpecialInfo.stUsb3VInfo.chUserDefinedName);printf("Serial Number: %s\n", hk_device->SpecialInfo.stUsb3VInfo.chSerialNumber);printf("Device Number: %d\n\n", hk_device->SpecialInfo.stUsb3VInfo.nDeviceNumber);}else{printf("Not support.\n");}return true;
}bool hk2cv(MV_FRAME_OUT_INFO_EX* hk_imginfo, unsigned char* data, cv::Mat& src_img) {cv::Mat cv_img;if (hk_imginfo->enPixelType == PixelType_Gvsp_Mono8){cv_img = cv::Mat(hk_imginfo->nHeight, hk_imginfo->nWidth, CV_8UC1, data);}else if (hk_imginfo->enPixelType == PixelType_Gvsp_RGB8_Packed){for (unsigned int j = 0; j < hk_imginfo->nHeight; j++){for (unsigned int i = 0; i < hk_imginfo->nWidth; i++){unsigned char red = data[j * (hk_imginfo->nWidth * 3) + i * 3];data[j * (hk_imginfo->nWidth * 3) + i * 3] = data[j * (hk_imginfo->nWidth * 3) + i * 3 + 2];data[j * (hk_imginfo->nWidth * 3) + i * 3 + 2] = red;}}cv_img = cv::Mat(hk_imginfo->nHeight, hk_imginfo->nWidth, CV_8UC3, data);}else{printf("unsupported pixel format\n");return false;}if (cv_img.data == NULL){return false;}cv_img.copyTo(src_img);return true;
}
因为每次断电后都要重新设置,这里我取了一个巧,先用客户端配置好参数,然后保存参数,以后每次运行只要加载参数就行了。如果运行提示没有找到dll文件,那么就是你runtime运行环境没有安装,或者没有将安装路径添加到系统环境变量。
正如开头所说的,只是拿来当普通摄像头用,所以代码很简单,后面有机会再深入研究。