编程软件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的错误。
这样仅仅作用于本文件,对其他文件没影响
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);
}
}