简介
某些项目需求使用多台相机同时拍摄某个场景不同角度的图片,比如制作黑客帝国电影中的“子弹时间”那样的视频效果。或者需要拍摄一线产线完整的图片,因为一个相机的视角有限,拍摄不到完整的产线情况。这个时候我们可以使用多个相机来进行拍摄。
实现原理
工业相机一般带有输入输出光耦IO,输入光耦IO可以当成触发进行触发拍照,输出光耦IO可以输出我们需要的信号。我们把多台相机的输入IO连接到一起,就能起到同时触发的作用。需要拍照的时候只需要有一个机械开关给相机发个光耦开关信号即可。如果需要软件来控制是否拍照,则只需要将输出光耦IO接到输入光耦IO。需要拍照的时候,软件控制输出光耦IO信号。
简单框架,画册得不好,光耦IO那部分也简化了,大家莫怪。
代码
下面使用3台云钥科技的GigE网络工业相机UGSMT500C和CKSDK来进行开发。相机像框图中分别命名为Camera0, Camera1, Camera2。
// MultiCameraSnapshot.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <windows.h>
#include "CKCameraInterface.h"
#include "opencv2/opencv.hpp"
#ifdef _DEBUG
#pragma comment(lib, "opencv_world347d.lib")
#else
#pragma comment(lib, "opencv_world347d.lib")
#endif
#ifdef WIN32
#pragma comment(lib, "CKCameraDLL.lib")
#else
#pragma comment(lib, "CKCameraDLL_x64.lib")
#endif
int main()
{
int nCameraNum;
CameraSdkStatus status;
status = CameraEnumerateDevice(&nCameraNum);
if (status == CAMERA_STATUS_SUCCESS)
return -1;
if (nCameraNum != 3)
{
printf("Don't find 3 cameras");
return -1;
}
bool isSuccess = TRUE;
HANDLE hCamera[3] = { NULL, NULL, NULL };
for (int i = 0; i < 3; i++)
{
char cameraFriendlyName[32];
sprintf_s(cameraFriendlyName, "Camera%d", i);
status = CameraInitEx2(&hCamera[i], cameraFriendlyName);
if (status == CAMERA_STATUS_SUCCESS)
{
printf("Open camera %s failed.\n", cameraFriendlyName);
isSuccess = FALSE;
break;
}
//设置图像输出格式
status |= CameraSetIspOutFormat(hCamera[i], CAMERA_MEDIA_TYPE_RGB8);
//如果是网络相机,设置网络相机最大传输大小
unsigned long deviceID = 0;
CameraGetDeviceType(hCamera, &deviceID);
if (deviceID == DEVICE_TYPE_GIGE)
{
status |= CameraGigeSetTransPacketSize(hCamera[i], 9014);
}
//设置曝光和增益
status |= CameraSetAeState(hCamera[i], 0);
status |= CameraSetExposureTime(hCamera[i], 30'000);
status |= CameraSetAnalogGain(hCamera[i], 1'000);
//设置输入IO为触发模式
status |= CameraSetInputIOMode(hCamera[i], 0, IOMODE_TRIG_INPUT);
status |= CameraSetTriggerJitterTime(hCamera[i], 0, 0);
status |= CameraSetTriggerSignalType(hCamera[i], 0, EXT_TRIG_LEADING_EDGE);
//如果是Camera0, 则设置输出IO为普通IO输出
if (strcmp(cameraFriendlyName, "Camera0") == 0)
{
status |= CameraSetOutputIOMode(hCamera[i], 0, IOMODE_GP_OUTPUT);
status |= CameraSetOutputIOState(hCamera[i], 0, 0);
}
//设置硬件触发模式
status |= CameraSetTriggerMode(hCamera[i], 2);
status |= CameraSetTriggerFrameCount(hCamera[i], 1);
status |= CameraSetTriggerDelayTime(hCamera[i], 0);
if (status != CAMERA_STATUS_SUCCESS)
{
isSuccess = FALSE;
break;
}
}
//判断是不是某个相机初始化没有成功,如果没有成功,则将所有已经成功打开的相机反初始化
if (!isSuccess)
{
for (int i = 0; i < 3; i++)
{
if (hCamera[i] != NULL)
{
CameraUnInit(hCamera[i]);
}
}
return -1;
}
cv::namedWindow("Camera0");
cv::namedWindow("Camera1");
cv::namedWindow("Camera2");
while (1)
{
//Camera0相机输出一个上升沿信号
CameraSetOutputIOState(hCamera[0], 0, 1);
CameraSetOutputIOState(hCamera[0], 0, 0);
for (int i = 0; i < 3; i++)
{
stImageInfo imgInfo;
BYTE *pImgData = CameraGetImageBufferEx(hCamera, &imgInfo, 1000);
if(pImgData == NULL)
continue;
//使用opencv将图片显示在三个窗口中,虽然三个相机是顺序读取的,但是他们是在同一时刻拍照的
cv::Mat image(imgInfo.iHeight, imgInfo.iWidth, CV_8UC3, pImgData);
if (i == 0)
{
cv::imshow("Camera0", image);
}
else if (i == 1)
{
cv::imshow("Camera1", image);
}
else
{
cv::imshow("Camera2", image);
}
//这里只是将三个相机同的图像同步显示出来,大家也可以运用做其它的事情。。。。。
}
int key = cv::waitKey(0);
if (key == 27)
break;
}
cv::destroyAllWindows();
for (int i = 0; i < 3; i++)
{
CameraUnInit(hCamera[i]);
}
return 0;
}
欢迎大家使用云钥科技的相机,有USB2.0、USB3.0、GIGE网络工 业相机,支持软硬件定制开发