注:代码仅供参考,相互学习。
本意:帮助大家快速入手大恒相机,也留个记录后续优化。

配置环境:VS2019、OpenCV454、Qt5.14.2、大恒水星系列相机(gige)

优化:
2022/4/22
1、把.h文件中类成员的初始化写到构造函数中
2、重新整理相机类和主窗口类关系
2022/7/21(完)
1、基本上重写了一版,这次逻辑更加清晰,考虑更全面。
这次更新是为了这篇博客有始有终,优化到目前这个阶段对于初学者应该是够用了。

一、qt界面

二、ui框架

三、代码部分

(1)DH_MER.h

#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_DH_MER.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include "GalaxyIncludes.h"

using namespace cv;
using namespace std;

class DH_MER : public QMainWindow, public IDeviceOfflineEventHandler, public ICaptureEventHandler
{
	Q_OBJECT

public:
	DH_MER(QWidget* parent = Q_NULLPTR);

public:
	void DoOnImageCaptured(CImageDataPointer& objImageDataPointer, void* pUserParam);
	void DoOnDeviceOfflineEvent(void* pUserParam); //掉线事件回调函数
public:
	CGXDevicePointer m_objDevicePtr; //设备指针,指向打开的相机
	CGXFeatureControlPointer m_objRemoteFeatureControlPtr; //(远端)设备属性控制器指针
	CGXFeatureControlPointer m_objFeatureControlPtr; //本地和流属性控制器
	CGXStreamPointer m_objStreamPtr; //流指针,指向相机打开的流
	GX_DEVICE_OFFLINE_CALLBACK_HANDLE m_hDeviceOffline; //掉线事件
	GX_DEVICE_CLASS_LIST objDeviceClass;//设备类型
	CGXDeviceInfo m_deviceInfo;//设备信息
	QString m_firmName;//厂商名称
	QString m_modelName;//设备型号
	QString m_serialNumName;//序列号
	QString m_ipName;//ip地址
	QString m_maskName;//掩码
	QString m_macName;//MAC地址
	int64_t m_width;
	int64_t m_height;
	QString m_bitDepth;
	cv::Mat capturedImg; //相机采集的图片
	//相机状态判断
	bool isOpenCam; //相机是否打开
	bool isOpenStream; //相机流是否打开
	bool isOffline; //设备是否掉线
	bool isTrigger; //相机是否触发
	int exposeTime; //曝光时间
	QString m_triggerMode;
	QString m_triggerSource;

private:
	Ui::DH_MERClass ui;

public slots:
	void on_openDevice_clicked();
	void on_closeDevice_clicked();
	void on_startCapture_clicked();
	void on_stopCapture_clicked();
	void on_TriggerSoftware_clicked();
	void getExposeTime();
public:
	void showMatInLabel(Mat matImg);
	void updateUI();
};

(2)DH_MER.cpp

#pragma once

#include "DH_MER.h"
#include<QWidget>

DH_MER::DH_MER(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

	isOpenCam = false;
	isOpenStream = false;
	isOffline = false;
	isTrigger = false;
	exposeTime = 30000;
	m_hDeviceOffline = NULL;
	m_firmName = "";
	m_modelName = "";
	m_serialNumName = "";
	m_ipName = "";
	m_maskName = "";
	m_macName = "";
	m_width = 0;
	m_height = 0;
	m_bitDepth = "";
	m_triggerMode = "";
	m_triggerSource = "";
	//曝光时间
	connect(ui.exposeTime,&QLineEdit::editingFinished, this, &DH_MER::getExposeTime);
	//初始化库
	try
	{
		IGXFactory::GetInstance().Init();//GxIAPICPPEx库在使用之前必须执行初始化
	}
	catch (CGalaxyException& e)
	{
		cout << "错误码: " << e.GetErrorCode() << endl;
		cout << "错误描述信息: " << e.what() << endl;
	}
	ui.TriggerMode->setEnabled(false);
	ui.TriggerSource->setEnabled(false);
	ui.TriggerSoftware->setEnabled(false);
	ui.comboBox_3->setEnabled(false);
}
void DH_MER::on_openDevice_clicked()
{
	try
	{
		if (!isOpenCam)
		{
			//初始化
			IGXFactory::GetInstance().Init();
			//枚举设备
			gxdeviceinfo_vector vectorDeviceInfo;
			IGXFactory::GetInstance().UpdateDeviceList(1000, vectorDeviceInfo);
			if (0 == vectorDeviceInfo.size())
			{
				cout << "无可用设备!" << endl;
				return;
			}
			cout << vectorDeviceInfo.size() << endl;
			//打开第一台设备
			m_objDevicePtr = IGXFactory::GetInstance().OpenDeviceBySN(vectorDeviceInfo[0].GetSN(), GX_ACCESS_EXCLUSIVE);
			isOpenCam = true;
			m_objRemoteFeatureControlPtr = m_objDevicePtr->GetRemoteFeatureControl();
			m_objFeatureControlPtr = m_objDevicePtr->GetFeatureControl();
			/*设备信息获取*/
			m_deviceInfo = m_objDevicePtr->GetDeviceInfo();
			m_firmName = m_deviceInfo.GetVendorName();
			m_modelName = m_deviceInfo.GetModelName();
			m_serialNumName = m_deviceInfo.GetSN();
			m_ipName = m_deviceInfo.GetIP();
			m_maskName = m_deviceInfo.GetSubnetMask();
			m_macName = m_deviceInfo.GetMAC();
			m_width = m_objRemoteFeatureControlPtr->GetIntFeature("Width")->GetValue();
			m_height = m_objRemoteFeatureControlPtr->GetIntFeature("Height")->GetValue();
			m_bitDepth = m_objRemoteFeatureControlPtr->GetEnumFeature("PixelSize")->GetValue();
#ifdef _DEBUG
			//设置心跳超时时间 6s
			m_objRemoteFeatureControlPtr->GetIntFeature("GevHeartbeatTimeout")->SetValue(6000);
#endif
			/*设备初始设置*/
			//千兆网系列相机设置
			objDeviceClass = m_objDevicePtr->GetDeviceInfo().GetDeviceClass();
			if (objDeviceClass == GX_DEVICE_CLASS_GEV)
			{
				//提高网络相机的采集性
				if (true == m_objFeatureControlPtr->IsImplemented("GevSCPSPacketSize"))		//判断设备是否支持流通道数据包功能
				{
					//获取当前网络环境的最优包长值
					int nPacketSize = m_objStreamPtr->GetOptimalPacketSize();
					//将最优包长值设置为当前设备的流通道包长值
					m_objRemoteFeatureControlPtr->GetIntFeature("GevSCPSPacketSize")->SetValue(nPacketSize);
				}
				//注册掉线事件
				m_hDeviceOffline = m_objDevicePtr->RegisterDeviceOfflineCallback(this, NULL);
			}
			//曝光时间
			if (exposeTime > 0 && exposeTime < 200000)
				m_objRemoteFeatureControlPtr->GetFloatFeature("ExposureTime")->SetValue(exposeTime);
			else
				exposeTime = 30000;
			//采集模式
			m_objRemoteFeatureControlPtr->GetEnumFeature("AcquisitionMode")->SetValue("Continuous");
			//触发模式
			m_objRemoteFeatureControlPtr->GetEnumFeature("TriggerSelector")->SetValue("FrameStart");
			m_objRemoteFeatureControlPtr->GetEnumFeature("TriggerMode")->SetValue("Off");
			//自动曝光
			m_objRemoteFeatureControlPtr->GetEnumFeature("ExposureAuto")->SetValue("Off");

			ui.TriggerMode->setEnabled(true);
			ui.TriggerSource->setEnabled(true);
			ui.TriggerSoftware->setEnabled(true);
			ui.comboBox_3->setEnabled(true);
		}
	}
	catch (CGalaxyException& e)
	{
		cout << "错误码: " << e.GetErrorCode() << endl;
		cout << "错误描述信息: " << e.what() << endl;
	}
	catch (std::exception& e)
	{
		cout << "错误描述信息: " << e.what() << endl;
	}
}
void DH_MER::on_closeDevice_clicked()
{
	if (isOpenCam)
	{
		if (isOpenStream)
		{
			//发送停采命令
			m_objRemoteFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();
			m_objStreamPtr->StopGrab();
			ui.TriggerMode->setEnabled(true);
			ui.TriggerSource->setEnabled(true);
			ui.TriggerSoftware->setEnabled(true);
			ui.comboBox_3->setEnabled(true);
			m_objStreamPtr->UnregisterCaptureCallback();//注销采集回调
			m_objStreamPtr->Close(); //关闭相机流
			isOpenStream = false;
		}
		if (objDeviceClass == GX_DEVICE_CLASS_GEV)
		{
			//注销掉线回调事件
			m_objDevicePtr->UnregisterDeviceOfflineCallback(m_hDeviceOffline);
		}
		m_objDevicePtr->Close(); //关闭相机,释放相机资源
		IGXFactory::GetInstance().Uninit(); //释放GxIAPICPPEx申请的所有资源
		isOpenCam = false;
	}
}
void DH_MER::on_startCapture_clicked() 
{
	if (isOpenCam)
	{
		uint32_t nStreamNum = m_objDevicePtr->GetStreamCount();
		if ((nStreamNum > 0) && (!isOpenStream))
		{
			m_objStreamPtr = m_objDevicePtr->OpenStream(0);
			isOpenStream = true;
		}
		m_objStreamPtr->RegisterCaptureCallback(this, NULL);
		m_objStreamPtr->StartGrab();
		m_objRemoteFeatureControlPtr->GetCommandFeature("AcquisitionStart")->Execute();
	}
	ui.TriggerMode->setEnabled(false);
	ui.TriggerSource->setEnabled(false);
	ui.TriggerSoftware->setEnabled(false);
	ui.comboBox_3->setEnabled(false);
}
void DH_MER::on_stopCapture_clicked()
{
	if (isOpenStream)
	{
		//发送停采命令
		m_objRemoteFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();
		m_objStreamPtr->StopGrab();
		isOpenStream = false;
	}
	ui.TriggerMode->setEnabled(true);
	ui.TriggerSource->setEnabled(true);
	ui.TriggerSoftware->setEnabled(true);
	ui.comboBox_3->setEnabled(true);
}
void DH_MER::on_TriggerSoftware_clicked()
{
	try
	{
		do
		{
			m_triggerMode = ui.TriggerMode->currentText();
			m_triggerSource = ui.TriggerSource->currentText();
			if ((m_triggerMode =="on") && (m_triggerSource == "Software"))
			{
				uint32_t nStreamNum = m_objDevicePtr->GetStreamCount();
				if ((nStreamNum > 0) && (!isOpenStream))
				{
					m_objStreamPtr = m_objDevicePtr->OpenStream(0);
					isOpenStream = true;
				}
				//发送开采命令
				m_objStreamPtr->StartGrab();
				m_objRemoteFeatureControlPtr->GetCommandFeature("AcquisitionStart")->Execute();
				CImageDataPointer objImageDataPtr = m_objStreamPtr->GetImage(500);//超时时间使用500ms,用户可以自行设定
				if (objImageDataPtr->GetStatus() == GX_FRAME_STATUS_SUCCESS)
				{
					cout << "采集成功" << endl;
					void* pRGB24Buffer = NULL;
					//原始数据是 Mono8 图像
					if (objImageDataPointer->GetPixelFormat()==GX_PIXEL_FORMAT_MONO8)
					{
						pRGB24Buffer = objImageDataPointer->ConvertToRaw8(GX_BIT_0_7);
						capturedImg = cv::Mat::zeros(cv::Size(m_width, m_height), CV_8UC1);
						memcpy(capturedImg.data, pRGB24Buffer, m_width * m_height);
					}
					if (objImageDataPointer->GetPixelFormat() == GX_PIXEL_FORMAT_MONO10)
					{
						pRGB24Buffer = objImageDataPointer->ConvertToRGB24(GX_BIT_2_9, GX_RAW2RGB_NEIGHBOUR, true);
						capturedImg = cv::Mat::zeros(cv::Size(m_width, m_height), CV_8UC3);
						memcpy(capturedImg.data, pRGB24Buffer, m_width * m_height * 3);
					}
					//resize(img, img, Size(), 0.1, 0.1, CV_INTER_AREA);
					showMatInLabel(capturedImg);
				}
				m_objRemoteFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();
				m_objStreamPtr->StopGrab();
			}
		} while (0);
	}
	catch (CGalaxyException& e)
	{
		cout << "错误码: " << e.GetErrorCode() << endl;
		cout << "错误描述信息: " << e.what() << endl;
	}
}
void DH_MER::showMatInLabel(Mat matImg)
{
	Mat src = matImg.clone();
	QImage imgForDisplay;
	if (matImg.channels() == 3)//RGB Img
	{
		cv::cvtColor(src, src, cv::COLOR_BGR2RGB);//颜色空间转换
		imgForDisplay = QImage((const uchar*)(src.data), src.cols, src.rows, src.cols * src.channels(), QImage::Format_RGB888);
	}
	else//Gray Img
	{
		imgForDisplay = QImage((const uchar*)(src.data), src.cols, src.rows, src.cols * src.channels(), QImage::Format_Indexed8);
	}
	ui.label_Img->setPixmap(QPixmap::fromImage(imgForDisplay));
}
void DH_MER::getExposeTime()
{
	try
	{
		exposeTime = ui.exposeTime->text().toInt();
		if (exposeTime >= 31)
		{
			m_objRemoteFeatureControlPtr->GetFloatFeature("ExposureTime")->SetValue(exposeTime);
		}
	}
	catch (CGalaxyException& e)
	{
		cout << "错误码: " << e.GetErrorCode() << endl;
		cout << "错误描述信息: " << e.what() << endl;
	}
	catch (std::exception& e)
	{
		cout << "错误描述信息: " << e.what() << endl;
	}
}
void DH_MER::updateUI()
{
	ui.width->setText(QString::number(m_width));
	ui.height->setText(QString::number(m_height));
	ui.factoryName->setText(m_firmName);
	ui.basicModel->setText(m_modelName);
}
void DH_MER::DoOnDeviceOfflineEvent(void* pUserParam)
{
	isOffline = true;
	IGXFactory::GetInstance().Uninit(); //释放GxIAPICPPEx申请的所有资源
	cout << "设备掉线,请检查并重新连接。" << endl;
}
void DH_MER::DoOnImageCaptured(CImageDataPointer& objImageDataPointer, void* pUserParam)
{
	//判断图像是否为完整帧
	if (GX_FRAME_STATUS_SUCCESS == objImageDataPointer->GetStatus())
	{
		//图像获取为完整帧,可以读取图像宽、高、数据格式等
		uint64_t m_width = objImageDataPointer->GetWidth();
		uint64_t m_height = objImageDataPointer->GetHeight();
		//GX_PIXEL_FORMAT_ENTRY emPixelFormat =objImageDataPointer->GetPixelFormat();
		void* pRGB24Buffer = NULL;
		//原始数据是 Mono8 图像
		if (objImageDataPointer->GetPixelFormat()==GX_PIXEL_FORMAT_MONO8)
		{
			pRGB24Buffer = objImageDataPointer->ConvertToRaw8(GX_BIT_0_7);
			capturedImg = cv::Mat::zeros(cv::Size(m_width, m_height), CV_8UC1);
			memcpy(capturedImg.data, pRGB24Buffer, m_width * m_height);
		}
		if (objImageDataPointer->GetPixelFormat() == GX_PIXEL_FORMAT_MONO10)
		{
			pRGB24Buffer = objImageDataPointer->ConvertToRGB24(GX_BIT_2_9, GX_RAW2RGB_NEIGHBOUR, true);
			capturedImg = cv::Mat::zeros(cv::Size(m_width, m_height), CV_8UC3);
			memcpy(capturedImg.data, pRGB24Buffer, m_width * m_height * 3);
		}
		if (!capturedImg.empty())
		{
			double d = m_objRemoteFeatureControlPtr->GetFloatFeature("ExposureTime")->GetValue();
			exposeTime = int(d);
			emit sendCapturedMat(capturedImg,n);
		}
		showMatInLabel(capturedImg);
		updateUI();
	}
}

(3)main.cpp

#include "DH_MER.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    qRegisterMetaType<cv::Mat>("cv::Mat");
    DH_MER w;
    w.show();
    return a.exec();
}

四、其他资源

大恒软件以及开发文档传送
完整项目链接(有兴趣可以自己重新配置一下环境):
https://pan.baidu/s/10AJiTQC9rrZNe2HTPyO8kg
提取码:vh0i

注:相机开发存在错误和不完善的地方,仅供参考。无私分享,如有帮助,不妨收藏点赞

更多推荐

vs+Qt+opencv+大恒相机开发(基础功能,适合初学者学习)