Hki/Pylon SDK control Camera_莫负好春光的博客-程序员秘密

技术标签: QT  Visios Studio  

在做一个关于相机库SDK的二次开发demo,记录此过程
工业相机都配有自己的相机软件,在软件中会集成这家相机的各种型号下的硬件配置,所以这部分不需要我们去关心,仅需要知道它干了些什么就可以,关于工业相机的编程模型和流程在:
https://blog.csdn.net/wenzhou1219/article/details/45874779
工业相机的编程原理及流程我们知道了,接下来就是找到这些工业相机为我们准备的SDK;
以Basler为例,在Basler的官方网站中找到它的Software,下载对应电脑系统的版本
在这里插入图片描述
在这里插入图片描述

下载完毕之后是安装,安装过程有一项选择开发者(Development)安装模式,其余按照提示即可;
以开发者模式安装后的pylon会比非开发者模式多出一个文件夹,在安装路径(Normal:C:\Program Files\Basler\pylon 6\Development)下找到它,文件夹名为Development。

该文件夹下有Basler为我们提供的include、lib及对应的Documentation,此外还提供了一些sample供我们玩耍。
打开sample文件夹,可以看到这是一个Vs工程,使用VS加载,通常不会成功。
这是因为你的VS里缺少了支持Basler开发者们写的工程的组件,按照提示去安装这些组件:
Tips:在快要安装完成时,会非常慢,查了一下,据说是在配置系统原点,慢就慢点吧,总比安装个组件搞坏了原有的系统好。
在这里插入图片描述
。。。Thousand Years Later。。。

以pylon的相机流程为例
总体流程:
1、加载相机对象
2、加载数据流抓取对象
3、连续或单帧采图
4、卸载数据流抓取对象
5、卸载相机对象

通常来说在编程上步骤1和步骤5是通用的,对应的事件对象也有这种机制,加载事件对象–完成功能–卸载事件对象。
下面对每个过程进行分析:
1、加载相机对象

1.1 初始化动态系统资源
	PylonInitialize  //建立内在的结构体,为一些全局参数提供空间
1.2 检测当前相机数目
	PylonEnumerateDevices  //枚举相机
1.3 创建相机对象
	PylonCreateDeviceByIndex  //找到对应相机index并创建对象
1.4 打开相机对象
	PylonDeviceOpen

2、加载数据流抓取对象

2.1 检测Stream 采集通道数目
	PylonDeviceGetNumStreamGrabberChannels
2.2 获取Stream Grabber抓取对象
	PylonDeviceGetStreamGrabber
2.3 打开对象
	PylonStreamGrabberOpen
2.4 获取同步对象
	PylonStreamWaitObjectWait
2.5 设置抓图参数
	PylonStreamGrabberSetMaxNumBuffer  //Buffer数目 				
	PylonStreamGrabberSetMaxBuffersize  //Buff大小
2.6 分配每个Buffer内存
	new
2.7 分配抓图要的资源
	PylonStreamGrabberPrepareGrab  //分配资源包括以下四个部分:         	
	//1、动态内存分配         
	//2、驱动数据内存分配         
	//3、xxx相机同步通道         
	//4、xxx相机同步带宽  
	//(此函数调用后,影响资源分配的参数均为只读型)
2.8 将Buffer 注册到抓取对象
	PylonStreamGrabberRegisterBuffer
2.9 Buffer依次放入抓图的输入对象中
	PylonStreamGrabberQueueBuffer

步骤2中,2.1-2.4为打开数据流抓取对象部分;2.5-2.9为分配抓图所需资源部分;

3、单帧或者连续抓图过程

3.1 设置抓图模式为连续,并开始抓图
	PylonDeviceFeatureFromString  //设置连续模式 		
	PylonDeviceExcuteCommandFeature  //开始抓图命令
3.2 等待下一个要抓取的Buffer被填充
	PylonWaitObjectWait
3.3 抓取Buffer结果并显示
	PylonStreamGrabberRetriveResult
3.4 将Buffer再放入抓图的输入队列中
	PylonStreamGrabberQueueBuffer

步骤3.2–3.3重复一次或者多次可实现单帧或者连续抓图;

4、卸载数据流抓取对象

4.1 将所有Buffer放到数据流抓取对象输出队列上
	PylonStreamGrabberCancelGrab
4.2 将输出队列上的数据全部取出
	PylonStreamGrabberRetriveResult
4.3 取消注册分配的Buffer
	PylonStreamGrabberDeregisterBuffer
4.4 释放Buffer内存
	delete
4.5 释放相关的分配资源
	PylonStreamGrabberFinishGrab
4.6 关闭数据流抓取对象
	PylonStreamGrabberClose

步骤4.1 - 4.5 均为释放抓图资源

5、卸载相机对象

5.1 关闭相机对象
	PylonDeviceClose
5.2 销毁相机对象
	PylonDestrouDevice
5.3 卸载动态系统资源
	PylonTerminate  //释放内在结构体


Recommend sample Description
ParametrizeCamera_LoadAndSave.cpp This sample application demonstrates how to save or load the features of a camera to or from a file.
GUI_ImageWindow.cpp This sample illustrates how to show images using the CPylonImageWindow class. Here, images are grabbed, split into multiple tiles and and each tile is shown in a separate image windows.
Grab_CameraEvents.cpp It is shown in this sample how to register event handlers indicating the arrival of events sent by the camera. For demonstration purposes, several different handlers are registered for the same event.
Grab_Strategies.cpp This sample shows the use of the Instant Camera grab strategies.
Grab.cpp Grab flow.

以上为Basler相机的采图流程,下面将其封装成动态库,并使用QT写一个Ui进行调用。

可能是由于电脑被公司的加密软件加密了,导致Pylon的相机库编译报错,问题是出现在枚举设备参数设置头文件EnumParameterT.h中

virtual CEnumParameterT<EnumT>& operator=(EnumT value){
    }

在这里插入图片描述
多方求解未果,遂弃Basler投HiK:

对于相机的操作原理都是一样的,海康的SDK提供两种方式采图:

一是先注册图像采集回调函数,然后操作相机 StartGrabbing,采集的图像在回调函数中返回;
二是不注册图像采集回调函数,然后在应用层循环调用GetOneFrame获取指定像素格式的帧数据,但是获取帧数据时,上层应用程序需要根据帧率控制好调用接口的频率;

我采用的时第二种方式,因为第一种方式,我尝试失败了,错误出在注册图像采集回调函数后,不能获取到曝光时间、曝光频率、帧率等信息,也可能与公司的加密软件有关,所以就直接采用了第二种方式:
这里未单独分一个新的线程去处理读取图像,所以效率来说不是很高,仅供了解原理使用,在图像的处理上采用了cv的Mat类型,此外还可以使用halcon的Hobject进行图像的显示、处理、存储等.
直接贴上槽函数,有注释:

QtGrabImage::QtGrabImage(QWidget *parent)
	: QMainWindow(parent)
{
    
	ui.setupUi(this);
	nRet = MV_OK;
	handle = NULL;
	pData = NULL;
	pDataForRGB = NULL;
	g_bExit = false;
	g_nPayloadSize = 0;
	nIndex = 0;
	nPacketSize = 0;

	//connect(ui.EnumCam, &QPushButton::clicked, this, &QtGrabImage::on_EnumCam_clicked);
	//connect(ui.OpenCam, &QPushButton::clicked, this, &QtGrabImage::on_OpenCam_clicked);
	//connect(ui.StartCam, &QPushButton::clicked, this, &QtGrabImage::on_StartCam_clicked);

	//connect(ui.StopCam, &QPushButton::clicked, this, &QtGrabImage::on_StopCam_clicked);
	//connect(ui.CloseCam, &QPushButton::clicked, this, &QtGrabImage::on_CloseCam_clicked);
	//connect(ui.SaveImg, &QPushButton::clicked, this, &QtGrabImage::on_SaveImg_clicked);
	//connect(ui.FrameModel, &QRadioButton::toggled, this, &QtGrabImage::on_FrameModel_clicked);//使用一个新的pushbutton去采集的话就不需要这两个状态了
	//connect(ui.ConstantModel, &QRadioButton::toggled, this, &QtGrabImage::on_ConstantModel_clicked);//直接用ui.RadioButton->isChecked()去判断
	connect(ui.comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(comboxSlots()));
}

bool QtGrabImage::PrintDeviceInfo (MV_CC_DEVICE_INFO* pstMVDevInfo)
{
    
	if (NULL == pstMVDevInfo)
	{
    
		QMessageBox::information(this, tr("Error"), QString::fromLocal8Bit("The Pointer of pstMVDevInfo is NULL!"));
		//printf("The Pointer of pstMVDevInfo is NULL!\n");
		return false;
	}
	if (pstMVDevInfo->nTLayerType == MV_GIGE_DEVICE)
	{
    
		int nIp1 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24);
		int nIp2 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16);
		int nIp3 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8);
		int nIp4 = (pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff);

		//打印当前相机ip和用户自定义名字
		QString strIp = QString::number(nIp1) + "." + QString::number(nIp2) + "." + QString::number(nIp3) + "." +
			QString::number(nIp4);
		unsigned char* cusrname = pstMVDevInfo->SpecialInfo.stGigEInfo.chUserDefinedName; //相机用户名是存储成unsigned char 类型
		std::string cstr = std::string((char *)cusrname);
		QString strName = QString::fromStdString(cstr);

		QString strMesg = "Current User: " + strName + " , Current Ip: " + strIp;
		ui.statusBar->showMessage(strMesg);
		ui.comboBox->addItem(strMesg);//调用之前先声明一下 disconnected
	}
	else if (pstMVDevInfo->nTLayerType == MV_USB_DEVICE)
	{
    
		QMessageBox::information(this, tr("Sorry : "), QString::fromLocal8Bit("Not USB Device!"));
	}
	else
	{
    
		QMessageBox::information(this, tr("Error : "), QString::fromLocal8Bit("Not support!"));
		//printf("Not support.\n");
	}

	return true;
}

//WorkThread线程函数,用于读取相机的图像流
//unsigned int _stdcall QtGrabImage::WorkThread(void *pUser)
//{
    
//	int nRet = MV_OK;
//	stImageInfo = { 0 };
//	memset(&stImageInfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));
//	unsigned char * pData = (unsigned char *)malloc(sizeof(unsigned char) * (g_nPayloadSize));
//	if (pData == NULL)
//	{
    
//		return 0;
//	}
//	unsigned int nDataSize = g_nPayloadSize;
//	while (1)
//	{
    
//		nRet = MV_CC_GetOneFrameTimeout(pUser, pData, nDataSize, &stImageInfo, 1000);
//		if (nRet == MV_OK)
//		{
    
//			printf("Get one frame : Width:[%d], Height[%d], nFrameNum[%d]\n",
//				stImageInfo.nWidth, stImageInfo.nHeight, stImageInfo.nFrameNum);
//		}
//		else
//		{
    
//			printf("Get frame : No data. nRet = [0x%x]\n", nRet);
//		}
//		if (g_bExit)
//		{
    
//			break;
//		}
//	}
//	free(pData);
//	return 0;
//}

void QtGrabImage::on_EnumCam_clicked()
{
    
	memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
	int nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
	if (MV_OK != nRet)
	{
    
		QString qstrerror = "Enum Device Faile! nRet:" + QString(nRet, 16);

		QMessageBox::information(this, tr("Error : "), qstrerror);
		//printf("Enum Devices fail! nRet [0x%x]\n", nRet);
		return;
	}
	QObject::disconnect(ui.comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(comboxSlots()));
	if (stDeviceList.nDeviceNum > 0)
	{
    
		for (unsigned int i = 0; i < stDeviceList.nDeviceNum; i++)
		{
    
			//printf("[device %d]:\n", i);
			MV_CC_DEVICE_INFO* pDeviceInfo = stDeviceList.pDeviceInfo[i];
			if (NULL == pDeviceInfo)
			{
    
				break;
			}
			PrintDeviceInfo(pDeviceInfo);
		}
	}
	else
	{
    
		QMessageBox::information(this, tr("Error: "), QString::fromLocal8Bit("Find No Device!"));
		//printf("Find No Devices!\n");
		return;
	}

	//printf("Please Intput camera index:");

	//scanf_s("%d", &nIndex);

	//if (nIndex >= stDeviceList.nDeviceNum)
	//{
    
	//	printf("Intput error!\n");
	//	return;
	//}
}

void QtGrabImage::comboxSlots()
{
    
	nIndex = ui.comboBox->currentIndex();
}

void QtGrabImage::on_OpenCam_clicked()
{
    
	int nRet = MV_CC_CreateHandle(&handle, stDeviceList.pDeviceInfo[nIndex]);
	if (MV_OK != nRet)
	{
    
		QString strerr = "Create Handle Fail! nRet :" + QString(nRet, 16);
		QMessageBox::information(this, tr("Error: "), strerr);
		//printf("Creat Handle Failed! nRet = [0x%x]\n", nRet);
		return;
	}
	nRet = MV_CC_OpenDevice(handle);
	if (MV_OK != nRet)
	{
    
		QString strerr = "Open Device Fail! nRet:" + QString::number(nRet, 16);
		QMessageBox::information(this, tr("Error "), strerr);
		//printf("Open Device Failed! nRet = [0x%x]\n", nRet);
		return;
	}
	//探测网络最佳包大小(只对GigE相机有效)
	if (stDeviceList.pDeviceInfo[nIndex]->nTLayerType == MV_GIGE_DEVICE)
	{
    
		nPacketSize = MV_CC_GetOptimalPacketSize(handle);
		if (nPacketSize > 0)
		{
    
			nRet = MV_CC_SetIntValue(handle, "GevSCPSPacketSize", nPacketSize);
			if (nRet != MV_OK)
			{
    
				QString strerr = "Set Packet Size fail nRet:" + QString(nRet, 16);
				QMessageBox::information(this, tr("Warning:"), strerr);
				//printf("Warning: Set Packet Size fail nRet [0x%x]!", nRet);
			}
		}
		else
		{
    
			QString strerr = "Get Packet Size fail nRet:" + QString(nRet, 16);
			QMessageBox::information(this, tr("Warning:"), strerr);
			//printf("Warning: Get Packet Size fail nRet [0x%x]!", nRet);
		}
	}
	//获取数据包大小
	memset(&stParam, 0, sizeof(MVCC_INTVALUE));
	nRet = MV_CC_GetIntValue(handle, "PayloadSize", &stParam);
	if (MV_OK != nRet)
	{
    
		QString strerr = "Get PayloadSize fail! nRet:" + QString(nRet, 16);
		QMessageBox::information(this, tr("Warning:"), strerr);
		//printf("Get PayloadSize fail! nRet [0x%x]\n", nRet);
		return;
	}
	g_nPayloadSize = stParam.nCurValue;
}

void QtGrabImage::on_StartCam_clicked()
{
    
	//设置触发模式为off
	int nRet = MV_CC_SetEnumValue(handle, "TriggerMode", 0);
	if (MV_OK != nRet)
	{
    
		QString strerr = "Set Trigger Model Fail! nRet:" + QString(nRet, 16);
		QMessageBox::information(this, tr("Error"), strerr);
		//printf("Set Trigger Mode fail! nRet [0x%x]\n", nRet);
		return;
	}
	//开始取流
	nRet = MV_CC_StartGrabbing(handle);
	if (nRet != MV_OK)
	{
    
		QString strerr = "Start Grabbing Fail! nRet:" + QString(nRet, 16);
		QMessageBox::information(this, tr("Error"), strerr);
		//printf("Start Grabbing Failed. nRet = [0x%x]\n", nRet);
		return;
	}
	//创建新线程去操作取流
	//unsigned int nThreadID = 0;
	//void *hThreadHandle = (void *)_beginthreadex(NULL, 0, WorkThread, handle, 0, &nThreadID);
	//if (NULL == hThreadHandle)
	//{
    
	//	return;
	//}
	stImageInfo = {
     0 };
	memset(&stImageInfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));
	pData = (unsigned char *)malloc(sizeof(unsigned char) * (g_nPayloadSize));
	if (pData == NULL)
	{
    
		QMessageBox::information(this, tr("Error"), QString::fromLocal8Bit("malloc pData fail!"));
		return;
	}
	unsigned nDataSize = g_nPayloadSize;
//	
//	nRet = MV_CC_GetOneFrameTimeout(handle, pData, nDataSize, &stImageInfo, 1000);
//	if (nRet == MV_OK)
//	{
    
//		QString strInfo = "Get one frame: Width:" + QString(stImageInfo.nWidth, 10) +
//			" Height:" + QString(stImageInfo.nHeight, 10) + " nFrameNum:" + QString(stImageInfo.nFrameNum);
//		
//		pDataForRGB = (unsigned char *)malloc(stImageInfo.nWidth * stImageInfo.nHeight * 3);
//		if (pDataForRGB == NULL)
//		{
    
//			QMessageBox::information(this, tr("Error"), QString::fromLocal8Bit("pDataForRGB malloc fail!"));
//			return;
//		}
//		unsigned nDataSizeForRGB = stImageInfo.nWidth * stImageInfo.nHeight * 3;
//		//像素格式转换
//		MV_CC_PIXEL_CONVERT_PARAM stConvertParam = { 0 };
//		memset(&stConvertParam, 0, sizeof(MV_CC_PIXEL_CONVERT_PARAM));
//
//		stConvertParam.nWidth = stImageInfo.nWidth;		//图像的宽
//		stConvertParam.nHeight = stImageInfo.nHeight;	//图像的高
//		stConvertParam.pSrcData = pData;					//输入数据缓存
//		stConvertParam.nSrcDataLen = stImageInfo.nFrameLen;	//输入数据大小
//		stConvertParam.enSrcPixelType = stImageInfo.enPixelType;		//源图像像素类型
//		stConvertParam.enDstPixelType = PixelType_Gvsp_RGB8_Packed;	//目标像素类型
//		stConvertParam.pDstBuffer = pDataForRGB;						//输出数据缓存地址
//		stConvertParam.nDstBufferSize = nDataSizeForRGB;				//输出数据大小
//		nRet = MV_CC_ConvertPixelType(handle, &stConvertParam);
//		if (nRet != MV_OK)
//		{
    
//			QMessageBox::information(this, tr("Error"), QString::fromLocal8Bit("Image Pixel convert fail!"));
//			return;
//		}
//		/*bool Convert2Mat(MV_FRAME_OUT_INFO_EX* pstImageInfo, unsigned char * pData, int i)*/
//		int cvheight = stImageInfo.nHeight;
//		int cvwidth = stImageInfo.nWidth;
//		cv::Mat cvImg(cvheight, cvwidth, CV_8UC3, pDataForRGB);
//		//cvImg 转换到QImage
//		cv::cvtColor(cvImg, cvImg, CV_BGR2RGB);
//		QImage qImg = QImage((const unsigned char*)(cvImg.data), cvImg.cols, cvImg.rows,
//			cvImg.cols*cvImg.channels(), QImage::Format_RGB888);
//		//显示
//		ui.label->clear();
//		ui.label->setPixmap(QPixmap::fromImage(qImg.scaled(ui.label->size())));//设置图像大小和label大小一致
		ui.label->resize(ui.label->pixmap()->size());//设置label的大小和图像的大小一致
	DispGrabImgFrame();
	return;
	//}
}

void QtGrabImage::on_CamGrab_clicked()
{
    
	//判断Radio 的状态 及运行接下来的事情
	if (ui.FrameModel->isChecked())
	{
    
		DispGrabImgFrame();
		return;
	}
	if (ui.ConstantModel->isChecked())
	{
    
		DispGrabImgConstant();
		return;
	}
	else
	{
    
		QMessageBox::information(this, tr("Error"), QString::fromLocal8Bit("Please choose a Model first!"));
		return;
	}
}

void QtGrabImage::on_StopCam_clicked()
{
    
	nRet = MV_CC_StopGrabbing(handle);
	if (MV_OK != nRet)
	{
    
		QString strerr = "Stop Grabbing fail! \n nRet:" + QString::number(nRet, 16);
		QMessageBox::information(this, tr("Error"), strerr);
		return;
	}
}

void QtGrabImage::on_SaveImg_clicked()
{
    
	QString saveImgname = QFileDialog::getSaveFileName(this, tr("Open Config"), " ", tr("config files (*.jpg)"));
	if (!saveImgname.isNull())
	{
    
		QImage qimg = ui.label->pixmap()->toImage();
		if (qimg.isNull())
		{
    
			QMessageBox::information(this, tr("Error"), QString::fromLocal8Bit("There is no Image to save!"));
			return;
		}
		else
		{
    
			qimg.save(saveImgname, "JPG", 100);
			QMessageBox::information(this, tr(" "), QString::fromLocal8Bit("Image saved Successed!"));
		}
	}
	else
	{
    
		QMessageBox::information(this, tr(" "), QString::fromLocal8Bit("Save Canceled!"));
		return;
	}
}

void QtGrabImage::on_CloseCam_clicked()
{
    
	//关闭设备
	nRet = MV_CC_CloseDevice(handle);
	if (MV_OK != nRet)
	{
    
		QString strerr = "CloseDevice fail! \n nRet:" + QString::number(nRet, 16);
		QMessageBox::information(this, tr("Error"), strerr);
		return;
	}

	//销毁句柄
	nRet = MV_CC_DestroyHandle(handle);
	if (MV_OK != nRet)
	{
    
		QString strerr = "Destroy handle fail! \n nRet:" + QString::number(nRet, 16);
		QMessageBox::information(this, tr("Error"), strerr);
		return;
	}
}

void QtGrabImage::DispGrabImgFrame()
{
    
	unsigned nDataSize = g_nPayloadSize;
	nRet = MV_CC_GetOneFrameTimeout(handle, pData, nDataSize, &stImageInfo, 1000);
	if (nRet == MV_OK)
	{
    
		QString strInfo = "Get one frame: Width:" + QString(stImageInfo.nWidth, 10) +
			" Height:" + QString(stImageInfo.nHeight, 10) + " nFrameNum:" + QString(stImageInfo.nFrameNum);
		pDataForRGB = (unsigned char *)malloc(stImageInfo.nWidth * stImageInfo.nHeight * 3);
		if (pDataForRGB == NULL)
		{
    
			QMessageBox::information(this, tr("Error"), QString::fromLocal8Bit("pDataForRGB malloc fail!"));
			return;
		}
		unsigned nDataSizeForRGB = stImageInfo.nWidth * stImageInfo.nHeight * 3;
		//像素格式转换
		MV_CC_PIXEL_CONVERT_PARAM stConvertParam = {
     0 };
		memset(&stConvertParam, 0, sizeof(MV_CC_PIXEL_CONVERT_PARAM));

		stConvertParam.nWidth = stImageInfo.nWidth;		//图像的宽
		stConvertParam.nHeight = stImageInfo.nHeight;	//图像的高
		stConvertParam.pSrcData = pData;					//输入数据缓存
		stConvertParam.nSrcDataLen = stImageInfo.nFrameLen;	//输入数据大小
		stConvertParam.enSrcPixelType = stImageInfo.enPixelType;		//源图像像素类型
		stConvertParam.enDstPixelType = PixelType_Gvsp_RGB8_Packed;	//目标像素类型
		stConvertParam.pDstBuffer = pDataForRGB;						//输出数据缓存地址
		stConvertParam.nDstBufferSize = nDataSizeForRGB;				//输出数据大小
		nRet = MV_CC_ConvertPixelType(handle, &stConvertParam);
		if (nRet != MV_OK)
		{
    
			QMessageBox::information(this, tr("Error"), QString::fromLocal8Bit("Image Pixel convert fail!"));
			return;
		}
		/*bool Convert2Mat(MV_FRAME_OUT_INFO_EX* pstImageInfo, unsigned char * pData, int i)*/
		int cvheight = stImageInfo.nHeight;
		int cvwidth = stImageInfo.nWidth;
		cv::Mat cvImg(cvheight, cvwidth, CV_8UC3, pDataForRGB);
		//cvImg 转换到QImage
		cv::cvtColor(cvImg, cvImg, CV_BGR2RGB);
		QImage qImg = QImage((const unsigned char*)(cvImg.data), cvImg.cols, cvImg.rows,
			cvImg.cols*cvImg.channels(), QImage::Format_RGB888);
		//显示
		ui.label->clear();
		ui.label->setPixmap(QPixmap::fromImage(qImg.scaled(ui.label->size())));
		Sleep(1000);
		//ui.label->resize(ui.label->size());
	}
}

void QtGrabImage::DispGrabImgConstant()
{
    
	for (int i = 0; i < 1000; i++)
	{
    
		++i;
		DispGrabImgFrame();
		while (waitKey())
		{
    
			return;
		}
	}
	return;
}

头文件也贴一下:

#pragma once
#include <Windows.h>
#include <stdio.h>
#include <string>
#include <conio.h>
#include <process.h>

#include "MvCameraControl.h"
//#include "TlFactory.h"
//#include "MvGigEDevice.h"

#include <qfiledialog.h>
#include <QtWidgets/QMainWindow>
#include <qmessagebox.h>
#include "ui_qtgrabimage.h"
#include <iostream>
#include <opencv2\opencv.hpp>

using namespace cv;
//using namespace MvCamCtrl;

class QtGrabImage : public QMainWindow
{
    
	Q_OBJECT

public:
	QtGrabImage(QWidget *parent = Q_NULLPTR);

	bool PrintDeviceInfo(MV_CC_DEVICE_INFO* pstMVDevInfo);
	//WorkThread线程函数,用于读取相机的图像
	unsigned int _stdcall QtGrabImage::WorkThread(void *pUser);

	int nRet;
	void *handle;
	unsigned char* pData;
	unsigned char* pDataForRGB;
	bool g_bExit;
	unsigned int g_nPayloadSize;
									
	MV_CC_DEVICE_INFO_LIST stDeviceList;
	unsigned int nIndex; //设备列表信息index
	int nPacketSize;  //网络包大小
	MVCC_INTVALUE stParam;  //数据包大小设置参数
	MV_FRAME_OUT_INFO_EX stImageInfo;  //用于接收单帧图像流

	void DispGrabImgFrame();
	void DispGrabImgConstant();
	//MvCamCtrl::CTlFactory& tlFactory;  //使用MvCamCtrl 下的功能,用于设置单帧/连续模式

private:
	Ui::QtGrabImageClass ui;

signals:
	void currentIndexChanged(int i);

private slots:
	
	void on_EnumCam_clicked();//在此函数中实现下拉列表选取枚举设备
	void on_OpenCam_clicked();
	void on_StartCam_clicked();
	//void on_FrameModel_clicked(bool);
	//void on_ConstantModel_clicked(bool);
	void on_CamGrab_clicked();
	void on_StopCam_clicked();
	void on_CloseCam_clicked();
	void on_SaveImg_clicked();
	void comboxSlots();
};

效果图如下(因为我用的是工业相机和FA镜头,正常拍摄到的图像就是这样,图中亮的地方是灯):
在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39975436/article/details/105249768

智能推荐

hadoop中Java的jar包运行出错问题_张简胡人的博客-程序员秘密

问题描述:[[email protected] local] # hadoop jar hdfstest.jar WordCount /input /output报错:Exception in thread “main” org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory hdfs://localhost:9000/output already exists说明:output 这个文件已经存在了,只需要删除output文件就

CLion中使用CMake导入第三方库的方法_mengzhengjie的博客-程序员秘密

https://blog.csdn.net/Haoran823/article/details/71657602CLion中使用CMake导入第三方库的方法最近尝试使用CLion这款IDE来写C++程序。由于CLion的工程都是基于CMake来构建的,因此导入第三方库就需要在CMake文件中进行配置。这里把利用CMake导入第三方库的过程记录下来。CMake的配置信息写在了CMakeList.tx...

JavaScript学习总结(一)——ECMAScript、BOM、DOM(核心、浏览器对象模型与文档对象模型)..._weixin_30567225的博客-程序员秘密

一、JavaScript简介JavaScript是一种解释执行的脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型,它遵循ECMAScript标准。它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,主要用来给HTML增加动态功能。几乎所有主流的语言都可以编译为JavaScript,进而能够在所有平台上的浏览器中执行,这也体现了Jav...

考试总结 模拟26_banzhu8652的博客-程序员秘密

心得:T1比较水,set水过,之前的有个达哥的等比数列的题,考场上忘了那道题怎么做了,虽然也做出来了T2思路很好想,但分数十分玄学,(不考虑细节+数据很水+代码很菜=50分玄学分数)T3很显然的dp,看着像一个单调队列,但也不怎么会,线段树学习一下其他人的打法题解T1一个贪心,对于每个数要尽量往前放,才能使块数更少,用一个set记录在当前块里的序列,若当前处...

Flume的source类型_flume source类型_围城客的博客-程序员秘密

1、Avro类型的Source:监听Avro端口来接收外部avro客户端的事件流。avro-source接收到的是经过avro序列化后的数据,然后 反序列化数据继续传输。所以,如果是avro-source的话,源数据必须是经过avro序列化后的数据。利用Avro source可以实现多级流动、扇出流、扇入流等效果。接收通过flume提供的avro客户端发送的日 志信息。2、Ex...

Arcgis Engine -- 接口编程思想_R芮R的博客-程序员秘密

--本文为转载收藏,仅供学习参考 学习AO,最重要的是理解“接口”这个概念。接口是什么?有什么具体作用?在多种计算机高级语言中,都可以看到“接口”这个术语,但基本上每一本书对“为什么使用接口”等重要文都都“语焉不详”,使得初学者往往不得要领。 认识接口,必须先要熟悉程序语言发展的历史才行,明白了程序语言发展的前世今生,才能知道这么多计算机语言为什么会是这个样子,为什么会是...

随便推点

mysql create table 报错near '`id` int(11) NOT NULL AUTO_INCREMENT_id int(11) not ull_xLplus的博客-程序员秘密

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '`id` int(11) NOT NULL AUTO_INCREMENT,首先我想说一下,create table ...

iOS刷机后安装源和插件_ios软件源_移动安全星球的博客-程序员秘密

相对比较全的一些源 雷锋源 https://apt.bacydia.com 蚂蚁源 Ant 蚂蚁源 | 最简洁的中文源 Bingner Index of / Frida build.frida.re 多米诺软件源 https://apt.wxhbts.com 比较好用的一些插件 .

WPF常用UI库和图标库(MahApps、HandyControl、LiveCharts)_步、步、为营的博客-程序员秘密

WPF有很多开源免费的UI库,本文主要介绍常见的MahApps、HandyControl两个UI库;在开发过程中经常会涉及到图表的开发,本文主要介绍LiveCharts开源图表库。

【Android】Android中两种常用布局(LinearLayout和RelativeLayout)_remo0x的博客-程序员秘密

LinearLayoutLinearLayout是一个很常用的布局,用于在单个方向(垂直或水平)中对齐所包含的所有组件,可以使用android:orientation属性指定布局方向。一个LinearLayout的所有组件都是一个接一个堆叠的,所以一个垂直列表每行只有一个组件,不管它们有多宽,水平列表只有一行高(最高组件的高度加padding)。 LinearLayout遵从组件之间的margin,

matlab无法设置断点,matlab调试时子函数断点不起作用_weixin_39796116的博客-程序员秘密

matlab调试代码时总是遇到这样一个奇怪的问题,就是当我在主程序(.m脚本)中调用子函数并在子函数中设置断点,然后开始调试运行主程序。。。发现主程序直接运行到结束而并没有在调用子函数的时候在所设置的断点处停下来,而且所设置的断点也被清除。。。但是如果在主程序中调用相应子函数的地方设置断点,调试时在此处停一下然后在继续运行则可以在子函数中的断点停下。。。这个问题困扰我挺长时间,虽然用第二种方法能够...

前端笔试所获(CORS,xss,img srcset,overflow:hidden,block,inline,inline-block,DOM)_cors dom_源魔方的博客-程序员秘密

1.cors跨域访问什么是跨域访问?跨域是浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域,以下情况都属于跨域:跨域原因示例域名不同www.taobao.com 和 www.jd.com域名相同,端口不同www.jd.com:8080 和 www.jd.com:8081二级域名不同item.jd.com 与 miaosha.jd.com注意:如果域名和端口都相同,但是请求路径不同,不属于跨域,如:www.jd.com/it

推荐文章

热门文章

相关标签