*** 工业相机在机器视觉中起到关键作用,本文基于海康 SDK 详细解读了设备连接与控制的各个步骤。内容涵盖设备枚举、句柄创建、图像采集回调以及设备异常处理,帮助开发者快速理解如何通过代码控制相机,实时采集并处理图像数据。***
1. 搜索并枚举相机设备
这个部分主要是枚举所有连接的相机设备,并在界面上显示设备的序列号,供用户选择。
void MainWindow::on_btnSeachCamera_clicked() {
ui->listWidget->clear(); // 清空当前相机列表
int nRet = MV_OK;
bool isGige = ui->radioGIGE->isChecked(); // 判断选择的是 GIGE 还是 USB 连接
// 枚举相机
if (isGige) {
nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE, &cameraList);
if (nRet != MV_OK) {
setLastErrorMsg(tc("C10: 未找到可用网口相机, 错误码: %1").arg(nRet));
}
} else {
nRet = MV_CC_EnumDevices(MV_USB_DEVICE, &cameraList);
if (nRet != MV_OK) {
setLastErrorMsg(tc("C10: 未找到可用 USB 相机, 错误码: %1").arg(nRet));
return;
}
}
// 如果没有找到相机,返回提示
if (cameraList.nDeviceNum == 0) {
setLastErrorMsg(tc("C10: 未找到任何可用相机"));
return;
}
// 将找到的相机序列号添加到 UI 列表中
for (int i = 0; i < cameraList.nDeviceNum; i++) {
const char *serial = isGige
? reinterpret_cast<char *>(cameraList.pDeviceInfo[i]->SpecialInfo.stGigEInfo.chSerialNumber)
: reinterpret_cast<char *>(cameraList.pDeviceInfo[i]->SpecialInfo.stUsb3VInfo.chSerialNumber);
ui->listWidget->addItem(serial);
}
}
- 主要功能:枚举设备,根据用户选择的接口类型(GIGE或USB),调用
MV_CC_EnumDevices
获取连接到计算机的相机列表。 - UI 更新:将所有找到的设备序列号添加到列表控件中供用户选择。
2. 创建设备句柄并连接设备
用户在选择相机并点击“连接”按钮后,程序会为选定的相机创建句柄,并尝试连接设备。
void MainWindow::on_btnconnect_clicked() {
MV_CC_DEVICE_INFO cameraInfo;
int nRet = MV_OK;
unsigned int i = 0; // 假设选择了第一个相机
// 创建设备句柄
memcpy(&cameraInfo, cameraList.pDeviceInfo[i], sizeof(MV_CC_DEVICE_INFO));
nRet = MV_CC_CreateHandle(&m_handle, &cameraInfo);
if (nRet != MV_OK) {
setLastErrorMsg(tc("C12: 相机 #%1 初始化失败, 错误码: %2").arg(i).arg(nRet));
return;
}
// 打开设备
nRet = MV_CC_OpenDevice(m_handle, MV_ACCESS_Exclusive);
if (nRet != MV_OK) {
setLastErrorMsg(tc("C14: 相机 #%1 打开失败, 错误码: %2").arg(i).arg(nRet));
return;
}
m_fram = (cameraInfo.nTLayerType == MV_GIGE_DEVICE) ? 0 : -1;
}
- 创建句柄:
MV_CC_CreateHandle
函数使用选中的设备信息cameraInfo
创建相机句柄m_handle
。 - 打开设备:通过
MV_CC_OpenDevice
打开相机,并指定独占模式(MV_ACCESS_Exclusive
),避免其他进程访问该设备。 - 帧计数初始化:如果是网口设备(
GIGE
),初始化帧计数器m_fram
为 0;否则设为 -1,表示未初始化。
3. 设置相机触发模式
用户可以通过界面选择不同的触发模式,包括连续采集、软件触发和硬件触发。相机的触发模式会影响图像采集的方式。
void MainWindow::on_comboBox_activated(int index) {
ui->btn_Grab->setVisible(index == OpenSoftWare); // 仅在软件触发模式下显示抓拍按钮
int nRet = MV_OK;
// 设置触发模式
switch (index) {
case OpenContinue: // 连续采集模式
nRet = MV_CC_SetEnumValue(m_handle, "TriggerMode", 0);
break;
case OpenSoftWare: // 软件触发模式
nRet = MV_CC_SetEnumValue(m_handle, "TriggerMode", 1);
if (nRet == MV_OK) nRet = MV_CC_SetEnumValue(m_handle, "TriggerSource", 7); // 设置触发源为软件
break;
case OpenHardWare: // 硬件触发模式
nRet = MV_CC_SetEnumValue(m_handle, "TriggerMode", 1);
if (nRet == MV_OK) nRet = MV_CC_SetEnumValue(m_handle, "TriggerSource", 0); // 触发源为硬件
if (nRet != MV_OK) nRet = MV_CC_SetEnumValue(m_handle, "TriggerSource", 1);
if (nRet == MV_OK) nRet = MV_CC_SetEnumValue(m_handle, "TriggerActivation", 0); // 触发激活为上升沿
break;
}
if (nRet != MV_OK) {
setLastErrorMsg(tc("C24: 设置触发模式失败, 错误码: %1").arg(nRet));
}
}
- 连续采集:设置触发模式为 0(关闭触发模式),相机会自动连续采集图像。
- 软件触发:设置触发模式为 1,并将触发源设置为软件触发源(值为 7),之后可以通过代码发送触发命令来抓取图像。
- 硬件触发:设置触发模式为 1,触发源为硬件触发通道 0 或 1(如硬件引脚输入触发信号)。
4. 图像采集回调函数 - ImageCallBack
每当相机采集到一帧图像时,都会触发 ImageCallBack
回调函数。该函数负责将图像数据转换为 Halcon 格式并显示在 UI 界面中。
void ImageCallBack(unsigned char *pData, MV_FRAME_OUT_INFO_EX *pFrameInfo, void *pUser) {
clock_t EnterTime = clock();
MainWindow *camera = static_cast<MainWindow *>(pUser);
// 更新相机图像参数信息到 UI 显示
camera->ui->lab_W->setText(QString::number(pFrameInfo->nWidth));
camera->ui->lab_H->setText(QString::number(pFrameInfo->nHeight));
camera->ui->lab_P->setText(QString::number(pFrameInfo->nFrameNum));
camera->ui->lab_tri->setText(QString::number(pFrameInfo->nTriggerIndex));
try {
HalconCpp::HObject ho_Image;
int ImageWidth = pFrameInfo->nWidth;
int ImageHeight = pFrameInfo->nHeight;
// 根据像素格式生成 Halcon 图像对象
switch (pFrameInfo->enPixelType) {
case PixelType_Gvsp_Mono8:
HalconCpp::GenImage1(&ho_Image, "byte", ImageWidth, ImageHeight, reinterpret_cast<Hlong>(pData));
break;
case PixelType_Gvsp_RGB8_Packed:
HalconCpp::GenImageInterleaved(&ho_Image, reinterpret_cast<Hlong>(pData), "rgb",
ImageWidth, ImageHeight, -1, "byte", 0, 0, 0, 0, -1, 0);
break;
case PixelType_Gvsp_BayerRG8:
HalconCpp::GenImage1(&ho_Image, "byte", ImageWidth, ImageHeight, reinterpret_cast<Hlong>(pData));
HalconCpp::CfaToRgb(ho_Image, &ho_Image, "bayer_rg", "bilinear");
break;
default:
HalconCpp::GenImageConst(&ho_Image, "byte", ImageWidth, ImageHeight);
break;
}
// 显示图像
camera->detect(ho_Image);
} catch (const HalconCpp::HException &) {
camera->setLastErrorMsg(tc("C25: 相机图像数据格式转换失败"));
}
}
- 图像数据转换:根据
pFrameInfo->enPixelType
中的像素类型,调用 Halcon 库的不同函数将图像数据pData
转换
为 Halcon 图像对象 ho_Image
。
- 图像显示:调用
camera->detect(ho_Image);
将转换后的图像显示在 UI 窗口中。 - 异常处理:若图像数据转换失败,则会记录错误信息。
5. 异常处理回调函数 - ExceptionCallBack
当设备连接断开或发生其他异常情况时,SDK 会调用该异常回调函数。我们可以在此函数中记录并显示错误信息,提示用户相机状态异常。
void ExceptionCallBack(unsigned int nMsgType, void *pUser) {
if (nMsgType == MV_EXCEPTION_DEV_DISCONNECT) {
MainWindow *camera = static_cast<MainWindow *>(pUser);
camera->setLastErrorMsg(tc("C26: 相机连接断开"));
}
}
- 主要功能:判断消息类型
nMsgType
是否为设备断开事件MV_EXCEPTION_DEV_DISCONNECT
。若设备断开,程序会调用setLastErrorMsg
显示错误信息。
总结
这段代码实现了通过海康 SDK 控制工业相机的主要功能,包括设备搜索、创建句柄、设置触发模式、图像采集和异常处理。该流程在实际的机器视觉应用中很常见,适用于产品质量检测、生产线监控等场景。流程概括如下:
- 设备枚举:找到并列出所有连接的相机设备,供用户选择。
- 创建句柄和连接设备:为选定设备创建句柄并连接设备。
- 触发模式设置:支持多种采集模式(如连续采集、软件触发、硬件触发),用户可以根据实际需求选择。
- 图像采集回调:采集到图像后触发回调,将图像数据转换为 Halcon 格式并显示。
- 异常处理:实时监控设备状态,当设备断开时触发异常回调并记录提示。