基于MFC的Basler相机采集程序

基于MFC的Basler相机采集程序

编程软件VS2015
相机Basler acA4024-8gc
本文采用了opencv3.4.10,并且采用了opencv1.0版本时代的CvvImage类,其对应的CvvImage.h和CvvImage.cpp在网上很多,下载下来即可将CvvImage.h和CvvImage.cpp加入工程。一个工程配置opencv网上的教程也很多,不再赘述。
然后打开Basler相机的开发工具包,将其包含路径和库路径加入工程,同时添加环境变量的路径,以便可以找到对应的dll文件。
Basler开发工具包里面有许多Sample,可以参考,我就是参考里面的范例做的。

添加头文件

#include “stdafx.h”
#include “BinCameRectify.h”
#include “BinCameRectifyDlg.h”
#include “afxdialogex.h”
#include
using namespace std;

#include “CvvImage.h”
#include “opencv2/opencv.hpp”
using namespace cv;

#include
#include
typedef Pylon::CBaslerGigEInstantCamera Camera_t;
using namespace Pylon;
using namespace Basler_GigECameraParams;
using namespace GenApi;

这里博主犯了一个低级错误,由于stdafx.h没有放在头文件的第一行,导致预编译无法通过一直报C2065的错误。

相机界面

基于MFC的对话框,创建自己的界面,并修改每个控件的ID
基于MFC的Basler相机采集程序_第1张图片

设置静态全局变量

这样仅仅作用于本文件,对其他文件没影响

static Mat g_srcImage;
static int ImgNum = 0;
static IplImage* frame;
static IplImage* m_grabframe;
static CRect rect;
static CDC* pDC;
static HDC hDC;
static CWnd *pwnd;
static CBaslerGigEInstantCamera camera;
static CGrabResultPtr ptrGrabResult;
static Size siz(4024, 3036);
static cv::Mat grab,grab2;

“开启设备 ”对应的响应函数

加载设备,并将其初始化与连接到对应的camera变量控制

// TODO: 在此添加控件通知处理程序代码
	PylonInitialize();
	camera.Attach(CTlFactory::GetInstance().CreateFirstDevice());
	camera.Open();
	camera.OffsetX.SetValue(0);
	camera.OffsetY.SetValue(0);
	camera.Width.SetValue(4024);
	camera.Height.SetValue(3036);
	GenApi::IEnumEntry* acquisitionStart = camera.TriggerSelector.GetEntry(TriggerSelector_AcquisitionStart);
	if (acquisitionStart && GenApi::IsAvailable(acquisitionStart))
	{
		camera.TriggerSelector.SetValue(TriggerSelector_AcquisitionStart);
		camera.TriggerMode.SetValue(TriggerMode_Off);
	}
	if (GenApi::IsAvailable(camera.PixelFormat.GetEntry(PixelFormat_Mono8)))
		camera.PixelFormat.SetValue(PixelFormat_Mono8);
	camera.ExposureMode.SetValue(ExposureMode_Timed);
	camera.ExposureTimeRaw.SetValue(1000020);
	camera.MaxNumBuffer = 5;

“开始采集”对应的响应函数

开始之后,先采集第一帧,并利用定时器一直采集并显示。

camera.StartGrabbing();
	if (camera.IsGrabbing())
	{
		camera.RetrieveResult(5000, ptrGrabResult, TimeoutHandling_ThrowException);
		if (ptrGrabResult->GrabSucceeded())
		{
			grab = cv::Mat(siz, CV_8UC1, ptrGrabResult->GetBuffer(), siz.width * 1);
			frame = &IplImage(grab);
			pDC = GetDlgItem(IDC_STATIC)->GetDC();//GetDlgItem(IDC_PIC_STATIC)意思为获取显示控件的句柄(句柄就是指针),获取显示控件的DC
			GetDlgItem(IDC_STATIC)->GetClientRect(&rect);
			hDC = pDC->GetSafeHdc();//获取显示控件的句柄
			CvvImage m_CvvImage;
			m_CvvImage.CopyOf(frame, 1); //复制该帧图像   
			m_CvvImage.DrawToHDC(hDC, &rect); //显示到设备的矩形框内
			ReleaseDC(pDC);
		}
		
	}
	SetTimer(1, 1002, NULL); //定时器,定时时间和帧率一致

时间触发器函数

这里使用SetTimer函数,需要添加计时器以实现循环。应用定时器实现动态显示相机采集到的图片
添加计时器:类向导-消息-WM-TIMER,双击添加OnTimer函数,如下

if (camera.IsGrabbing())
	{
		
		camera.RetrieveResult(5000, ptrGrabResult, TimeoutHandling_ThrowException);
		if (ptrGrabResult->GrabSucceeded())
		{
			grab2 = cv::Mat(siz, CV_8UC1, ptrGrabResult->GetBuffer(), siz.width * 1);
			frame = &IplImage(grab2);
			pDC = GetDlgItem(IDC_STATIC)->GetDC();//GetDlgItem(IDC_PIC_STATIC)意思为获取显示控件的句柄(句柄就是指针),获取显示控件的DC
			GetDlgItem(IDC_STATIC)->GetClientRect(&rect);
			hDC = pDC->GetSafeHdc();//获取显示控件的句柄
			CvvImage m_CvvImage;
			m_CvvImage.CopyOf(frame, 1); //复制该帧图像   
			m_CvvImage.DrawToHDC(hDC, &rect); //显示到设备的矩形框内
			ReleaseDC(pDC);
		}
		
	}
	CDialogEx::OnTimer(WM_TIMER);
	return 0;

“停止采集” 消息响应函数

只需要停止采集和断开连接,如果不断开连接,下次就无法再加载设备了。

// TODO: 在此添加控件通知处理程序代码
	camera.StopGrabbing();
	PylonTerminate();

“捕获图像”消息响应函数

// TODO: 在此添加控件通知处理程序代码
	g_srcImage = cv::Mat(siz, CV_8UC1, ptrGrabResult->GetBuffer(), siz.width * 1);
	ImgNum++;
	frame = &IplImage(g_srcImage);
	m_grabframe = frame;
	if (m_grabframe == 0)
	{
		MessageBox(_T("摄像头已关闭,无法捕捉图像!!!"));
		return;
	}
	//以下代码是完成图像的显示过程
	IplImage * m_snap = cvCreateImage(cvGetSize(m_grabframe), m_grabframe->depth, m_grabframe->nChannels);
	cvCopy(m_grabframe, m_snap, NULL);
	pDC = GetDlgItem(IDC_STATIC2)->GetDC();//意思为获取显示控件的句柄(句柄就是指针),获取显示控件的DC
	GetDlgItem(IDC_STATIC2)->GetClientRect(&rect);
	hDC = pDC->GetSafeHdc();//获取显示控件的句柄
	CvvImage m_CvvImage;
	m_CvvImage.CopyOf(m_snap, 1); //复制该帧图像   
	m_CvvImage.DrawToHDC(hDC, &rect); //显示到设备环境的矩形框内

	//图像保存
	string strSaveName;
	char buffer[256];
	sprintf_s(buffer, "D%04d", ImgNum);
	strSaveName = buffer;
	string outPutPath = "D:\\Picture\\";
	//定义保存图像的完整路径
	string strImgSavePath = outPutPath + "\\" + strSaveName;
	//定义保存图像的格式
	strImgSavePath += ".jpeg";
	//strImgSavePath += ".png";

	//保存操作
	imwrite(strImgSavePath.c_str(), g_srcImage);

调整曝光时间和增益对应的消息对应函数

这里面博主利用成员变量来camera_gain和exposure_time来控制相机增益和曝光时间。由于博主的电脑不支持千兆网卡,所以曝光时间增长,降低帧率。

 static int64_t Adjust(int64_t val, int64_t minimum, int64_t maximum, int64_t inc)
  {
	// Check the input parameters.
	if (inc <= 0)
	{
		// Negative increments are invalid.
		throw LOGICAL_ERROR_EXCEPTION("Unexpected increment %d", inc);
	}
	if (minimum > maximum)
	{
		// Minimum must not be bigger than or equal to the maximum.
		throw LOGICAL_ERROR_EXCEPTION("minimum bigger than maximum.");
	}

	// Check the lower bound.
	if (val < minimum)
	{
		return minimum;
	}

	// Check the upper bound.
	if (val > maximum)
	{
		return maximum;
	}

	// Check the increment.
	if (inc == 1)
	{
		// Special case: all values are valid.
		return val;
	}
	else
	{
		// The value must be min + (n * inc).
		// Due to the integer division, the value will be rounded down.
		return minimum + (((val - minimum) / inc) * inc);
	}
}
//调整曝光时间
void CBinCameRectifyDlg::OnEnKillfocusEdit3()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(true);
	KillTimer(1);
	SetTimer(1, exposure_time / 1000, NULL);
	INodeMap& nodemap = camera.GetNodeMap();
	CIntegerPtr ptrExposureTimeRaw(nodemap.GetNode("ExposureTimeRaw"));
	if (IsWritable(ptrExposureTimeRaw))
	{
		int64_t newExposureTimeRaw = Adjust(exposure_time, ptrExposureTimeRaw->GetMin(), ptrExposureTimeRaw->GetMax(), ptrExposureTimeRaw->GetInc());
		exposure_time = newExposureTimeRaw;
		UpdateData(FALSE);
		ptrExposureTimeRaw->SetValue(newExposureTimeRaw);
	}
	
}


//调整相机增益
void CBinCameRectifyDlg::OnEnKillfocusEdit2()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(true);
	INodeMap& nodemap = camera.GetNodeMap();
	CEnumerationPtr PtrgainAuto(nodemap.GetNode("GainAuto"));
	if (IsWritable(PtrgainAuto))
	{
		PtrgainAuto->FromString("Off");
	}

	// Access the GainRaw integer type node.
	CIntegerPtr PtrgainRaw(nodemap.GetNode("GainRaw"));
	if (PtrgainRaw.IsValid())
	{
		// Make sure the calculated value is valid.
		int64_t newGainRaw = Adjust(camera_gain, PtrgainRaw->GetMin(), PtrgainRaw->GetMax(), PtrgainRaw->GetInc());
		camera_gain = newGainRaw;
		UpdateData(FALSE);
		PtrgainRaw->SetValue(newGainRaw);
	}
	
}

你可能感兴趣的:(机器视觉)